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