• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/scopeinfo.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/parsing/parser.h"
19 #include "src/v8.h"
20 #include "src/v8memory.h"
21 
22 namespace v8 {
23 namespace internal {
24 
SetElementSloppy(Handle<JSObject> object,uint32_t index,Handle<Object> value)25 void 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.
40 class Differencer {
41  public:
Differencer(Comparator::Input * input)42   explicit Differencer(Comparator::Input* input)
43       : input_(input), len1_(input->GetLength1()), len2_(input->GetLength2()) {
44     buffer_ = NewArray<int>(len1_ * len2_);
45   }
~Differencer()46   ~Differencer() {
47     DeleteArray(buffer_);
48   }
49 
Initialize()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.
FillTable()59   void FillTable() {
60     CompareUpToTail(0, 0);
61   }
62 
SaveResult(Comparator::Output * chunk_writer)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.
CompareUpToTail(int pos1,int pos2)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 
get_cell(int i1,int i2)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.
set_value4_and_dir(int i1,int i2,int value4,Direction dir)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 
get_value4(int i1,int i2)169   int get_value4(int i1, int i2) {
170     return get_cell(i1, i2) & (kMaxUInt32 ^ kDirectionMask);
171   }
get_direction(int i1,int i2)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).
StaticAssertHolder()182   void StaticAssertHolder() {
183     STATIC_ASSERT(MAX_DIRECTION_FLAG_VALUE < (1 << kDirectionSizeBits));
184   }
185 
186   class ResultWriter {
187    public:
ResultWriter(Comparator::Output * chunk_writer)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     }
eq()192     void eq() {
193       FlushChunk();
194       pos1_++;
195       pos2_++;
196     }
skip1(int len1)197     void skip1(int len1) {
198       StartChunk();
199       pos1_ += len1;
200     }
skip2(int len2)201     void skip2(int len2) {
202       StartChunk();
203       pos2_ += len2;
204     }
close()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 
StartChunk()217     void StartChunk() {
218       if (!has_open_chunk_) {
219         pos1_begin_ = pos1_;
220         pos2_begin_ = pos2_;
221         has_open_chunk_ = true;
222       }
223     }
224 
FlushChunk()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 
CalculateDifference(Comparator::Input * input,Comparator::Output * result_writer)236 void 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 
CompareSubstrings(Handle<String> s1,int pos1,Handle<String> s2,int pos2,int len)245 static 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.
260 class 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 
267 class 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 
min(int a,int b)274 static 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.
NarrowDownInput(SubrangableInput * input,SubrangableOutput * output)281 static 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).
322 class CompareOutputArrayWriter {
323  public:
CompareOutputArrayWriter(Isolate * isolate)324   explicit CompareOutputArrayWriter(Isolate* isolate)
325       : array_(isolate->factory()->NewJSArray(10)), current_size_(0) {}
326 
GetResult()327   Handle<JSArray> GetResult() {
328     return array_;
329   }
330 
WriteChunk(int char_pos1,int char_pos2,int char_len1,int char_len2)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.
356 class TokensCompareInput : public Comparator::Input {
357  public:
TokensCompareInput(Handle<String> s1,int offset1,int len1,Handle<String> s2,int offset2,int len2)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   }
GetLength1()363   virtual int GetLength1() {
364     return len1_;
365   }
GetLength2()366   virtual int GetLength2() {
367     return len2_;
368   }
Equals(int index1,int index2)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.
385 class TokensCompareOutput : public Comparator::Output {
386  public:
TokensCompareOutput(CompareOutputArrayWriter * array_writer,int offset1,int offset2)387   TokensCompareOutput(CompareOutputArrayWriter* array_writer,
388                       int offset1, int offset2)
389         : array_writer_(array_writer), offset1_(offset1), offset2_(offset2) {
390   }
391 
AddChunk(int pos1,int pos2,int len1,int len2)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.
405 class LineEndsWrapper {
406  public:
LineEndsWrapper(Handle<String> string)407   explicit LineEndsWrapper(Handle<String> string)
408       : ends_array_(String::CalculateLineEnds(string, false)),
409         string_len_(string->length()) {
410   }
length()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.
GetLineStart(int index)416   int GetLineStart(int index) {
417     if (index == 0) {
418       return 0;
419     } else {
420       return GetLineEnd(index - 1);
421     }
422   }
GetLineEnd(int index)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 
GetPosAfterNewLine(int index)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.
445 class LineArrayCompareInput : public SubrangableInput {
446  public:
LineArrayCompareInput(Handle<String> s1,Handle<String> s2,LineEndsWrapper line_ends1,LineEndsWrapper line_ends2)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   }
GetLength1()455   int GetLength1() {
456     return subrange_len1_;
457   }
GetLength2()458   int GetLength2() {
459     return subrange_len2_;
460   }
Equals(int index1,int index2)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   }
SetSubrange1(int offset,int len)477   void SetSubrange1(int offset, int len) {
478     subrange_offset1_ = offset;
479     subrange_len1_ = len;
480   }
SetSubrange2(int offset,int len)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.
500 class TokenizingLineArrayCompareOutput : public SubrangableOutput {
501  public:
TokenizingLineArrayCompareOutput(LineEndsWrapper line_ends1,LineEndsWrapper line_ends2,Handle<String> s1,Handle<String> s2)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 
AddChunk(int line_pos1,int line_pos2,int line_len1,int line_len2)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   }
SetSubrange1(int offset,int len)533   void SetSubrange1(int offset, int len) {
534     subrange_offset1_ = offset;
535   }
SetSubrange2(int offset,int len)536   void SetSubrange2(int offset, int len) {
537     subrange_offset2_ = offset;
538   }
539 
GetResult()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 
CompareStrings(Handle<String> s1,Handle<String> s2)557 Handle<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"
UnwrapJSValue(Handle<JSValue> jsValue)577 static 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.
WrapInJSValue(Handle<HeapObject> object)584 static 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 
UnwrapSharedFunctionInfoFromJSValue(Handle<JSValue> jsValue)594 static 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 
GetArrayLength(Handle<JSArray> array)602 static int GetArrayLength(Handle<JSArray> array) {
603   Object* length = array->length();
604   CHECK(length->IsSmi());
605   return Smi::cast(length)->value();
606 }
607 
608 
SetInitialProperties(Handle<String> name,int start_position,int end_position,int param_num,int literal_count,int parent_index)609 void 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 
623 
SetFunctionCode(Handle<Code> function_code,Handle<HeapObject> code_scope_info)624 void FunctionInfoWrapper::SetFunctionCode(Handle<Code> function_code,
625                                           Handle<HeapObject> code_scope_info) {
626   Handle<JSValue> code_wrapper = WrapInJSValue(function_code);
627   this->SetField(kCodeOffset_, code_wrapper);
628 
629   Handle<JSValue> scope_wrapper = WrapInJSValue(code_scope_info);
630   this->SetField(kCodeScopeInfoOffset_, scope_wrapper);
631 }
632 
633 
SetSharedFunctionInfo(Handle<SharedFunctionInfo> info)634 void FunctionInfoWrapper::SetSharedFunctionInfo(
635     Handle<SharedFunctionInfo> info) {
636   Handle<JSValue> info_holder = WrapInJSValue(info);
637   this->SetField(kSharedFunctionInfoOffset_, info_holder);
638 }
639 
640 
GetFunctionCode()641 Handle<Code> FunctionInfoWrapper::GetFunctionCode() {
642   Handle<Object> element = this->GetField(kCodeOffset_);
643   Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element);
644   Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
645   CHECK(raw_result->IsCode());
646   return Handle<Code>::cast(raw_result);
647 }
648 
649 
GetFeedbackVector()650 MaybeHandle<TypeFeedbackVector> FunctionInfoWrapper::GetFeedbackVector() {
651   Handle<Object> element = this->GetField(kSharedFunctionInfoOffset_);
652   if (element->IsJSValue()) {
653     Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element);
654     Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
655     Handle<SharedFunctionInfo> shared =
656         Handle<SharedFunctionInfo>::cast(raw_result);
657     return Handle<TypeFeedbackVector>(shared->feedback_vector(), isolate());
658   } else {
659     // Scripts may never have a SharedFunctionInfo created.
660     return MaybeHandle<TypeFeedbackVector>();
661   }
662 }
663 
664 
GetCodeScopeInfo()665 Handle<Object> FunctionInfoWrapper::GetCodeScopeInfo() {
666   Handle<Object> element = this->GetField(kCodeScopeInfoOffset_);
667   return UnwrapJSValue(Handle<JSValue>::cast(element));
668 }
669 
670 
SetProperties(Handle<String> name,int start_position,int end_position,Handle<SharedFunctionInfo> info)671 void SharedInfoWrapper::SetProperties(Handle<String> name,
672                                       int start_position,
673                                       int end_position,
674                                       Handle<SharedFunctionInfo> info) {
675   HandleScope scope(isolate());
676   this->SetField(kFunctionNameOffset_, name);
677   Handle<JSValue> info_holder = WrapInJSValue(info);
678   this->SetField(kSharedInfoOffset_, info_holder);
679   this->SetSmiValueField(kStartPositionOffset_, start_position);
680   this->SetSmiValueField(kEndPositionOffset_, end_position);
681 }
682 
683 
GetInfo()684 Handle<SharedFunctionInfo> SharedInfoWrapper::GetInfo() {
685   Handle<Object> element = this->GetField(kSharedInfoOffset_);
686   Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element);
687   return UnwrapSharedFunctionInfoFromJSValue(value_wrapper);
688 }
689 
690 
691 class FunctionInfoListener {
692  public:
FunctionInfoListener(Isolate * isolate)693   explicit FunctionInfoListener(Isolate* isolate) {
694     current_parent_index_ = -1;
695     len_ = 0;
696     result_ = isolate->factory()->NewJSArray(10);
697   }
698 
FunctionStarted(FunctionLiteral * fun)699   void FunctionStarted(FunctionLiteral* fun) {
700     HandleScope scope(isolate());
701     FunctionInfoWrapper info = FunctionInfoWrapper::Create(isolate());
702     info.SetInitialProperties(fun->name(), fun->start_position(),
703                               fun->end_position(), fun->parameter_count(),
704                               fun->materialized_literal_count(),
705                               current_parent_index_);
706     current_parent_index_ = len_;
707     SetElementSloppy(result_, len_, info.GetJSArray());
708     len_++;
709   }
710 
FunctionDone()711   void FunctionDone() {
712     HandleScope scope(isolate());
713     FunctionInfoWrapper info =
714         FunctionInfoWrapper::cast(
715             *Object::GetElement(
716                 isolate(), result_, current_parent_index_).ToHandleChecked());
717     current_parent_index_ = info.GetParentIndex();
718   }
719 
720   // Saves only function code, because for a script function we
721   // may never create a SharedFunctionInfo object.
FunctionCode(Handle<Code> function_code)722   void FunctionCode(Handle<Code> function_code) {
723     FunctionInfoWrapper info =
724         FunctionInfoWrapper::cast(
725             *Object::GetElement(
726                 isolate(), result_, current_parent_index_).ToHandleChecked());
727     info.SetFunctionCode(function_code,
728                          Handle<HeapObject>(isolate()->heap()->null_value()));
729   }
730 
731   // Saves full information about a function: its code, its scope info
732   // and a SharedFunctionInfo object.
FunctionInfo(Handle<SharedFunctionInfo> shared,Scope * scope,Zone * zone)733   void FunctionInfo(Handle<SharedFunctionInfo> shared, Scope* scope,
734                     Zone* zone) {
735     if (!shared->IsSharedFunctionInfo()) {
736       return;
737     }
738     FunctionInfoWrapper info =
739         FunctionInfoWrapper::cast(
740             *Object::GetElement(
741                 isolate(), result_, current_parent_index_).ToHandleChecked());
742     info.SetFunctionCode(Handle<Code>(shared->code()),
743                          Handle<HeapObject>(shared->scope_info()));
744     info.SetSharedFunctionInfo(shared);
745 
746     Handle<Object> scope_info_list = SerializeFunctionScope(scope, zone);
747     info.SetFunctionScopeInfo(scope_info_list);
748   }
749 
GetResult()750   Handle<JSArray> GetResult() { return result_; }
751 
752  private:
isolate() const753   Isolate* isolate() const { return result_->GetIsolate(); }
754 
SerializeFunctionScope(Scope * scope,Zone * zone)755   Handle<Object> SerializeFunctionScope(Scope* scope, Zone* zone) {
756     Handle<JSArray> scope_info_list = isolate()->factory()->NewJSArray(10);
757     int scope_info_length = 0;
758 
759     // Saves some description of scope. It stores name and indexes of
760     // variables in the whole scope chain. Null-named slots delimit
761     // scopes of this chain.
762     Scope* current_scope = scope;
763     while (current_scope != NULL) {
764       HandleScope handle_scope(isolate());
765       ZoneList<Variable*> stack_list(current_scope->StackLocalCount(), zone);
766       ZoneList<Variable*> context_list(
767           current_scope->ContextLocalCount(), zone);
768       ZoneList<Variable*> globals_list(current_scope->ContextGlobalCount(),
769                                        zone);
770       current_scope->CollectStackAndContextLocals(&stack_list, &context_list,
771                                                   &globals_list);
772       context_list.Sort(&Variable::CompareIndex);
773 
774       for (int i = 0; i < context_list.length(); i++) {
775         SetElementSloppy(scope_info_list,
776                          scope_info_length,
777                          context_list[i]->name());
778         scope_info_length++;
779         SetElementSloppy(
780             scope_info_list,
781             scope_info_length,
782             Handle<Smi>(Smi::FromInt(context_list[i]->index()), isolate()));
783         scope_info_length++;
784       }
785       SetElementSloppy(scope_info_list,
786                        scope_info_length,
787                        Handle<Object>(isolate()->heap()->null_value(),
788                                       isolate()));
789       scope_info_length++;
790 
791       current_scope = current_scope->outer_scope();
792     }
793 
794     return scope_info_list;
795   }
796 
797   Handle<JSArray> result_;
798   int len_;
799   int current_parent_index_;
800 };
801 
802 
InitializeThreadLocal(Debug * debug)803 void LiveEdit::InitializeThreadLocal(Debug* debug) {
804   debug->thread_local_.frame_drop_mode_ = LiveEdit::FRAMES_UNTOUCHED;
805 }
806 
807 
SetAfterBreakTarget(Debug * debug)808 bool LiveEdit::SetAfterBreakTarget(Debug* debug) {
809   Code* code = NULL;
810   Isolate* isolate = debug->isolate_;
811   switch (debug->thread_local_.frame_drop_mode_) {
812     case FRAMES_UNTOUCHED:
813       return false;
814     case FRAME_DROPPED_IN_DEBUG_SLOT_CALL:
815       // Debug break slot stub does not return normally, instead it manually
816       // cleans the stack and jumps. We should patch the jump address.
817       code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit);
818       break;
819     case FRAME_DROPPED_IN_DIRECT_CALL:
820       // Nothing to do, after_break_target is not used here.
821       return true;
822     case FRAME_DROPPED_IN_RETURN_CALL:
823       code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit);
824       break;
825     case CURRENTLY_SET_MODE:
826       UNREACHABLE();
827       break;
828   }
829   debug->after_break_target_ = code->entry();
830   return true;
831 }
832 
833 
GatherCompileInfo(Handle<Script> script,Handle<String> source)834 MaybeHandle<JSArray> LiveEdit::GatherCompileInfo(Handle<Script> script,
835                                                  Handle<String> source) {
836   Isolate* isolate = script->GetIsolate();
837 
838   FunctionInfoListener listener(isolate);
839   Handle<Object> original_source =
840       Handle<Object>(script->source(), isolate);
841   script->set_source(*source);
842   isolate->set_active_function_info_listener(&listener);
843 
844   {
845     // Creating verbose TryCatch from public API is currently the only way to
846     // force code save location. We do not use this the object directly.
847     v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
848     try_catch.SetVerbose(true);
849 
850     // A logical 'try' section.
851     Compiler::CompileForLiveEdit(script);
852   }
853 
854   // A logical 'catch' section.
855   Handle<JSObject> rethrow_exception;
856   if (isolate->has_pending_exception()) {
857     Handle<Object> exception(isolate->pending_exception(), isolate);
858     MessageLocation message_location = isolate->GetMessageLocation();
859 
860     isolate->clear_pending_message();
861     isolate->clear_pending_exception();
862 
863     // If possible, copy positions from message object to exception object.
864     if (exception->IsJSObject() && !message_location.script().is_null()) {
865       rethrow_exception = Handle<JSObject>::cast(exception);
866 
867       Factory* factory = isolate->factory();
868       Handle<String> start_pos_key = factory->InternalizeOneByteString(
869           STATIC_CHAR_VECTOR("startPosition"));
870       Handle<String> end_pos_key =
871           factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("endPosition"));
872       Handle<String> script_obj_key =
873           factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("scriptObject"));
874       Handle<Smi> start_pos(
875           Smi::FromInt(message_location.start_pos()), isolate);
876       Handle<Smi> end_pos(Smi::FromInt(message_location.end_pos()), isolate);
877       Handle<JSObject> script_obj =
878           Script::GetWrapper(message_location.script());
879       Object::SetProperty(rethrow_exception, start_pos_key, start_pos, SLOPPY)
880           .Assert();
881       Object::SetProperty(rethrow_exception, end_pos_key, end_pos, SLOPPY)
882           .Assert();
883       Object::SetProperty(rethrow_exception, script_obj_key, script_obj, SLOPPY)
884           .Assert();
885     }
886   }
887 
888   // A logical 'finally' section.
889   isolate->set_active_function_info_listener(NULL);
890   script->set_source(*original_source);
891 
892   if (rethrow_exception.is_null()) {
893     return listener.GetResult();
894   } else {
895     return isolate->Throw<JSArray>(rethrow_exception);
896   }
897 }
898 
899 
900 // Visitor that finds all references to a particular code object,
901 // including "CODE_TARGET" references in other code objects and replaces
902 // them on the fly.
903 class ReplacingVisitor : public ObjectVisitor {
904  public:
ReplacingVisitor(Code * original,Code * substitution)905   explicit ReplacingVisitor(Code* original, Code* substitution)
906     : original_(original), substitution_(substitution) {
907   }
908 
VisitPointers(Object ** start,Object ** end)909   void VisitPointers(Object** start, Object** end) override {
910     for (Object** p = start; p < end; p++) {
911       if (*p == original_) {
912         *p = substitution_;
913       }
914     }
915   }
916 
VisitCodeEntry(Address entry)917   void VisitCodeEntry(Address entry) override {
918     if (Code::GetObjectFromEntryAddress(entry) == original_) {
919       Address substitution_entry = substitution_->instruction_start();
920       Memory::Address_at(entry) = substitution_entry;
921     }
922   }
923 
VisitCodeTarget(RelocInfo * rinfo)924   void VisitCodeTarget(RelocInfo* rinfo) override {
925     if (RelocInfo::IsCodeTarget(rinfo->rmode()) &&
926         Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) {
927       Address substitution_entry = substitution_->instruction_start();
928       rinfo->set_target_address(substitution_entry);
929     }
930   }
931 
VisitDebugTarget(RelocInfo * rinfo)932   void VisitDebugTarget(RelocInfo* rinfo) override { VisitCodeTarget(rinfo); }
933 
934  private:
935   Code* original_;
936   Code* substitution_;
937 };
938 
939 
940 // Finds all references to original and replaces them with substitution.
ReplaceCodeObject(Handle<Code> original,Handle<Code> substitution)941 static void ReplaceCodeObject(Handle<Code> original,
942                               Handle<Code> substitution) {
943   // Perform a full GC in order to ensure that we are not in the middle of an
944   // incremental marking phase when we are replacing the code object.
945   // Since we are not in an incremental marking phase we can write pointers
946   // to code objects (that are never in new space) without worrying about
947   // write barriers.
948   Heap* heap = original->GetHeap();
949   HeapIterator iterator(heap);
950 
951   DCHECK(!heap->InNewSpace(*substitution));
952 
953   ReplacingVisitor visitor(*original, *substitution);
954 
955   // Iterate over all roots. Stack frames may have pointer into original code,
956   // so temporary replace the pointers with offset numbers
957   // in prologue/epilogue.
958   heap->IterateRoots(&visitor, VISIT_ALL);
959 
960   // Now iterate over all pointers of all objects, including code_target
961   // implicit pointers.
962   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
963     obj->Iterate(&visitor);
964   }
965 }
966 
967 
968 // Patch function literals.
969 // Name 'literals' is a misnomer. Rather it's a cache for complex object
970 // boilerplates and for a native context. We must clean cached values.
971 // Additionally we may need to allocate a new array if number of literals
972 // changed.
973 class LiteralFixer {
974  public:
PatchLiterals(FunctionInfoWrapper * compile_info_wrapper,Handle<SharedFunctionInfo> shared_info,Isolate * isolate)975   static void PatchLiterals(FunctionInfoWrapper* compile_info_wrapper,
976                             Handle<SharedFunctionInfo> shared_info,
977                             Isolate* isolate) {
978     int new_literal_count = compile_info_wrapper->GetLiteralCount();
979     int old_literal_count = shared_info->num_literals();
980 
981     if (old_literal_count == new_literal_count) {
982       // If literal count didn't change, simply go over all functions
983       // and clear literal arrays.
984       ClearValuesVisitor visitor;
985       IterateJSFunctions(shared_info, &visitor);
986     } else {
987       // When literal count changes, we have to create new array instances.
988       // Since we cannot create instances when iterating heap, we should first
989       // collect all functions and fix their literal arrays.
990       Handle<FixedArray> function_instances =
991           CollectJSFunctions(shared_info, isolate);
992       Handle<TypeFeedbackVector> vector(shared_info->feedback_vector());
993 
994       for (int i = 0; i < function_instances->length(); i++) {
995         Handle<JSFunction> fun(JSFunction::cast(function_instances->get(i)));
996         Handle<LiteralsArray> new_literals =
997             LiteralsArray::New(isolate, vector, new_literal_count, TENURED);
998         fun->set_literals(*new_literals);
999       }
1000 
1001       shared_info->set_num_literals(new_literal_count);
1002     }
1003   }
1004 
1005  private:
1006   // Iterates all function instances in the HEAP that refers to the
1007   // provided shared_info.
1008   template<typename Visitor>
IterateJSFunctions(Handle<SharedFunctionInfo> shared_info,Visitor * visitor)1009   static void IterateJSFunctions(Handle<SharedFunctionInfo> shared_info,
1010                                  Visitor* visitor) {
1011     HeapIterator iterator(shared_info->GetHeap());
1012     for (HeapObject* obj = iterator.next(); obj != NULL;
1013         obj = iterator.next()) {
1014       if (obj->IsJSFunction()) {
1015         JSFunction* function = JSFunction::cast(obj);
1016         if (function->shared() == *shared_info) {
1017           visitor->visit(function);
1018         }
1019       }
1020     }
1021   }
1022 
1023   // Finds all instances of JSFunction that refers to the provided shared_info
1024   // and returns array with them.
CollectJSFunctions(Handle<SharedFunctionInfo> shared_info,Isolate * isolate)1025   static Handle<FixedArray> CollectJSFunctions(
1026       Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
1027     CountVisitor count_visitor;
1028     count_visitor.count = 0;
1029     IterateJSFunctions(shared_info, &count_visitor);
1030     int size = count_visitor.count;
1031 
1032     Handle<FixedArray> result = isolate->factory()->NewFixedArray(size);
1033     if (size > 0) {
1034       CollectVisitor collect_visitor(result);
1035       IterateJSFunctions(shared_info, &collect_visitor);
1036     }
1037     return result;
1038   }
1039 
1040   class ClearValuesVisitor {
1041    public:
visit(JSFunction * fun)1042     void visit(JSFunction* fun) {
1043       FixedArray* literals = fun->literals();
1044       int len = literals->length();
1045       for (int j = 0; j < len; j++) {
1046         literals->set_undefined(j);
1047       }
1048     }
1049   };
1050 
1051   class CountVisitor {
1052    public:
visit(JSFunction * fun)1053     void visit(JSFunction* fun) {
1054       count++;
1055     }
1056     int count;
1057   };
1058 
1059   class CollectVisitor {
1060    public:
CollectVisitor(Handle<FixedArray> output)1061     explicit CollectVisitor(Handle<FixedArray> output)
1062         : m_output(output), m_pos(0) {}
1063 
visit(JSFunction * fun)1064     void visit(JSFunction* fun) {
1065       m_output->set(m_pos, fun);
1066       m_pos++;
1067     }
1068    private:
1069     Handle<FixedArray> m_output;
1070     int m_pos;
1071   };
1072 };
1073 
1074 
1075 // Marks code that shares the same shared function info or has inlined
1076 // code that shares the same function info.
1077 class DependentFunctionMarker: public OptimizedFunctionVisitor {
1078  public:
1079   SharedFunctionInfo* shared_info_;
1080   bool found_;
1081 
DependentFunctionMarker(SharedFunctionInfo * shared_info)1082   explicit DependentFunctionMarker(SharedFunctionInfo* shared_info)
1083     : shared_info_(shared_info), found_(false) { }
1084 
EnterContext(Context * context)1085   virtual void EnterContext(Context* context) { }  // Don't care.
LeaveContext(Context * context)1086   virtual void LeaveContext(Context* context)  { }  // Don't care.
VisitFunction(JSFunction * function)1087   virtual void VisitFunction(JSFunction* function) {
1088     // It should be guaranteed by the iterator that everything is optimized.
1089     DCHECK(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
1090     if (function->Inlines(shared_info_)) {
1091       // Mark the code for deoptimization.
1092       function->code()->set_marked_for_deoptimization(true);
1093       found_ = true;
1094     }
1095   }
1096 };
1097 
1098 
DeoptimizeDependentFunctions(SharedFunctionInfo * function_info)1099 static void DeoptimizeDependentFunctions(SharedFunctionInfo* function_info) {
1100   DisallowHeapAllocation no_allocation;
1101   DependentFunctionMarker marker(function_info);
1102   // TODO(titzer): need to traverse all optimized code to find OSR code here.
1103   Deoptimizer::VisitAllOptimizedFunctions(function_info->GetIsolate(), &marker);
1104 
1105   if (marker.found_) {
1106     // Only go through with the deoptimization if something was found.
1107     Deoptimizer::DeoptimizeMarkedCode(function_info->GetIsolate());
1108   }
1109 }
1110 
1111 
ReplaceFunctionCode(Handle<JSArray> new_compile_info_array,Handle<JSArray> shared_info_array)1112 void LiveEdit::ReplaceFunctionCode(
1113     Handle<JSArray> new_compile_info_array,
1114     Handle<JSArray> shared_info_array) {
1115   Isolate* isolate = new_compile_info_array->GetIsolate();
1116 
1117   FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
1118   SharedInfoWrapper shared_info_wrapper(shared_info_array);
1119 
1120   Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
1121 
1122   if (shared_info->code()->kind() == Code::FUNCTION) {
1123     Handle<Code> code = compile_info_wrapper.GetFunctionCode();
1124     ReplaceCodeObject(Handle<Code>(shared_info->code()), code);
1125     Handle<Object> code_scope_info = compile_info_wrapper.GetCodeScopeInfo();
1126     if (code_scope_info->IsFixedArray()) {
1127       shared_info->set_scope_info(ScopeInfo::cast(*code_scope_info));
1128     }
1129     shared_info->DisableOptimization(kLiveEdit);
1130     // Update the type feedback vector, if needed.
1131     MaybeHandle<TypeFeedbackVector> feedback_vector =
1132         compile_info_wrapper.GetFeedbackVector();
1133     if (!feedback_vector.is_null()) {
1134       shared_info->set_feedback_vector(*feedback_vector.ToHandleChecked());
1135     }
1136   }
1137 
1138   int start_position = compile_info_wrapper.GetStartPosition();
1139   int end_position = compile_info_wrapper.GetEndPosition();
1140   shared_info->set_start_position(start_position);
1141   shared_info->set_end_position(end_position);
1142 
1143   LiteralFixer::PatchLiterals(&compile_info_wrapper, shared_info, isolate);
1144 
1145   DeoptimizeDependentFunctions(*shared_info);
1146   isolate->compilation_cache()->Remove(shared_info);
1147 }
1148 
1149 
FunctionSourceUpdated(Handle<JSArray> shared_info_array)1150 void LiveEdit::FunctionSourceUpdated(Handle<JSArray> shared_info_array) {
1151   SharedInfoWrapper shared_info_wrapper(shared_info_array);
1152   Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
1153 
1154   DeoptimizeDependentFunctions(*shared_info);
1155   shared_info_array->GetIsolate()->compilation_cache()->Remove(shared_info);
1156 }
1157 
1158 
SetFunctionScript(Handle<JSValue> function_wrapper,Handle<Object> script_handle)1159 void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
1160                                  Handle<Object> script_handle) {
1161   Handle<SharedFunctionInfo> shared_info =
1162       UnwrapSharedFunctionInfoFromJSValue(function_wrapper);
1163   CHECK(script_handle->IsScript() || script_handle->IsUndefined());
1164   SharedFunctionInfo::SetScript(shared_info, script_handle);
1165   shared_info->DisableOptimization(kLiveEdit);
1166 
1167   function_wrapper->GetIsolate()->compilation_cache()->Remove(shared_info);
1168 }
1169 
1170 
1171 // For a script text change (defined as position_change_array), translates
1172 // position in unchanged text to position in changed text.
1173 // Text change is a set of non-overlapping regions in text, that have changed
1174 // their contents and length. It is specified as array of groups of 3 numbers:
1175 // (change_begin, change_end, change_end_new_position).
1176 // Each group describes a change in text; groups are sorted by change_begin.
1177 // Only position in text beyond any changes may be successfully translated.
1178 // If a positions is inside some region that changed, result is currently
1179 // undefined.
TranslatePosition(int original_position,Handle<JSArray> position_change_array)1180 static int TranslatePosition(int original_position,
1181                              Handle<JSArray> position_change_array) {
1182   int position_diff = 0;
1183   int array_len = GetArrayLength(position_change_array);
1184   Isolate* isolate = position_change_array->GetIsolate();
1185   // TODO(635): binary search may be used here
1186   for (int i = 0; i < array_len; i += 3) {
1187     HandleScope scope(isolate);
1188     Handle<Object> element = Object::GetElement(
1189         isolate, position_change_array, i).ToHandleChecked();
1190     CHECK(element->IsSmi());
1191     int chunk_start = Handle<Smi>::cast(element)->value();
1192     if (original_position < chunk_start) {
1193       break;
1194     }
1195     element = Object::GetElement(
1196         isolate, position_change_array, i + 1).ToHandleChecked();
1197     CHECK(element->IsSmi());
1198     int chunk_end = Handle<Smi>::cast(element)->value();
1199     // Position mustn't be inside a chunk.
1200     DCHECK(original_position >= chunk_end);
1201     element = Object::GetElement(
1202         isolate, position_change_array, i + 2).ToHandleChecked();
1203     CHECK(element->IsSmi());
1204     int chunk_changed_end = Handle<Smi>::cast(element)->value();
1205     position_diff = chunk_changed_end - chunk_end;
1206   }
1207 
1208   return original_position + position_diff;
1209 }
1210 
1211 
1212 // Auto-growing buffer for writing relocation info code section. This buffer
1213 // is a simplified version of buffer from Assembler. Unlike Assembler, this
1214 // class is platform-independent and it works without dealing with instructions.
1215 // As specified by RelocInfo format, the buffer is filled in reversed order:
1216 // from upper to lower addresses.
1217 // It uses NewArray/DeleteArray for memory management.
1218 class RelocInfoBuffer {
1219  public:
RelocInfoBuffer(int buffer_initial_capicity,byte * pc)1220   RelocInfoBuffer(int buffer_initial_capicity, byte* pc) {
1221     buffer_size_ = buffer_initial_capicity + kBufferGap;
1222     buffer_ = NewArray<byte>(buffer_size_);
1223 
1224     reloc_info_writer_.Reposition(buffer_ + buffer_size_, pc);
1225   }
~RelocInfoBuffer()1226   ~RelocInfoBuffer() {
1227     DeleteArray(buffer_);
1228   }
1229 
1230   // As specified by RelocInfo format, the buffer is filled in reversed order:
1231   // from upper to lower addresses.
Write(const RelocInfo * rinfo)1232   void Write(const RelocInfo* rinfo) {
1233     if (buffer_ + kBufferGap >= reloc_info_writer_.pos()) {
1234       Grow();
1235     }
1236     reloc_info_writer_.Write(rinfo);
1237   }
1238 
GetResult()1239   Vector<byte> GetResult() {
1240     // Return the bytes from pos up to end of buffer.
1241     int result_size =
1242         static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer_.pos());
1243     return Vector<byte>(reloc_info_writer_.pos(), result_size);
1244   }
1245 
1246  private:
Grow()1247   void Grow() {
1248     // Compute new buffer size.
1249     int new_buffer_size;
1250     if (buffer_size_ < 2 * KB) {
1251       new_buffer_size = 4 * KB;
1252     } else {
1253       new_buffer_size = 2 * buffer_size_;
1254     }
1255     // Some internal data structures overflow for very large buffers,
1256     // they must ensure that kMaximalBufferSize is not too large.
1257     if (new_buffer_size > kMaximalBufferSize) {
1258       V8::FatalProcessOutOfMemory("RelocInfoBuffer::GrowBuffer");
1259     }
1260 
1261     // Set up new buffer.
1262     byte* new_buffer = NewArray<byte>(new_buffer_size);
1263 
1264     // Copy the data.
1265     int curently_used_size =
1266         static_cast<int>(buffer_ + buffer_size_ - reloc_info_writer_.pos());
1267     MemMove(new_buffer + new_buffer_size - curently_used_size,
1268             reloc_info_writer_.pos(), curently_used_size);
1269 
1270     reloc_info_writer_.Reposition(
1271         new_buffer + new_buffer_size - curently_used_size,
1272         reloc_info_writer_.last_pc());
1273 
1274     DeleteArray(buffer_);
1275     buffer_ = new_buffer;
1276     buffer_size_ = new_buffer_size;
1277   }
1278 
1279   RelocInfoWriter reloc_info_writer_;
1280   byte* buffer_;
1281   int buffer_size_;
1282 
1283   static const int kBufferGap = RelocInfoWriter::kMaxSize;
1284   static const int kMaximalBufferSize = 512*MB;
1285 };
1286 
1287 
1288 // Patch positions in code (changes relocation info section) and possibly
1289 // returns new instance of code.
PatchPositionsInCode(Handle<Code> code,Handle<JSArray> position_change_array)1290 static Handle<Code> PatchPositionsInCode(
1291     Handle<Code> code,
1292     Handle<JSArray> position_change_array) {
1293   Isolate* isolate = code->GetIsolate();
1294 
1295   RelocInfoBuffer buffer_writer(code->relocation_size(),
1296                                 code->instruction_start());
1297 
1298   {
1299     for (RelocIterator it(*code); !it.done(); it.next()) {
1300       RelocInfo* rinfo = it.rinfo();
1301       if (RelocInfo::IsPosition(rinfo->rmode())) {
1302         int position = static_cast<int>(rinfo->data());
1303         int new_position = TranslatePosition(position,
1304                                              position_change_array);
1305         if (position != new_position) {
1306           RelocInfo info_copy(rinfo->isolate(), rinfo->pc(), rinfo->rmode(),
1307                               new_position, NULL);
1308           buffer_writer.Write(&info_copy);
1309           continue;
1310         }
1311       }
1312       if (RelocInfo::IsRealRelocMode(rinfo->rmode())) {
1313         buffer_writer.Write(it.rinfo());
1314       }
1315     }
1316   }
1317 
1318   Vector<byte> buffer = buffer_writer.GetResult();
1319 
1320   if (buffer.length() == code->relocation_size()) {
1321     // Simply patch relocation area of code.
1322     MemCopy(code->relocation_start(), buffer.start(), buffer.length());
1323     return code;
1324   } else {
1325     // Relocation info section now has different size. We cannot simply
1326     // rewrite it inside code object. Instead we have to create a new
1327     // code object.
1328     Handle<Code> result(isolate->factory()->CopyCode(code, buffer));
1329     return result;
1330   }
1331 }
1332 
1333 
PatchFunctionPositions(Handle<JSArray> shared_info_array,Handle<JSArray> position_change_array)1334 void LiveEdit::PatchFunctionPositions(Handle<JSArray> shared_info_array,
1335                                       Handle<JSArray> position_change_array) {
1336   SharedInfoWrapper shared_info_wrapper(shared_info_array);
1337   Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo();
1338 
1339   int old_function_start = info->start_position();
1340   int new_function_start = TranslatePosition(old_function_start,
1341                                              position_change_array);
1342   int new_function_end = TranslatePosition(info->end_position(),
1343                                            position_change_array);
1344   int new_function_token_pos =
1345       TranslatePosition(info->function_token_position(), position_change_array);
1346 
1347   info->set_start_position(new_function_start);
1348   info->set_end_position(new_function_end);
1349   info->set_function_token_position(new_function_token_pos);
1350 
1351   if (info->code()->kind() == Code::FUNCTION) {
1352     // Patch relocation info section of the code.
1353     Handle<Code> patched_code = PatchPositionsInCode(Handle<Code>(info->code()),
1354                                                      position_change_array);
1355     if (*patched_code != info->code()) {
1356       // Replace all references to the code across the heap. In particular,
1357       // some stubs may refer to this code and this code may be being executed
1358       // on stack (it is safe to substitute the code object on stack, because
1359       // we only change the structure of rinfo and leave instructions
1360       // untouched).
1361       ReplaceCodeObject(Handle<Code>(info->code()), patched_code);
1362     }
1363   }
1364 }
1365 
1366 
CreateScriptCopy(Handle<Script> original)1367 static Handle<Script> CreateScriptCopy(Handle<Script> original) {
1368   Isolate* isolate = original->GetIsolate();
1369 
1370   Handle<String> original_source(String::cast(original->source()));
1371   Handle<Script> copy = isolate->factory()->NewScript(original_source);
1372 
1373   copy->set_name(original->name());
1374   copy->set_line_offset(original->line_offset());
1375   copy->set_column_offset(original->column_offset());
1376   copy->set_type(original->type());
1377   copy->set_context_data(original->context_data());
1378   copy->set_eval_from_shared(original->eval_from_shared());
1379   copy->set_eval_from_instructions_offset(
1380       original->eval_from_instructions_offset());
1381 
1382   // Copy all the flags, but clear compilation state.
1383   copy->set_flags(original->flags());
1384   copy->set_compilation_state(Script::COMPILATION_STATE_INITIAL);
1385 
1386   return copy;
1387 }
1388 
1389 
ChangeScriptSource(Handle<Script> original_script,Handle<String> new_source,Handle<Object> old_script_name)1390 Handle<Object> LiveEdit::ChangeScriptSource(Handle<Script> original_script,
1391                                             Handle<String> new_source,
1392                                             Handle<Object> old_script_name) {
1393   Isolate* isolate = original_script->GetIsolate();
1394   Handle<Object> old_script_object;
1395   if (old_script_name->IsString()) {
1396     Handle<Script> old_script = CreateScriptCopy(original_script);
1397     old_script->set_name(String::cast(*old_script_name));
1398     old_script_object = old_script;
1399     isolate->debug()->OnAfterCompile(old_script);
1400   } else {
1401     old_script_object = isolate->factory()->null_value();
1402   }
1403 
1404   original_script->set_source(*new_source);
1405 
1406   // Drop line ends so that they will be recalculated.
1407   original_script->set_line_ends(isolate->heap()->undefined_value());
1408 
1409   return old_script_object;
1410 }
1411 
1412 
1413 
ReplaceRefToNestedFunction(Handle<JSValue> parent_function_wrapper,Handle<JSValue> orig_function_wrapper,Handle<JSValue> subst_function_wrapper)1414 void LiveEdit::ReplaceRefToNestedFunction(
1415     Handle<JSValue> parent_function_wrapper,
1416     Handle<JSValue> orig_function_wrapper,
1417     Handle<JSValue> subst_function_wrapper) {
1418 
1419   Handle<SharedFunctionInfo> parent_shared =
1420       UnwrapSharedFunctionInfoFromJSValue(parent_function_wrapper);
1421   Handle<SharedFunctionInfo> orig_shared =
1422       UnwrapSharedFunctionInfoFromJSValue(orig_function_wrapper);
1423   Handle<SharedFunctionInfo> subst_shared =
1424       UnwrapSharedFunctionInfoFromJSValue(subst_function_wrapper);
1425 
1426   for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) {
1427     if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) {
1428       if (it.rinfo()->target_object() == *orig_shared) {
1429         it.rinfo()->set_target_object(*subst_shared);
1430       }
1431     }
1432   }
1433 }
1434 
1435 
1436 // Check an activation against list of functions. If there is a function
1437 // that matches, its status in result array is changed to status argument value.
CheckActivation(Handle<JSArray> shared_info_array,Handle<JSArray> result,StackFrame * frame,LiveEdit::FunctionPatchabilityStatus status)1438 static bool CheckActivation(Handle<JSArray> shared_info_array,
1439                             Handle<JSArray> result,
1440                             StackFrame* frame,
1441                             LiveEdit::FunctionPatchabilityStatus status) {
1442   if (!frame->is_java_script()) return false;
1443 
1444   Handle<JSFunction> function(JavaScriptFrame::cast(frame)->function());
1445 
1446   Isolate* isolate = shared_info_array->GetIsolate();
1447   int len = GetArrayLength(shared_info_array);
1448   for (int i = 0; i < len; i++) {
1449     HandleScope scope(isolate);
1450     Handle<Object> element =
1451         Object::GetElement(isolate, shared_info_array, i).ToHandleChecked();
1452     Handle<JSValue> jsvalue = Handle<JSValue>::cast(element);
1453     Handle<SharedFunctionInfo> shared =
1454         UnwrapSharedFunctionInfoFromJSValue(jsvalue);
1455 
1456     if (function->Inlines(*shared)) {
1457       SetElementSloppy(result, i, Handle<Smi>(Smi::FromInt(status), isolate));
1458       return true;
1459     }
1460   }
1461   return false;
1462 }
1463 
1464 
1465 // Iterates over handler chain and removes all elements that are inside
1466 // frames being dropped.
FixTryCatchHandler(StackFrame * top_frame,StackFrame * bottom_frame)1467 static bool FixTryCatchHandler(StackFrame* top_frame,
1468                                StackFrame* bottom_frame) {
1469   Address* pointer_address =
1470       &Memory::Address_at(top_frame->isolate()->get_address_from_id(
1471           Isolate::kHandlerAddress));
1472 
1473   while (*pointer_address < top_frame->sp()) {
1474     pointer_address = &Memory::Address_at(*pointer_address);
1475   }
1476   Address* above_frame_address = pointer_address;
1477   while (*pointer_address < bottom_frame->fp()) {
1478     pointer_address = &Memory::Address_at(*pointer_address);
1479   }
1480   bool change = *above_frame_address != *pointer_address;
1481   *above_frame_address = *pointer_address;
1482   return change;
1483 }
1484 
1485 
1486 // Initializes an artificial stack frame. The data it contains is used for:
1487 //  a. successful work of frame dropper code which eventually gets control,
1488 //  b. being compatible with regular stack structure for various stack
1489 //     iterators.
1490 // Frame structure (conforms InternalFrame structure):
1491 //   -- code
1492 //   -- SMI maker
1493 //   -- function (slot is called "context")
1494 //   -- frame base
SetUpFrameDropperFrame(StackFrame * bottom_js_frame,Handle<Code> code)1495 static void SetUpFrameDropperFrame(StackFrame* bottom_js_frame,
1496                                    Handle<Code> code) {
1497   DCHECK(bottom_js_frame->is_java_script());
1498 
1499   Address fp = bottom_js_frame->fp();
1500 
1501   // Move function pointer into "context" slot.
1502   Memory::Object_at(fp + StandardFrameConstants::kContextOffset) =
1503       Memory::Object_at(fp + JavaScriptFrameConstants::kFunctionOffset);
1504 
1505   Memory::Object_at(fp + InternalFrameConstants::kCodeOffset) = *code;
1506   Memory::Object_at(fp + StandardFrameConstants::kMarkerOffset) =
1507       Smi::FromInt(StackFrame::INTERNAL);
1508 }
1509 
1510 
1511 // Removes specified range of frames from stack. There may be 1 or more
1512 // frames in range. Anyway the bottom frame is restarted rather than dropped,
1513 // and therefore has to be a JavaScript frame.
1514 // Returns error message or NULL.
DropFrames(Vector<StackFrame * > frames,int top_frame_index,int bottom_js_frame_index,LiveEdit::FrameDropMode * mode)1515 static const char* DropFrames(Vector<StackFrame*> frames, int top_frame_index,
1516                               int bottom_js_frame_index,
1517                               LiveEdit::FrameDropMode* mode) {
1518   if (!LiveEdit::kFrameDropperSupported) {
1519     return "Stack manipulations are not supported in this architecture.";
1520   }
1521 
1522   StackFrame* pre_top_frame = frames[top_frame_index - 1];
1523   StackFrame* top_frame = frames[top_frame_index];
1524   StackFrame* bottom_js_frame = frames[bottom_js_frame_index];
1525 
1526   DCHECK(bottom_js_frame->is_java_script());
1527 
1528   // Check the nature of the top frame.
1529   Isolate* isolate = bottom_js_frame->isolate();
1530   Code* pre_top_frame_code = pre_top_frame->LookupCode();
1531   bool frame_has_padding = true;
1532   if (pre_top_frame_code ==
1533       isolate->builtins()->builtin(Builtins::kSlot_DebugBreak)) {
1534     // OK, we can drop debug break slot.
1535     *mode = LiveEdit::FRAME_DROPPED_IN_DEBUG_SLOT_CALL;
1536   } else if (pre_top_frame_code ==
1537              isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit)) {
1538     // OK, we can drop our own code.
1539     pre_top_frame = frames[top_frame_index - 2];
1540     top_frame = frames[top_frame_index - 1];
1541     *mode = LiveEdit::CURRENTLY_SET_MODE;
1542     frame_has_padding = false;
1543   } else if (pre_top_frame_code ==
1544              isolate->builtins()->builtin(Builtins::kReturn_DebugBreak)) {
1545     *mode = LiveEdit::FRAME_DROPPED_IN_RETURN_CALL;
1546   } else if (pre_top_frame_code->kind() == Code::STUB &&
1547              CodeStub::GetMajorKey(pre_top_frame_code) == CodeStub::CEntry) {
1548     // Entry from our unit tests on 'debugger' statement.
1549     // It's fine, we support this case.
1550     *mode = LiveEdit::FRAME_DROPPED_IN_DIRECT_CALL;
1551     // We don't have a padding from 'debugger' statement call.
1552     // Here the stub is CEntry, it's not debug-only and can't be padded.
1553     // If anyone would complain, a proxy padded stub could be added.
1554     frame_has_padding = false;
1555   } else if (pre_top_frame->type() == StackFrame::ARGUMENTS_ADAPTOR) {
1556     // This must be adaptor that remain from the frame dropping that
1557     // is still on stack. A frame dropper frame must be above it.
1558     DCHECK(frames[top_frame_index - 2]->LookupCode() ==
1559            isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit));
1560     pre_top_frame = frames[top_frame_index - 3];
1561     top_frame = frames[top_frame_index - 2];
1562     *mode = LiveEdit::CURRENTLY_SET_MODE;
1563     frame_has_padding = false;
1564   } else {
1565     return "Unknown structure of stack above changing function";
1566   }
1567 
1568   Address unused_stack_top = top_frame->sp();
1569   int new_frame_size = LiveEdit::kFrameDropperFrameSize * kPointerSize;
1570   Address unused_stack_bottom = bottom_js_frame->fp()
1571       - new_frame_size + kPointerSize;  // Bigger address end is exclusive.
1572 
1573   Address* top_frame_pc_address = top_frame->pc_address();
1574 
1575   // top_frame may be damaged below this point. Do not used it.
1576   DCHECK(!(top_frame = NULL));
1577 
1578   if (unused_stack_top > unused_stack_bottom) {
1579     if (frame_has_padding) {
1580       int shortage_bytes =
1581           static_cast<int>(unused_stack_top - unused_stack_bottom);
1582 
1583       Address padding_start = pre_top_frame->fp() -
1584           LiveEdit::kFrameDropperFrameSize * kPointerSize;
1585 
1586       Address padding_pointer = padding_start;
1587       Smi* padding_object = Smi::FromInt(LiveEdit::kFramePaddingValue);
1588       while (Memory::Object_at(padding_pointer) == padding_object) {
1589         padding_pointer -= kPointerSize;
1590       }
1591       int padding_counter =
1592           Smi::cast(Memory::Object_at(padding_pointer))->value();
1593       if (padding_counter * kPointerSize < shortage_bytes) {
1594         return "Not enough space for frame dropper frame "
1595             "(even with padding frame)";
1596       }
1597       Memory::Object_at(padding_pointer) =
1598           Smi::FromInt(padding_counter - shortage_bytes / kPointerSize);
1599 
1600       StackFrame* pre_pre_frame = frames[top_frame_index - 2];
1601 
1602       MemMove(padding_start + kPointerSize - shortage_bytes,
1603               padding_start + kPointerSize,
1604               LiveEdit::kFrameDropperFrameSize * kPointerSize);
1605 
1606       pre_top_frame->UpdateFp(pre_top_frame->fp() - shortage_bytes);
1607       pre_pre_frame->SetCallerFp(pre_top_frame->fp());
1608       unused_stack_top -= shortage_bytes;
1609 
1610       STATIC_ASSERT(sizeof(Address) == kPointerSize);
1611       top_frame_pc_address -= shortage_bytes / kPointerSize;
1612     } else {
1613       return "Not enough space for frame dropper frame";
1614     }
1615   }
1616 
1617   // Committing now. After this point we should return only NULL value.
1618 
1619   FixTryCatchHandler(pre_top_frame, bottom_js_frame);
1620   // Make sure FixTryCatchHandler is idempotent.
1621   DCHECK(!FixTryCatchHandler(pre_top_frame, bottom_js_frame));
1622 
1623   Handle<Code> code = isolate->builtins()->FrameDropper_LiveEdit();
1624   *top_frame_pc_address = code->entry();
1625   pre_top_frame->SetCallerFp(bottom_js_frame->fp());
1626 
1627   SetUpFrameDropperFrame(bottom_js_frame, code);
1628 
1629   for (Address a = unused_stack_top;
1630       a < unused_stack_bottom;
1631       a += kPointerSize) {
1632     Memory::Object_at(a) = Smi::FromInt(0);
1633   }
1634 
1635   return NULL;
1636 }
1637 
1638 
1639 // Describes a set of call frames that execute any of listed functions.
1640 // Finding no such frames does not mean error.
1641 class MultipleFunctionTarget {
1642  public:
MultipleFunctionTarget(Handle<JSArray> old_shared_array,Handle<JSArray> new_shared_array,Handle<JSArray> result)1643   MultipleFunctionTarget(Handle<JSArray> old_shared_array,
1644                          Handle<JSArray> new_shared_array,
1645                          Handle<JSArray> result)
1646       : old_shared_array_(old_shared_array),
1647         new_shared_array_(new_shared_array),
1648         result_(result) {}
MatchActivation(StackFrame * frame,LiveEdit::FunctionPatchabilityStatus status)1649   bool MatchActivation(StackFrame* frame,
1650       LiveEdit::FunctionPatchabilityStatus status) {
1651     return CheckActivation(old_shared_array_, result_, frame, status);
1652   }
GetNotFoundMessage() const1653   const char* GetNotFoundMessage() const {
1654     return NULL;
1655   }
FrameUsesNewTarget(StackFrame * frame)1656   bool FrameUsesNewTarget(StackFrame* frame) {
1657     if (!frame->is_java_script()) return false;
1658     JavaScriptFrame* jsframe = JavaScriptFrame::cast(frame);
1659     Handle<SharedFunctionInfo> old_shared(jsframe->function()->shared());
1660     Isolate* isolate = old_shared->GetIsolate();
1661     int len = GetArrayLength(old_shared_array_);
1662     // Find corresponding new shared function info and return whether it
1663     // references new.target.
1664     for (int i = 0; i < len; i++) {
1665       HandleScope scope(isolate);
1666       Handle<Object> old_element =
1667           Object::GetElement(isolate, old_shared_array_, i).ToHandleChecked();
1668       if (!old_shared.is_identical_to(UnwrapSharedFunctionInfoFromJSValue(
1669               Handle<JSValue>::cast(old_element)))) {
1670         continue;
1671       }
1672 
1673       Handle<Object> new_element =
1674           Object::GetElement(isolate, new_shared_array_, i).ToHandleChecked();
1675       if (new_element->IsUndefined()) return false;
1676       Handle<SharedFunctionInfo> new_shared =
1677           UnwrapSharedFunctionInfoFromJSValue(
1678               Handle<JSValue>::cast(new_element));
1679       if (new_shared->scope_info()->HasNewTarget()) {
1680         SetElementSloppy(
1681             result_, i,
1682             Handle<Smi>(
1683                 Smi::FromInt(
1684                     LiveEdit::FUNCTION_BLOCKED_NO_NEW_TARGET_ON_RESTART),
1685                 isolate));
1686         return true;
1687       }
1688       return false;
1689     }
1690     return false;
1691   }
1692 
1693  private:
1694   Handle<JSArray> old_shared_array_;
1695   Handle<JSArray> new_shared_array_;
1696   Handle<JSArray> result_;
1697 };
1698 
1699 
1700 // Drops all call frame matched by target and all frames above them.
1701 template <typename TARGET>
DropActivationsInActiveThreadImpl(Isolate * isolate,TARGET & target,bool do_drop)1702 static const char* DropActivationsInActiveThreadImpl(Isolate* isolate,
1703                                                      TARGET& target,  // NOLINT
1704                                                      bool do_drop) {
1705   Debug* debug = isolate->debug();
1706   Zone zone;
1707   Vector<StackFrame*> frames = CreateStackMap(isolate, &zone);
1708 
1709 
1710   int top_frame_index = -1;
1711   int frame_index = 0;
1712   for (; frame_index < frames.length(); frame_index++) {
1713     StackFrame* frame = frames[frame_index];
1714     if (frame->id() == debug->break_frame_id()) {
1715       top_frame_index = frame_index;
1716       break;
1717     }
1718     if (target.MatchActivation(
1719             frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
1720       // We are still above break_frame. It is not a target frame,
1721       // it is a problem.
1722       return "Debugger mark-up on stack is not found";
1723     }
1724   }
1725 
1726   if (top_frame_index == -1) {
1727     // We haven't found break frame, but no function is blocking us anyway.
1728     return target.GetNotFoundMessage();
1729   }
1730 
1731   bool target_frame_found = false;
1732   int bottom_js_frame_index = top_frame_index;
1733   bool non_droppable_frame_found = false;
1734   LiveEdit::FunctionPatchabilityStatus non_droppable_reason;
1735 
1736   for (; frame_index < frames.length(); frame_index++) {
1737     StackFrame* frame = frames[frame_index];
1738     if (frame->is_exit()) {
1739       non_droppable_frame_found = true;
1740       non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE;
1741       break;
1742     }
1743     if (frame->is_java_script()) {
1744       SharedFunctionInfo* shared =
1745           JavaScriptFrame::cast(frame)->function()->shared();
1746       if (shared->is_generator()) {
1747         non_droppable_frame_found = true;
1748         non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR;
1749         break;
1750       }
1751     }
1752     if (target.MatchActivation(
1753             frame, LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
1754       target_frame_found = true;
1755       bottom_js_frame_index = frame_index;
1756     }
1757   }
1758 
1759   if (non_droppable_frame_found) {
1760     // There is a C or generator frame on stack.  We can't drop C frames, and we
1761     // can't restart generators.  Check that there are no target frames below
1762     // them.
1763     for (; frame_index < frames.length(); frame_index++) {
1764       StackFrame* frame = frames[frame_index];
1765       if (frame->is_java_script()) {
1766         if (target.MatchActivation(frame, non_droppable_reason)) {
1767           // Fail.
1768           return NULL;
1769         }
1770       }
1771     }
1772   }
1773 
1774   // We cannot restart a frame that uses new.target.
1775   if (target.FrameUsesNewTarget(frames[bottom_js_frame_index])) return NULL;
1776 
1777   if (!do_drop) {
1778     // We are in check-only mode.
1779     return NULL;
1780   }
1781 
1782   if (!target_frame_found) {
1783     // Nothing to drop.
1784     return target.GetNotFoundMessage();
1785   }
1786 
1787   LiveEdit::FrameDropMode drop_mode = LiveEdit::FRAMES_UNTOUCHED;
1788   const char* error_message =
1789       DropFrames(frames, top_frame_index, bottom_js_frame_index, &drop_mode);
1790 
1791   if (error_message != NULL) {
1792     return error_message;
1793   }
1794 
1795   // Adjust break_frame after some frames has been dropped.
1796   StackFrame::Id new_id = StackFrame::NO_ID;
1797   for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) {
1798     if (frames[i]->type() == StackFrame::JAVA_SCRIPT) {
1799       new_id = frames[i]->id();
1800       break;
1801     }
1802   }
1803   debug->FramesHaveBeenDropped(new_id, drop_mode);
1804   return NULL;
1805 }
1806 
1807 
1808 // Fills result array with statuses of functions. Modifies the stack
1809 // removing all listed function if possible and if do_drop is true.
DropActivationsInActiveThread(Handle<JSArray> old_shared_array,Handle<JSArray> new_shared_array,Handle<JSArray> result,bool do_drop)1810 static const char* DropActivationsInActiveThread(
1811     Handle<JSArray> old_shared_array, Handle<JSArray> new_shared_array,
1812     Handle<JSArray> result, bool do_drop) {
1813   MultipleFunctionTarget target(old_shared_array, new_shared_array, result);
1814   Isolate* isolate = old_shared_array->GetIsolate();
1815 
1816   const char* message =
1817       DropActivationsInActiveThreadImpl(isolate, target, do_drop);
1818   if (message) {
1819     return message;
1820   }
1821 
1822   int array_len = GetArrayLength(old_shared_array);
1823 
1824   // Replace "blocked on active" with "replaced on active" status.
1825   for (int i = 0; i < array_len; i++) {
1826     Handle<Object> obj =
1827         Object::GetElement(isolate, result, i).ToHandleChecked();
1828     if (*obj == Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
1829       Handle<Object> replaced(
1830           Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK), isolate);
1831       SetElementSloppy(result, i, replaced);
1832     }
1833   }
1834   return NULL;
1835 }
1836 
1837 
FindActiveGenerators(Handle<FixedArray> shared_info_array,Handle<FixedArray> result,int len)1838 bool LiveEdit::FindActiveGenerators(Handle<FixedArray> shared_info_array,
1839                                     Handle<FixedArray> result,
1840                                     int len) {
1841   Isolate* isolate = shared_info_array->GetIsolate();
1842   bool found_suspended_activations = false;
1843 
1844   DCHECK_LE(len, result->length());
1845 
1846   FunctionPatchabilityStatus active = FUNCTION_BLOCKED_ACTIVE_GENERATOR;
1847 
1848   Heap* heap = isolate->heap();
1849   HeapIterator iterator(heap);
1850   HeapObject* obj = NULL;
1851   while ((obj = iterator.next()) != NULL) {
1852     if (!obj->IsJSGeneratorObject()) continue;
1853 
1854     JSGeneratorObject* gen = JSGeneratorObject::cast(obj);
1855     if (gen->is_closed()) continue;
1856 
1857     HandleScope scope(isolate);
1858 
1859     for (int i = 0; i < len; i++) {
1860       Handle<JSValue> jsvalue =
1861           Handle<JSValue>::cast(FixedArray::get(shared_info_array, i));
1862       Handle<SharedFunctionInfo> shared =
1863           UnwrapSharedFunctionInfoFromJSValue(jsvalue);
1864 
1865       if (gen->function()->shared() == *shared) {
1866         result->set(i, Smi::FromInt(active));
1867         found_suspended_activations = true;
1868       }
1869     }
1870   }
1871 
1872   return found_suspended_activations;
1873 }
1874 
1875 
1876 class InactiveThreadActivationsChecker : public ThreadVisitor {
1877  public:
InactiveThreadActivationsChecker(Handle<JSArray> old_shared_array,Handle<JSArray> result)1878   InactiveThreadActivationsChecker(Handle<JSArray> old_shared_array,
1879                                    Handle<JSArray> result)
1880       : old_shared_array_(old_shared_array),
1881         result_(result),
1882         has_blocked_functions_(false) {}
VisitThread(Isolate * isolate,ThreadLocalTop * top)1883   void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1884     for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1885       has_blocked_functions_ |=
1886           CheckActivation(old_shared_array_, result_, it.frame(),
1887                           LiveEdit::FUNCTION_BLOCKED_ON_OTHER_STACK);
1888     }
1889   }
HasBlockedFunctions()1890   bool HasBlockedFunctions() {
1891     return has_blocked_functions_;
1892   }
1893 
1894  private:
1895   Handle<JSArray> old_shared_array_;
1896   Handle<JSArray> result_;
1897   bool has_blocked_functions_;
1898 };
1899 
1900 
CheckAndDropActivations(Handle<JSArray> old_shared_array,Handle<JSArray> new_shared_array,bool do_drop)1901 Handle<JSArray> LiveEdit::CheckAndDropActivations(
1902     Handle<JSArray> old_shared_array, Handle<JSArray> new_shared_array,
1903     bool do_drop) {
1904   Isolate* isolate = old_shared_array->GetIsolate();
1905   int len = GetArrayLength(old_shared_array);
1906 
1907   DCHECK(old_shared_array->HasFastElements());
1908   Handle<FixedArray> old_shared_array_elements(
1909       FixedArray::cast(old_shared_array->elements()));
1910 
1911   Handle<JSArray> result = isolate->factory()->NewJSArray(len);
1912   Handle<FixedArray> result_elements =
1913       JSObject::EnsureWritableFastElements(result);
1914 
1915   // Fill the default values.
1916   for (int i = 0; i < len; i++) {
1917     FunctionPatchabilityStatus status = FUNCTION_AVAILABLE_FOR_PATCH;
1918     result_elements->set(i, Smi::FromInt(status));
1919   }
1920 
1921   // Scan the heap for active generators -- those that are either currently
1922   // running (as we wouldn't want to restart them, because we don't know where
1923   // to restart them from) or suspended.  Fail if any one corresponds to the set
1924   // of functions being edited.
1925   if (FindActiveGenerators(old_shared_array_elements, result_elements, len)) {
1926     return result;
1927   }
1928 
1929   // Check inactive threads. Fail if some functions are blocked there.
1930   InactiveThreadActivationsChecker inactive_threads_checker(old_shared_array,
1931                                                             result);
1932   isolate->thread_manager()->IterateArchivedThreads(
1933       &inactive_threads_checker);
1934   if (inactive_threads_checker.HasBlockedFunctions()) {
1935     return result;
1936   }
1937 
1938   // Try to drop activations from the current stack.
1939   const char* error_message = DropActivationsInActiveThread(
1940       old_shared_array, new_shared_array, result, do_drop);
1941   if (error_message != NULL) {
1942     // Add error message as an array extra element.
1943     Handle<String> str =
1944         isolate->factory()->NewStringFromAsciiChecked(error_message);
1945     SetElementSloppy(result, len, str);
1946   }
1947   return result;
1948 }
1949 
1950 
1951 // Describes a single callframe a target. Not finding this frame
1952 // means an error.
1953 class SingleFrameTarget {
1954  public:
SingleFrameTarget(JavaScriptFrame * frame)1955   explicit SingleFrameTarget(JavaScriptFrame* frame)
1956       : m_frame(frame),
1957         m_saved_status(LiveEdit::FUNCTION_AVAILABLE_FOR_PATCH) {}
1958 
MatchActivation(StackFrame * frame,LiveEdit::FunctionPatchabilityStatus status)1959   bool MatchActivation(StackFrame* frame,
1960       LiveEdit::FunctionPatchabilityStatus status) {
1961     if (frame->fp() == m_frame->fp()) {
1962       m_saved_status = status;
1963       return true;
1964     }
1965     return false;
1966   }
GetNotFoundMessage() const1967   const char* GetNotFoundMessage() const {
1968     return "Failed to found requested frame";
1969   }
saved_status()1970   LiveEdit::FunctionPatchabilityStatus saved_status() {
1971     return m_saved_status;
1972   }
set_status(LiveEdit::FunctionPatchabilityStatus status)1973   void set_status(LiveEdit::FunctionPatchabilityStatus status) {
1974     m_saved_status = status;
1975   }
1976 
FrameUsesNewTarget(StackFrame * frame)1977   bool FrameUsesNewTarget(StackFrame* frame) {
1978     if (!frame->is_java_script()) return false;
1979     JavaScriptFrame* jsframe = JavaScriptFrame::cast(frame);
1980     Handle<SharedFunctionInfo> shared(jsframe->function()->shared());
1981     return shared->scope_info()->HasNewTarget();
1982   }
1983 
1984  private:
1985   JavaScriptFrame* m_frame;
1986   LiveEdit::FunctionPatchabilityStatus m_saved_status;
1987 };
1988 
1989 
1990 // Finds a drops required frame and all frames above.
1991 // Returns error message or NULL.
RestartFrame(JavaScriptFrame * frame)1992 const char* LiveEdit::RestartFrame(JavaScriptFrame* frame) {
1993   SingleFrameTarget target(frame);
1994 
1995   const char* result =
1996       DropActivationsInActiveThreadImpl(frame->isolate(), target, true);
1997   if (result != NULL) {
1998     return result;
1999   }
2000   if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE) {
2001     return "Function is blocked under native code";
2002   }
2003   if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR) {
2004     return "Function is blocked under a generator activation";
2005   }
2006   return NULL;
2007 }
2008 
2009 
LiveEditFunctionTracker(Isolate * isolate,FunctionLiteral * fun)2010 LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
2011                                                  FunctionLiteral* fun)
2012     : isolate_(isolate) {
2013   if (isolate_->active_function_info_listener() != NULL) {
2014     isolate_->active_function_info_listener()->FunctionStarted(fun);
2015   }
2016 }
2017 
2018 
~LiveEditFunctionTracker()2019 LiveEditFunctionTracker::~LiveEditFunctionTracker() {
2020   if (isolate_->active_function_info_listener() != NULL) {
2021     isolate_->active_function_info_listener()->FunctionDone();
2022   }
2023 }
2024 
2025 
RecordFunctionInfo(Handle<SharedFunctionInfo> info,FunctionLiteral * lit,Zone * zone)2026 void LiveEditFunctionTracker::RecordFunctionInfo(
2027     Handle<SharedFunctionInfo> info, FunctionLiteral* lit,
2028     Zone* zone) {
2029   if (isolate_->active_function_info_listener() != NULL) {
2030     isolate_->active_function_info_listener()->FunctionInfo(info, lit->scope(),
2031                                                             zone);
2032   }
2033 }
2034 
2035 
RecordRootFunctionInfo(Handle<Code> code)2036 void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
2037   isolate_->active_function_info_listener()->FunctionCode(code);
2038 }
2039 
2040 
IsActive(Isolate * isolate)2041 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
2042   return isolate->active_function_info_listener() != NULL;
2043 }
2044 
2045 }  // namespace internal
2046 }  // namespace v8
2047