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