v8  3.11.10(node0.8.26)
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  CompilationInfo 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 // 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() {
645  Handle<JSArray> array = FACTORY->NewJSArray(S::kSize_);
646  return S(array);
647  }
648  static S cast(Object* object) {
649  JSArray* array = JSArray::cast(object);
650  Handle<JSArray> array_handle(array);
651  return S(array_handle);
652  }
653  explicit JSArrayBasedStruct(Handle<JSArray> array) : array_(array) {
654  }
655  Handle<JSArray> GetJSArray() {
656  return array_;
657  }
658 
659  protected:
660  void SetField(int field_position, Handle<Object> value) {
661  SetElementNonStrict(array_, field_position, value);
662  }
663  void SetSmiValueField(int field_position, int value) {
664  SetElementNonStrict(array_,
665  field_position,
666  Handle<Smi>(Smi::FromInt(value)));
667  }
668  Object* GetField(int field_position) {
669  return array_->GetElementNoExceptionThrown(field_position);
670  }
671  int GetSmiValueField(int field_position) {
672  Object* res = GetField(field_position);
673  return Smi::cast(res)->value();
674  }
675 
676  private:
677  Handle<JSArray> array_;
678 };
679 
680 
681 // Represents some function compilation details. This structure will be used
682 // from JavaScript. It contains Code object, which is kept wrapped
683 // into a BlindReference for sanitizing reasons.
684 class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
685  public:
686  explicit FunctionInfoWrapper(Handle<JSArray> array)
687  : JSArrayBasedStruct<FunctionInfoWrapper>(array) {
688  }
689  void SetInitialProperties(Handle<String> name, int start_position,
690  int end_position, int param_num, int parent_index) {
691  HandleScope scope;
692  this->SetField(kFunctionNameOffset_, name);
693  this->SetSmiValueField(kStartPositionOffset_, start_position);
694  this->SetSmiValueField(kEndPositionOffset_, end_position);
695  this->SetSmiValueField(kParamNumOffset_, param_num);
696  this->SetSmiValueField(kParentIndexOffset_, parent_index);
697  }
698  void SetFunctionCode(Handle<Code> function_code,
699  Handle<Object> code_scope_info) {
700  Handle<JSValue> code_wrapper = WrapInJSValue(function_code);
701  this->SetField(kCodeOffset_, code_wrapper);
702 
703  Handle<JSValue> scope_wrapper = WrapInJSValue(code_scope_info);
704  this->SetField(kCodeScopeInfoOffset_, scope_wrapper);
705  }
706  void SetOuterScopeInfo(Handle<Object> scope_info_array) {
707  this->SetField(kOuterScopeInfoOffset_, scope_info_array);
708  }
709  void SetSharedFunctionInfo(Handle<SharedFunctionInfo> info) {
710  Handle<JSValue> info_holder = WrapInJSValue(info);
711  this->SetField(kSharedFunctionInfoOffset_, info_holder);
712  }
713  int GetParentIndex() {
714  return this->GetSmiValueField(kParentIndexOffset_);
715  }
716  Handle<Code> GetFunctionCode() {
717  Handle<Object> raw_result = UnwrapJSValue(Handle<JSValue>(
718  JSValue::cast(this->GetField(kCodeOffset_))));
719  return Handle<Code>::cast(raw_result);
720  }
721  Handle<Object> GetCodeScopeInfo() {
722  Handle<Object> raw_result = UnwrapJSValue(Handle<JSValue>(
723  JSValue::cast(this->GetField(kCodeScopeInfoOffset_))));
724  return raw_result;
725  }
726  int GetStartPosition() {
727  return this->GetSmiValueField(kStartPositionOffset_);
728  }
729  int GetEndPosition() {
730  return this->GetSmiValueField(kEndPositionOffset_);
731  }
732 
733  private:
734  static const int kFunctionNameOffset_ = 0;
735  static const int kStartPositionOffset_ = 1;
736  static const int kEndPositionOffset_ = 2;
737  static const int kParamNumOffset_ = 3;
738  static const int kCodeOffset_ = 4;
739  static const int kCodeScopeInfoOffset_ = 5;
740  static const int kOuterScopeInfoOffset_ = 6;
741  static const int kParentIndexOffset_ = 7;
742  static const int kSharedFunctionInfoOffset_ = 8;
743  static const int kSize_ = 9;
744 
745  friend class JSArrayBasedStruct<FunctionInfoWrapper>;
746 };
747 
748 
749 // Wraps SharedFunctionInfo along with some of its fields for passing it
750 // back to JavaScript. SharedFunctionInfo object itself is additionally
751 // wrapped into BlindReference for sanitizing reasons.
752 class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> {
753  public:
754  static bool IsInstance(Handle<JSArray> array) {
755  return array->length() == Smi::FromInt(kSize_) &&
756  array->GetElementNoExceptionThrown(kSharedInfoOffset_)->IsJSValue();
757  }
758 
759  explicit SharedInfoWrapper(Handle<JSArray> array)
760  : JSArrayBasedStruct<SharedInfoWrapper>(array) {
761  }
762 
763  void SetProperties(Handle<String> name, int start_position, int end_position,
764  Handle<SharedFunctionInfo> info) {
765  HandleScope scope;
766  this->SetField(kFunctionNameOffset_, name);
767  Handle<JSValue> info_holder = WrapInJSValue(info);
768  this->SetField(kSharedInfoOffset_, info_holder);
769  this->SetSmiValueField(kStartPositionOffset_, start_position);
770  this->SetSmiValueField(kEndPositionOffset_, end_position);
771  }
772  Handle<SharedFunctionInfo> GetInfo() {
773  Object* element = this->GetField(kSharedInfoOffset_);
774  Handle<JSValue> value_wrapper(JSValue::cast(element));
775  Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
776  return Handle<SharedFunctionInfo>::cast(raw_result);
777  }
778 
779  private:
780  static const int kFunctionNameOffset_ = 0;
781  static const int kStartPositionOffset_ = 1;
782  static const int kEndPositionOffset_ = 2;
783  static const int kSharedInfoOffset_ = 3;
784  static const int kSize_ = 4;
785 
786  friend class JSArrayBasedStruct<SharedInfoWrapper>;
787 };
788 
789 
790 class FunctionInfoListener {
791  public:
792  FunctionInfoListener() {
793  current_parent_index_ = -1;
794  len_ = 0;
795  result_ = FACTORY->NewJSArray(10);
796  }
797 
798  void FunctionStarted(FunctionLiteral* fun) {
799  HandleScope scope;
800  FunctionInfoWrapper info = FunctionInfoWrapper::Create();
801  info.SetInitialProperties(fun->name(), fun->start_position(),
802  fun->end_position(), fun->parameter_count(),
803  current_parent_index_);
804  current_parent_index_ = len_;
805  SetElementNonStrict(result_, len_, info.GetJSArray());
806  len_++;
807  }
808 
809  void FunctionDone() {
810  HandleScope scope;
811  FunctionInfoWrapper info =
812  FunctionInfoWrapper::cast(
813  result_->GetElementNoExceptionThrown(current_parent_index_));
814  current_parent_index_ = info.GetParentIndex();
815  }
816 
817  // Saves only function code, because for a script function we
818  // may never create a SharedFunctionInfo object.
819  void FunctionCode(Handle<Code> function_code) {
820  FunctionInfoWrapper info =
821  FunctionInfoWrapper::cast(
822  result_->GetElementNoExceptionThrown(current_parent_index_));
823  info.SetFunctionCode(function_code, Handle<Object>(HEAP->null_value()));
824  }
825 
826  // Saves full information about a function: its code, its scope info
827  // and a SharedFunctionInfo object.
828  void FunctionInfo(Handle<SharedFunctionInfo> shared, Scope* scope,
829  Zone* zone) {
830  if (!shared->IsSharedFunctionInfo()) {
831  return;
832  }
833  FunctionInfoWrapper info =
834  FunctionInfoWrapper::cast(
835  result_->GetElementNoExceptionThrown(current_parent_index_));
836  info.SetFunctionCode(Handle<Code>(shared->code()),
837  Handle<Object>(shared->scope_info()));
838  info.SetSharedFunctionInfo(shared);
839 
840  Handle<Object> scope_info_list(SerializeFunctionScope(scope, zone));
841  info.SetOuterScopeInfo(scope_info_list);
842  }
843 
844  Handle<JSArray> GetResult() { return result_; }
845 
846  private:
847  Object* SerializeFunctionScope(Scope* scope, Zone* zone) {
848  HandleScope handle_scope;
849 
850  Handle<JSArray> scope_info_list = FACTORY->NewJSArray(10);
851  int scope_info_length = 0;
852 
853  // Saves some description of scope. It stores name and indexes of
854  // variables in the whole scope chain. Null-named slots delimit
855  // scopes of this chain.
856  Scope* outer_scope = scope->outer_scope();
857  if (outer_scope == NULL) {
858  return HEAP->undefined_value();
859  }
860  do {
861  ZoneList<Variable*> stack_list(outer_scope->StackLocalCount(), zone);
862  ZoneList<Variable*> context_list(outer_scope->ContextLocalCount(), zone);
863  outer_scope->CollectStackAndContextLocals(&stack_list, &context_list);
864  context_list.Sort(&Variable::CompareIndex);
865 
866  for (int i = 0; i < context_list.length(); i++) {
867  SetElementNonStrict(scope_info_list,
868  scope_info_length,
869  context_list[i]->name());
870  scope_info_length++;
871  SetElementNonStrict(
872  scope_info_list,
873  scope_info_length,
874  Handle<Smi>(Smi::FromInt(context_list[i]->index())));
875  scope_info_length++;
876  }
877  SetElementNonStrict(scope_info_list,
878  scope_info_length,
879  Handle<Object>(HEAP->null_value()));
880  scope_info_length++;
881 
882  outer_scope = outer_scope->outer_scope();
883  } while (outer_scope != NULL);
884 
885  return *scope_info_list;
886  }
887 
888  Handle<JSArray> result_;
889  int len_;
890  int current_parent_index_;
891 };
892 
893 
894 JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script,
895  Handle<String> source) {
896  Isolate* isolate = Isolate::Current();
897  ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
898 
899  FunctionInfoListener listener;
900  Handle<Object> original_source = Handle<Object>(script->source());
901  script->set_source(*source);
902  isolate->set_active_function_info_listener(&listener);
903  CompileScriptForTracker(isolate, script);
904  isolate->set_active_function_info_listener(NULL);
905  script->set_source(*original_source);
906 
907  return *(listener.GetResult());
908 }
909 
910 
911 void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> array) {
912  HandleScope scope;
913  int len = Smi::cast(array->length())->value();
914  for (int i = 0; i < len; i++) {
915  Handle<SharedFunctionInfo> info(
916  SharedFunctionInfo::cast(array->GetElementNoExceptionThrown(i)));
917  SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create();
918  Handle<String> name_handle(String::cast(info->name()));
919  info_wrapper.SetProperties(name_handle, info->start_position(),
920  info->end_position(), info);
921  SetElementNonStrict(array, i, info_wrapper.GetJSArray());
922  }
923 }
924 
925 
926 // Visitor that collects all references to a particular code object,
927 // including "CODE_TARGET" references in other code objects.
928 // It works in context of ZoneScope.
929 class ReferenceCollectorVisitor : public ObjectVisitor {
930  public:
931  ReferenceCollectorVisitor(Code* original, Zone* zone)
932  : original_(original),
933  rvalues_(10, zone),
934  reloc_infos_(10, zone),
935  code_entries_(10, zone),
936  zone_(zone) {
937  }
938 
939  virtual void VisitPointers(Object** start, Object** end) {
940  for (Object** p = start; p < end; p++) {
941  if (*p == original_) {
942  rvalues_.Add(p, zone_);
943  }
944  }
945  }
946 
947  virtual void VisitCodeEntry(Address entry) {
948  if (Code::GetObjectFromEntryAddress(entry) == original_) {
949  code_entries_.Add(entry, zone_);
950  }
951  }
952 
953  virtual void VisitCodeTarget(RelocInfo* rinfo) {
954  if (RelocInfo::IsCodeTarget(rinfo->rmode()) &&
955  Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) {
956  reloc_infos_.Add(*rinfo, zone_);
957  }
958  }
959 
960  virtual void VisitDebugTarget(RelocInfo* rinfo) {
961  VisitCodeTarget(rinfo);
962  }
963 
964  // Post-visiting method that iterates over all collected references and
965  // modifies them.
966  void Replace(Code* substitution) {
967  for (int i = 0; i < rvalues_.length(); i++) {
968  *(rvalues_[i]) = substitution;
969  }
970  Address substitution_entry = substitution->instruction_start();
971  for (int i = 0; i < reloc_infos_.length(); i++) {
972  reloc_infos_[i].set_target_address(substitution_entry);
973  }
974  for (int i = 0; i < code_entries_.length(); i++) {
975  Address entry = code_entries_[i];
976  Memory::Address_at(entry) = substitution_entry;
977  }
978  }
979 
980  private:
981  Code* original_;
982  ZoneList<Object**> rvalues_;
983  ZoneList<RelocInfo> reloc_infos_;
984  ZoneList<Address> code_entries_;
985  Zone* zone_;
986 };
987 
988 
989 // Finds all references to original and replaces them with substitution.
990 static void ReplaceCodeObject(Code* original, Code* substitution) {
991  ASSERT(!HEAP->InNewSpace(substitution));
992 
993  HeapIterator iterator;
994  AssertNoAllocation no_allocations_please;
995 
996  // A zone scope for ReferenceCollectorVisitor.
997  ZoneScope scope(Isolate::Current(), DELETE_ON_EXIT);
998 
999  ReferenceCollectorVisitor visitor(original, Isolate::Current()->zone());
1000 
1001  // Iterate over all roots. Stack frames may have pointer into original code,
1002  // so temporary replace the pointers with offset numbers
1003  // in prologue/epilogue.
1004  {
1005  HEAP->IterateStrongRoots(&visitor, VISIT_ALL);
1006  }
1007 
1008  // Now iterate over all pointers of all objects, including code_target
1009  // implicit pointers.
1010  for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1011  obj->Iterate(&visitor);
1012  }
1013 
1014  visitor.Replace(substitution);
1015 }
1016 
1017 
1018 // Check whether the code is natural function code (not a lazy-compile stub
1019 // code).
1020 static bool IsJSFunctionCode(Code* code) {
1021  return code->kind() == Code::FUNCTION;
1022 }
1023 
1024 
1025 // Returns true if an instance of candidate were inlined into function's code.
1026 static bool IsInlined(JSFunction* function, SharedFunctionInfo* candidate) {
1027  AssertNoAllocation no_gc;
1028 
1029  if (function->code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
1030 
1031  DeoptimizationInputData* data =
1032  DeoptimizationInputData::cast(function->code()->deoptimization_data());
1033 
1034  if (data == HEAP->empty_fixed_array()) return false;
1035 
1036  FixedArray* literals = data->LiteralArray();
1037 
1038  int inlined_count = data->InlinedFunctionCount()->value();
1039  for (int i = 0; i < inlined_count; ++i) {
1040  JSFunction* inlined = JSFunction::cast(literals->get(i));
1041  if (inlined->shared() == candidate) return true;
1042  }
1043 
1044  return false;
1045 }
1046 
1047 
1048 class DependentFunctionsDeoptimizingVisitor : public OptimizedFunctionVisitor {
1049  public:
1050  explicit DependentFunctionsDeoptimizingVisitor(
1051  SharedFunctionInfo* function_info)
1052  : function_info_(function_info) {}
1053 
1054  virtual void EnterContext(Context* context) {
1055  }
1056 
1057  virtual void VisitFunction(JSFunction* function) {
1058  if (function->shared() == function_info_ ||
1059  IsInlined(function, function_info_)) {
1061  }
1062  }
1063 
1064  virtual void LeaveContext(Context* context) {
1065  }
1066 
1067  private:
1068  SharedFunctionInfo* function_info_;
1069 };
1070 
1071 
1072 static void DeoptimizeDependentFunctions(SharedFunctionInfo* function_info) {
1073  AssertNoAllocation no_allocation;
1074 
1075  DependentFunctionsDeoptimizingVisitor visitor(function_info);
1077 }
1078 
1079 
1080 MaybeObject* LiveEdit::ReplaceFunctionCode(
1081  Handle<JSArray> new_compile_info_array,
1082  Handle<JSArray> shared_info_array) {
1083  HandleScope scope;
1084 
1085  if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
1086  return Isolate::Current()->ThrowIllegalOperation();
1087  }
1088 
1089  FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
1090  SharedInfoWrapper shared_info_wrapper(shared_info_array);
1091 
1092  Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
1093 
1094  HEAP->EnsureHeapIsIterable();
1095 
1096  if (IsJSFunctionCode(shared_info->code())) {
1097  Handle<Code> code = compile_info_wrapper.GetFunctionCode();
1098  ReplaceCodeObject(shared_info->code(), *code);
1099  Handle<Object> code_scope_info = compile_info_wrapper.GetCodeScopeInfo();
1100  if (code_scope_info->IsFixedArray()) {
1101  shared_info->set_scope_info(ScopeInfo::cast(*code_scope_info));
1102  }
1103  }
1104 
1105  if (shared_info->debug_info()->IsDebugInfo()) {
1106  Handle<DebugInfo> debug_info(DebugInfo::cast(shared_info->debug_info()));
1107  Handle<Code> new_original_code =
1108  FACTORY->CopyCode(compile_info_wrapper.GetFunctionCode());
1109  debug_info->set_original_code(*new_original_code);
1110  }
1111 
1112  int start_position = compile_info_wrapper.GetStartPosition();
1113  int end_position = compile_info_wrapper.GetEndPosition();
1114  shared_info->set_start_position(start_position);
1115  shared_info->set_end_position(end_position);
1116 
1117  shared_info->set_construct_stub(
1118  Isolate::Current()->builtins()->builtin(
1119  Builtins::kJSConstructStubGeneric));
1120 
1121  DeoptimizeDependentFunctions(*shared_info);
1122  Isolate::Current()->compilation_cache()->Remove(shared_info);
1123 
1124  return HEAP->undefined_value();
1125 }
1126 
1127 
1128 MaybeObject* LiveEdit::FunctionSourceUpdated(
1129  Handle<JSArray> shared_info_array) {
1130  HandleScope scope;
1131 
1132  if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
1133  return Isolate::Current()->ThrowIllegalOperation();
1134  }
1135 
1136  SharedInfoWrapper shared_info_wrapper(shared_info_array);
1137  Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
1138 
1139  DeoptimizeDependentFunctions(*shared_info);
1140  Isolate::Current()->compilation_cache()->Remove(shared_info);
1141 
1142  return HEAP->undefined_value();
1143 }
1144 
1145 
1146 void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
1147  Handle<Object> script_handle) {
1148  Handle<SharedFunctionInfo> shared_info =
1149  Handle<SharedFunctionInfo>::cast(UnwrapJSValue(function_wrapper));
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 = Smi::cast(position_change_array->length())->value();
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  int chunk_start = Smi::cast(element)->value();
1173  if (original_position < chunk_start) {
1174  break;
1175  }
1176  element = position_change_array->GetElementNoExceptionThrown(i + 1);
1177  int chunk_end = Smi::cast(element)->value();
1178  // Position mustn't be inside a chunk.
1179  ASSERT(original_position >= chunk_end);
1180  element = position_change_array->GetElementNoExceptionThrown(i + 2);
1181  int chunk_changed_end = Smi::cast(element)->value();
1182  position_diff = chunk_changed_end - chunk_end;
1183  }
1184 
1185  return original_position + position_diff;
1186 }
1187 
1188 
1189 // Auto-growing buffer for writing relocation info code section. This buffer
1190 // is a simplified version of buffer from Assembler. Unlike Assembler, this
1191 // class is platform-independent and it works without dealing with instructions.
1192 // As specified by RelocInfo format, the buffer is filled in reversed order:
1193 // from upper to lower addresses.
1194 // It uses NewArray/DeleteArray for memory management.
1195 class RelocInfoBuffer {
1196  public:
1197  RelocInfoBuffer(int buffer_initial_capicity, byte* pc) {
1198  buffer_size_ = buffer_initial_capicity + kBufferGap;
1199  buffer_ = NewArray<byte>(buffer_size_);
1200 
1201  reloc_info_writer_.Reposition(buffer_ + buffer_size_, pc);
1202  }
1203  ~RelocInfoBuffer() {
1205  }
1206 
1207  // As specified by RelocInfo format, the buffer is filled in reversed order:
1208  // from upper to lower addresses.
1209  void Write(const RelocInfo* rinfo) {
1210  if (buffer_ + kBufferGap >= reloc_info_writer_.pos()) {
1211  Grow();
1212  }
1213  reloc_info_writer_.Write(rinfo);
1214  }
1215 
1216  Vector<byte> GetResult() {
1217  // Return the bytes from pos up to end of buffer.
1218  int result_size =
1219  static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer_.pos());
1220  return Vector<byte>(reloc_info_writer_.pos(), result_size);
1221  }
1222 
1223  private:
1224  void Grow() {
1225  // Compute new buffer size.
1226  int new_buffer_size;
1227  if (buffer_size_ < 2 * KB) {
1228  new_buffer_size = 4 * KB;
1229  } else {
1230  new_buffer_size = 2 * buffer_size_;
1231  }
1232  // Some internal data structures overflow for very large buffers,
1233  // they must ensure that kMaximalBufferSize is not too large.
1234  if (new_buffer_size > kMaximalBufferSize) {
1235  V8::FatalProcessOutOfMemory("RelocInfoBuffer::GrowBuffer");
1236  }
1237 
1238  // Set up new buffer.
1239  byte* new_buffer = NewArray<byte>(new_buffer_size);
1240 
1241  // Copy the data.
1242  int curently_used_size =
1243  static_cast<int>(buffer_ + buffer_size_ - reloc_info_writer_.pos());
1244  memmove(new_buffer + new_buffer_size - curently_used_size,
1245  reloc_info_writer_.pos(), curently_used_size);
1246 
1247  reloc_info_writer_.Reposition(
1248  new_buffer + new_buffer_size - curently_used_size,
1249  reloc_info_writer_.last_pc());
1250 
1252  buffer_ = new_buffer;
1253  buffer_size_ = new_buffer_size;
1254  }
1255 
1256  RelocInfoWriter reloc_info_writer_;
1257  byte* buffer_;
1258  int buffer_size_;
1259 
1260  static const int kBufferGap = RelocInfoWriter::kMaxSize;
1261  static const int kMaximalBufferSize = 512*MB;
1262 };
1263 
1264 // Patch positions in code (changes relocation info section) and possibly
1265 // returns new instance of code.
1266 static Handle<Code> PatchPositionsInCode(
1267  Handle<Code> code,
1268  Handle<JSArray> position_change_array) {
1269 
1270  RelocInfoBuffer buffer_writer(code->relocation_size(),
1271  code->instruction_start());
1272 
1273  {
1274  AssertNoAllocation no_allocations_please;
1275  for (RelocIterator it(*code); !it.done(); it.next()) {
1276  RelocInfo* rinfo = it.rinfo();
1277  if (RelocInfo::IsPosition(rinfo->rmode())) {
1278  int position = static_cast<int>(rinfo->data());
1279  int new_position = TranslatePosition(position,
1280  position_change_array);
1281  if (position != new_position) {
1282  RelocInfo info_copy(rinfo->pc(), rinfo->rmode(), new_position, NULL);
1283  buffer_writer.Write(&info_copy);
1284  continue;
1285  }
1286  }
1287  buffer_writer.Write(it.rinfo());
1288  }
1289  }
1290 
1291  Vector<byte> buffer = buffer_writer.GetResult();
1292 
1293  if (buffer.length() == code->relocation_size()) {
1294  // Simply patch relocation area of code.
1295  memcpy(code->relocation_start(), buffer.start(), buffer.length());
1296  return code;
1297  } else {
1298  // Relocation info section now has different size. We cannot simply
1299  // rewrite it inside code object. Instead we have to create a new
1300  // code object.
1301  Handle<Code> result(FACTORY->CopyCode(code, buffer));
1302  return result;
1303  }
1304 }
1305 
1306 
1307 MaybeObject* LiveEdit::PatchFunctionPositions(
1308  Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array) {
1309 
1310  if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
1311  return Isolate::Current()->ThrowIllegalOperation();
1312  }
1313 
1314  SharedInfoWrapper shared_info_wrapper(shared_info_array);
1315  Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo();
1316 
1317  int old_function_start = info->start_position();
1318  int new_function_start = TranslatePosition(old_function_start,
1319  position_change_array);
1320  int new_function_end = TranslatePosition(info->end_position(),
1321  position_change_array);
1322  int new_function_token_pos =
1323  TranslatePosition(info->function_token_position(), position_change_array);
1324 
1325  info->set_start_position(new_function_start);
1326  info->set_end_position(new_function_end);
1327  info->set_function_token_position(new_function_token_pos);
1328 
1329  HEAP->EnsureHeapIsIterable();
1330 
1331  if (IsJSFunctionCode(info->code())) {
1332  // Patch relocation info section of the code.
1333  Handle<Code> patched_code = PatchPositionsInCode(Handle<Code>(info->code()),
1334  position_change_array);
1335  if (*patched_code != info->code()) {
1336  // Replace all references to the code across the heap. In particular,
1337  // some stubs may refer to this code and this code may be being executed
1338  // on stack (it is safe to substitute the code object on stack, because
1339  // we only change the structure of rinfo and leave instructions
1340  // untouched).
1341  ReplaceCodeObject(info->code(), *patched_code);
1342  }
1343  }
1344 
1345  return HEAP->undefined_value();
1346 }
1347 
1348 
1349 static Handle<Script> CreateScriptCopy(Handle<Script> original) {
1350  Handle<String> original_source(String::cast(original->source()));
1351 
1352  Handle<Script> copy = FACTORY->NewScript(original_source);
1353 
1354  copy->set_name(original->name());
1355  copy->set_line_offset(original->line_offset());
1356  copy->set_column_offset(original->column_offset());
1357  copy->set_data(original->data());
1358  copy->set_type(original->type());
1359  copy->set_context_data(original->context_data());
1360  copy->set_compilation_type(original->compilation_type());
1361  copy->set_eval_from_shared(original->eval_from_shared());
1362  copy->set_eval_from_instructions_offset(
1363  original->eval_from_instructions_offset());
1364 
1365  return copy;
1366 }
1367 
1368 
1369 Object* LiveEdit::ChangeScriptSource(Handle<Script> original_script,
1370  Handle<String> new_source,
1371  Handle<Object> old_script_name) {
1372  Handle<Object> old_script_object;
1373  if (old_script_name->IsString()) {
1374  Handle<Script> old_script = CreateScriptCopy(original_script);
1375  old_script->set_name(String::cast(*old_script_name));
1376  old_script_object = old_script;
1377  Isolate::Current()->debugger()->OnAfterCompile(
1378  old_script, Debugger::SEND_WHEN_DEBUGGING);
1379  } else {
1380  old_script_object = Handle<Object>(HEAP->null_value());
1381  }
1382 
1383  original_script->set_source(*new_source);
1384 
1385  // Drop line ends so that they will be recalculated.
1386  original_script->set_line_ends(HEAP->undefined_value());
1387 
1388  return *old_script_object;
1389 }
1390 
1391 
1392 
1393 void LiveEdit::ReplaceRefToNestedFunction(
1394  Handle<JSValue> parent_function_wrapper,
1395  Handle<JSValue> orig_function_wrapper,
1396  Handle<JSValue> subst_function_wrapper) {
1397 
1398  Handle<SharedFunctionInfo> parent_shared =
1399  Handle<SharedFunctionInfo>::cast(UnwrapJSValue(parent_function_wrapper));
1400  Handle<SharedFunctionInfo> orig_shared =
1401  Handle<SharedFunctionInfo>::cast(UnwrapJSValue(orig_function_wrapper));
1402  Handle<SharedFunctionInfo> subst_shared =
1403  Handle<SharedFunctionInfo>::cast(UnwrapJSValue(subst_function_wrapper));
1404 
1405  for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) {
1406  if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) {
1407  if (it.rinfo()->target_object() == *orig_shared) {
1408  it.rinfo()->set_target_object(*subst_shared);
1409  }
1410  }
1411  }
1412 }
1413 
1414 
1415 // Check an activation against list of functions. If there is a function
1416 // that matches, its status in result array is changed to status argument value.
1417 static bool CheckActivation(Handle<JSArray> shared_info_array,
1418  Handle<JSArray> result,
1419  StackFrame* frame,
1420  LiveEdit::FunctionPatchabilityStatus status) {
1421  if (!frame->is_java_script()) return false;
1422 
1423  Handle<JSFunction> function(
1424  JSFunction::cast(JavaScriptFrame::cast(frame)->function()));
1425 
1426  int len = Smi::cast(shared_info_array->length())->value();
1427  for (int i = 0; i < len; i++) {
1428  JSValue* wrapper =
1429  JSValue::cast(shared_info_array->GetElementNoExceptionThrown(i));
1430  Handle<SharedFunctionInfo> shared(
1431  SharedFunctionInfo::cast(wrapper->value()));
1432 
1433  if (function->shared() == *shared || IsInlined(*function, *shared)) {
1434  SetElementNonStrict(result, i, Handle<Smi>(Smi::FromInt(status)));
1435  return true;
1436  }
1437  }
1438  return false;
1439 }
1440 
1441 
1442 // Iterates over handler chain and removes all elements that are inside
1443 // frames being dropped.
1444 static bool FixTryCatchHandler(StackFrame* top_frame,
1445  StackFrame* bottom_frame) {
1446  Address* pointer_address =
1447  &Memory::Address_at(Isolate::Current()->get_address_from_id(
1448  Isolate::kHandlerAddress));
1449 
1450  while (*pointer_address < top_frame->sp()) {
1451  pointer_address = &Memory::Address_at(*pointer_address);
1452  }
1453  Address* above_frame_address = pointer_address;
1454  while (*pointer_address < bottom_frame->fp()) {
1455  pointer_address = &Memory::Address_at(*pointer_address);
1456  }
1457  bool change = *above_frame_address != *pointer_address;
1458  *above_frame_address = *pointer_address;
1459  return change;
1460 }
1461 
1462 
1463 // Removes specified range of frames from stack. There may be 1 or more
1464 // frames in range. Anyway the bottom frame is restarted rather than dropped,
1465 // and therefore has to be a JavaScript frame.
1466 // Returns error message or NULL.
1467 static const char* DropFrames(Vector<StackFrame*> frames,
1468  int top_frame_index,
1469  int bottom_js_frame_index,
1470  Debug::FrameDropMode* mode,
1471  Object*** restarter_frame_function_pointer) {
1472  if (!Debug::kFrameDropperSupported) {
1473  return "Stack manipulations are not supported in this architecture.";
1474  }
1475 
1476  StackFrame* pre_top_frame = frames[top_frame_index - 1];
1477  StackFrame* top_frame = frames[top_frame_index];
1478  StackFrame* bottom_js_frame = frames[bottom_js_frame_index];
1479 
1480  ASSERT(bottom_js_frame->is_java_script());
1481 
1482  // Check the nature of the top frame.
1483  Isolate* isolate = Isolate::Current();
1484  Code* pre_top_frame_code = pre_top_frame->LookupCode();
1485  bool frame_has_padding;
1486  if (pre_top_frame_code->is_inline_cache_stub() &&
1487  pre_top_frame_code->ic_state() == DEBUG_BREAK) {
1488  // OK, we can drop inline cache calls.
1489  *mode = Debug::FRAME_DROPPED_IN_IC_CALL;
1490  frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
1491  } else if (pre_top_frame_code ==
1492  isolate->debug()->debug_break_slot()) {
1493  // OK, we can drop debug break slot.
1494  *mode = Debug::FRAME_DROPPED_IN_DEBUG_SLOT_CALL;
1495  frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
1496  } else if (pre_top_frame_code ==
1497  isolate->builtins()->builtin(
1498  Builtins::kFrameDropper_LiveEdit)) {
1499  // OK, we can drop our own code.
1500  *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
1501  frame_has_padding = false;
1502  } else if (pre_top_frame_code ==
1503  isolate->builtins()->builtin(Builtins::kReturn_DebugBreak)) {
1504  *mode = Debug::FRAME_DROPPED_IN_RETURN_CALL;
1505  frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
1506  } else if (pre_top_frame_code->kind() == Code::STUB &&
1507  pre_top_frame_code->major_key() == CodeStub::CEntry) {
1508  // Entry from our unit tests on 'debugger' statement.
1509  // It's fine, we support this case.
1510  *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
1511  // We don't have a padding from 'debugger' statement call.
1512  // Here the stub is CEntry, it's not debug-only and can't be padded.
1513  // If anyone would complain, a proxy padded stub could be added.
1514  frame_has_padding = false;
1515  } else {
1516  return "Unknown structure of stack above changing function";
1517  }
1518 
1519  Address unused_stack_top = top_frame->sp();
1520  Address unused_stack_bottom = bottom_js_frame->fp()
1521  - Debug::kFrameDropperFrameSize * kPointerSize // Size of the new frame.
1522  + kPointerSize; // Bigger address end is exclusive.
1523 
1524  Address* top_frame_pc_address = top_frame->pc_address();
1525 
1526  // top_frame may be damaged below this point. Do not used it.
1527  ASSERT(!(top_frame = NULL));
1528 
1529  if (unused_stack_top > unused_stack_bottom) {
1530  if (frame_has_padding) {
1531  int shortage_bytes =
1532  static_cast<int>(unused_stack_top - unused_stack_bottom);
1533 
1534  Address padding_start = pre_top_frame->fp() -
1535  Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize;
1536 
1537  Address padding_pointer = padding_start;
1538  Smi* padding_object =
1539  Smi::FromInt(Debug::FramePaddingLayout::kPaddingValue);
1540  while (Memory::Object_at(padding_pointer) == padding_object) {
1541  padding_pointer -= kPointerSize;
1542  }
1543  int padding_counter =
1544  Smi::cast(Memory::Object_at(padding_pointer))->value();
1545  if (padding_counter * kPointerSize < shortage_bytes) {
1546  return "Not enough space for frame dropper frame "
1547  "(even with padding frame)";
1548  }
1549  Memory::Object_at(padding_pointer) =
1550  Smi::FromInt(padding_counter - shortage_bytes / kPointerSize);
1551 
1552  StackFrame* pre_pre_frame = frames[top_frame_index - 2];
1553 
1554  memmove(padding_start + kPointerSize - shortage_bytes,
1555  padding_start + kPointerSize,
1556  Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize);
1557 
1558  pre_top_frame->UpdateFp(pre_top_frame->fp() - shortage_bytes);
1559  pre_pre_frame->SetCallerFp(pre_top_frame->fp());
1560  unused_stack_top -= shortage_bytes;
1561 
1562  STATIC_ASSERT(sizeof(Address) == kPointerSize);
1563  top_frame_pc_address -= shortage_bytes / kPointerSize;
1564  } else {
1565  return "Not enough space for frame dropper frame";
1566  }
1567  }
1568 
1569  // Committing now. After this point we should return only NULL value.
1570 
1571  FixTryCatchHandler(pre_top_frame, bottom_js_frame);
1572  // Make sure FixTryCatchHandler is idempotent.
1573  ASSERT(!FixTryCatchHandler(pre_top_frame, bottom_js_frame));
1574 
1575  Handle<Code> code = Isolate::Current()->builtins()->FrameDropper_LiveEdit();
1576  *top_frame_pc_address = code->entry();
1577  pre_top_frame->SetCallerFp(bottom_js_frame->fp());
1578 
1579  *restarter_frame_function_pointer =
1580  Debug::SetUpFrameDropperFrame(bottom_js_frame, code);
1581 
1582  ASSERT((**restarter_frame_function_pointer)->IsJSFunction());
1583 
1584  for (Address a = unused_stack_top;
1585  a < unused_stack_bottom;
1586  a += kPointerSize) {
1588  }
1589 
1590  return NULL;
1591 }
1592 
1593 
1594 static bool IsDropableFrame(StackFrame* frame) {
1595  return !frame->is_exit();
1596 }
1597 
1598 // Fills result array with statuses of functions. Modifies the stack
1599 // removing all listed function if possible and if do_drop is true.
1600 static const char* DropActivationsInActiveThread(
1601  Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop,
1602  Zone* zone) {
1603  Isolate* isolate = Isolate::Current();
1604  Debug* debug = isolate->debug();
1605  ZoneScope scope(isolate, DELETE_ON_EXIT);
1606  Vector<StackFrame*> frames = CreateStackMap(zone);
1607 
1608  int array_len = Smi::cast(shared_info_array->length())->value();
1609 
1610  int top_frame_index = -1;
1611  int frame_index = 0;
1612  for (; frame_index < frames.length(); frame_index++) {
1613  StackFrame* frame = frames[frame_index];
1614  if (frame->id() == debug->break_frame_id()) {
1615  top_frame_index = frame_index;
1616  break;
1617  }
1618  if (CheckActivation(shared_info_array, result, frame,
1619  LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
1620  // We are still above break_frame. It is not a target frame,
1621  // it is a problem.
1622  return "Debugger mark-up on stack is not found";
1623  }
1624  }
1625 
1626  if (top_frame_index == -1) {
1627  // We haven't found break frame, but no function is blocking us anyway.
1628  return NULL;
1629  }
1630 
1631  bool target_frame_found = false;
1632  int bottom_js_frame_index = top_frame_index;
1633  bool c_code_found = false;
1634 
1635  for (; frame_index < frames.length(); frame_index++) {
1636  StackFrame* frame = frames[frame_index];
1637  if (!IsDropableFrame(frame)) {
1638  c_code_found = true;
1639  break;
1640  }
1641  if (CheckActivation(shared_info_array, result, frame,
1642  LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
1643  target_frame_found = true;
1644  bottom_js_frame_index = frame_index;
1645  }
1646  }
1647 
1648  if (c_code_found) {
1649  // There is a C frames on stack. Check that there are no target frames
1650  // below them.
1651  for (; frame_index < frames.length(); frame_index++) {
1652  StackFrame* frame = frames[frame_index];
1653  if (frame->is_java_script()) {
1654  if (CheckActivation(shared_info_array, result, frame,
1655  LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
1656  // Cannot drop frame under C frames.
1657  return NULL;
1658  }
1659  }
1660  }
1661  }
1662 
1663  if (!do_drop) {
1664  // We are in check-only mode.
1665  return NULL;
1666  }
1667 
1668  if (!target_frame_found) {
1669  // Nothing to drop.
1670  return NULL;
1671  }
1672 
1673  Debug::FrameDropMode drop_mode = Debug::FRAMES_UNTOUCHED;
1674  Object** restarter_frame_function_pointer = NULL;
1675  const char* error_message = DropFrames(frames, top_frame_index,
1676  bottom_js_frame_index, &drop_mode,
1677  &restarter_frame_function_pointer);
1678 
1679  if (error_message != NULL) {
1680  return error_message;
1681  }
1682 
1683  // Adjust break_frame after some frames has been dropped.
1684  StackFrame::Id new_id = StackFrame::NO_ID;
1685  for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) {
1686  if (frames[i]->type() == StackFrame::JAVA_SCRIPT) {
1687  new_id = frames[i]->id();
1688  break;
1689  }
1690  }
1691  debug->FramesHaveBeenDropped(new_id, drop_mode,
1692  restarter_frame_function_pointer);
1693 
1694  // Replace "blocked on active" with "replaced on active" status.
1695  for (int i = 0; i < array_len; i++) {
1696  if (result->GetElement(i) ==
1697  Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
1698  Handle<Object> replaced(
1699  Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK));
1700  SetElementNonStrict(result, i, replaced);
1701  }
1702  }
1703  return NULL;
1704 }
1705 
1706 
1707 class InactiveThreadActivationsChecker : public ThreadVisitor {
1708  public:
1709  InactiveThreadActivationsChecker(Handle<JSArray> shared_info_array,
1710  Handle<JSArray> result)
1711  : shared_info_array_(shared_info_array), result_(result),
1712  has_blocked_functions_(false) {
1713  }
1714  void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1715  for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1716  has_blocked_functions_ |= CheckActivation(
1717  shared_info_array_, result_, it.frame(),
1718  LiveEdit::FUNCTION_BLOCKED_ON_OTHER_STACK);
1719  }
1720  }
1721  bool HasBlockedFunctions() {
1722  return has_blocked_functions_;
1723  }
1724 
1725  private:
1726  Handle<JSArray> shared_info_array_;
1727  Handle<JSArray> result_;
1728  bool has_blocked_functions_;
1729 };
1730 
1731 
1732 Handle<JSArray> LiveEdit::CheckAndDropActivations(
1733  Handle<JSArray> shared_info_array, bool do_drop, Zone* zone) {
1734  int len = Smi::cast(shared_info_array->length())->value();
1735 
1736  Handle<JSArray> result = FACTORY->NewJSArray(len);
1737 
1738  // Fill the default values.
1739  for (int i = 0; i < len; i++) {
1740  SetElementNonStrict(
1741  result,
1742  i,
1743  Handle<Smi>(Smi::FromInt(FUNCTION_AVAILABLE_FOR_PATCH)));
1744  }
1745 
1746 
1747  // First check inactive threads. Fail if some functions are blocked there.
1748  InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array,
1749  result);
1750  Isolate::Current()->thread_manager()->IterateArchivedThreads(
1751  &inactive_threads_checker);
1752  if (inactive_threads_checker.HasBlockedFunctions()) {
1753  return result;
1754  }
1755 
1756  // Try to drop activations from the current stack.
1757  const char* error_message =
1758  DropActivationsInActiveThread(shared_info_array, result, do_drop, zone);
1759  if (error_message != NULL) {
1760  // Add error message as an array extra element.
1761  Vector<const char> vector_message(error_message, StrLength(error_message));
1762  Handle<String> str = FACTORY->NewStringFromAscii(vector_message);
1763  SetElementNonStrict(result, len, str);
1764  }
1765  return result;
1766 }
1767 
1768 
1770  FunctionLiteral* fun)
1771  : isolate_(isolate) {
1772  if (isolate_->active_function_info_listener() != NULL) {
1773  isolate_->active_function_info_listener()->FunctionStarted(fun);
1774  }
1775 }
1776 
1777 
1779  if (isolate_->active_function_info_listener() != NULL) {
1780  isolate_->active_function_info_listener()->FunctionDone();
1781  }
1782 }
1783 
1784 
1786  Handle<SharedFunctionInfo> info, FunctionLiteral* lit,
1787  Zone* zone) {
1788  if (isolate_->active_function_info_listener() != NULL) {
1789  isolate_->active_function_info_listener()->FunctionInfo(info, lit->scope(),
1790  zone);
1791  }
1792 }
1793 
1794 
1795 void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
1796  isolate_->active_function_info_listener()->FunctionCode(code);
1797 }
1798 
1799 
1800 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
1801  return isolate->active_function_info_listener() != NULL;
1802 }
1803 
1804 
1805 #else // ENABLE_DEBUGGER_SUPPORT
1806 
1807 // This ifdef-else-endif section provides working or stub implementation of
1808 // LiveEditFunctionTracker.
1810  FunctionLiteral* fun) {
1811 }
1812 
1813 
1815 }
1816 
1817 
1820 }
1821 
1822 
1824 }
1825 
1826 
1828  return false;
1829 }
1830 
1831 #endif // ENABLE_DEBUGGER_SUPPORT
1832 
1833 
1834 
1835 } } // namespace v8::internal
byte * Address
Definition: globals.h:172
const SwVfpRegister s2
static Object *& Object_at(Address addr)
Definition: v8memory.h:75
void RecordRootFunctionInfo(Handle< Code > code)
Definition: liveedit.cc:1823
static bool IsActive(Isolate *isolate)
Definition: liveedit.cc:1827
static String * cast(Object *obj)
static Smi * FromInt(int value)
Definition: objects-inl.h:973
const int KB
Definition: globals.h:221
static Object * GetObjectFromEntryAddress(Address location_of_address)
Definition: objects-inl.h:3391
Handle< FixedArray > CalculateLineEnds(Handle< String > src, bool with_last_line)
Definition: handles.cc:444
value format" "after each garbage collection") DEFINE_bool(print_cumulative_gc_stat, false, "print cumulative GC statistics in name=value format on exit") DEFINE_bool(trace_gc_verbose, false, "print more details following each garbage collection") DEFINE_bool(trace_fragmentation, false, "report fragmentation for old pointer and data pages") DEFINE_bool(collect_maps, true, "garbage collect maps from which no objects can be reached") DEFINE_bool(flush_code, true, "flush code that we expect not to use again before full gc") DEFINE_bool(incremental_marking, true, "use incremental marking") DEFINE_bool(incremental_marking_steps, true, "do incremental marking steps") DEFINE_bool(trace_incremental_marking, false, "trace progress of the incremental marking") DEFINE_bool(use_idle_notification, true, "Use idle notification to reduce memory footprint.") DEFINE_bool(send_idle_notification, false, "Send idle notifcation between stress runs.") DEFINE_bool(use_ic, true, "use inline caching") DEFINE_bool(native_code_counters, false, "generate extra code for manipulating stats counters") DEFINE_bool(always_compact, false, "Perform compaction on every full GC") DEFINE_bool(lazy_sweeping, true, "Use lazy sweeping for old pointer and data spaces") DEFINE_bool(never_compact, false, "Never perform compaction on full GC-testing only") DEFINE_bool(compact_code_space, true, "Compact code space on full non-incremental collections") DEFINE_bool(cleanup_code_caches_at_gc, true, "Flush inline caches prior to mark compact collection and" "flush code caches in maps during mark compact cycle.") DEFINE_int(random_seed, 0, "Default seed for initializing random generator" "(0, the default, means to use system random).") DEFINE_bool(use_verbose_printer, true, "allows verbose printing") DEFINE_bool(allow_natives_syntax, false, "allow natives syntax") DEFINE_bool(trace_sim, false, "Trace simulator execution") DEFINE_bool(check_icache, false, "Check icache flushes in ARM and MIPS simulator") DEFINE_int(stop_sim_at, 0, "Simulator stop after x number of instructions") DEFINE_int(sim_stack_alignment, 8, "Stack alingment in bytes in simulator(4 or 8, 8 is default)") DEFINE_bool(trace_exception, false, "print stack trace when throwing exceptions") DEFINE_bool(preallocate_message_memory, false, "preallocate some memory to build stack traces.") DEFINE_bool(randomize_hashes, true, "randomize hashes to avoid predictable hash collisions" "(with snapshots this option cannot override the baked-in seed)") DEFINE_int(hash_seed, 0, "Fixed seed to use to hash property keys(0 means random)" "(with snapshots this option cannot override the baked-in seed)") DEFINE_bool(preemption, false, "activate a 100ms timer that switches between V8 threads") DEFINE_bool(regexp_optimization, true, "generate optimized regexp code") DEFINE_bool(testing_bool_flag, true, "testing_bool_flag") DEFINE_int(testing_int_flag, 13, "testing_int_flag") DEFINE_float(testing_float_flag, 2.5, "float-flag") DEFINE_string(testing_string_flag, "Hello, world!", "string-flag") DEFINE_int(testing_prng_seed, 42, "Seed used for threading test randomness") DEFINE_string(testing_serialization_file, "/tmp/serdes", "file in which to serialize heap") DEFINE_bool(help, false, "Print usage message, including flags, on console") DEFINE_bool(dump_counters, false, "Dump counters on exit") DEFINE_string(map_counters, "", "Map counters to a file") DEFINE_args(js_arguments, JSARGUMENTS_INIT, "Pass all remaining arguments to the script.Alias for\"--\".") DEFINE_bool(debug_compile_events, true,"Enable debugger compile events") DEFINE_bool(debug_script_collected_events, true,"Enable debugger script collected events") DEFINE_bool(gdbjit, false,"enable GDBJIT interface (disables compacting GC)") DEFINE_bool(gdbjit_full, false,"enable GDBJIT interface for all code objects") DEFINE_bool(gdbjit_dump, false,"dump elf objects with debug info to disk") DEFINE_string(gdbjit_dump_filter,"","dump only objects containing this substring") DEFINE_bool(force_marking_deque_overflows, false,"force overflows of marking deque by reducing it's size ""to 64 words") DEFINE_bool(stress_compaction, false,"stress the GC compactor to flush out bugs (implies ""--force_marking_deque_overflows)")#define FLAG DEFINE_bool(enable_slow_asserts, false,"enable asserts that are slow to execute") DEFINE_bool(trace_codegen, false,"print name of functions for which code is generated") DEFINE_bool(print_source, false,"pretty print source code") DEFINE_bool(print_builtin_source, false,"pretty print source code for builtins") DEFINE_bool(print_ast, false,"print source AST") DEFINE_bool(print_builtin_ast, false,"print source AST for builtins") DEFINE_string(stop_at,"","function name where to insert a breakpoint") DEFINE_bool(print_builtin_scopes, false,"print scopes for builtins") DEFINE_bool(print_scopes, false,"print scopes") DEFINE_bool(trace_contexts, false,"trace contexts operations") DEFINE_bool(gc_greedy, false,"perform GC prior to some allocations") DEFINE_bool(gc_verbose, false,"print stuff during garbage collection") DEFINE_bool(heap_stats, false,"report heap statistics before and after GC") DEFINE_bool(code_stats, false,"report code statistics after GC") DEFINE_bool(verify_heap, false,"verify heap pointers before and after GC") DEFINE_bool(print_handles, false,"report handles after GC") DEFINE_bool(print_global_handles, false,"report global handles after GC") DEFINE_bool(trace_ic, false,"trace inline cache state transitions") DEFINE_bool(print_interfaces, false,"print interfaces") DEFINE_bool(print_interface_details, false,"print interface inference details") DEFINE_int(print_interface_depth, 5,"depth for printing interfaces") DEFINE_bool(trace_normalization, false,"prints when objects are turned into dictionaries.") DEFINE_bool(trace_lazy, false,"trace lazy compilation") DEFINE_bool(collect_heap_spill_statistics, false,"report heap spill statistics along with heap_stats ""(requires heap_stats)") DEFINE_bool(trace_isolates, false,"trace isolate state changes") DEFINE_bool(log_state_changes, false,"Log state changes.") DEFINE_bool(regexp_possessive_quantifier, false,"enable possessive quantifier syntax for testing") DEFINE_bool(trace_regexp_bytecodes, false,"trace regexp bytecode execution") DEFINE_bool(trace_regexp_assembler, false,"trace regexp macro assembler calls.")#define FLAG DEFINE_bool(log, false,"Minimal logging (no API, code, GC, suspect, or handles samples).") DEFINE_bool(log_all, false,"Log all events to the log file.") DEFINE_bool(log_runtime, false,"Activate runtime system %Log call.") DEFINE_bool(log_api, false,"Log API events to the log file.") DEFINE_bool(log_code, false,"Log code events to the log file without profiling.") DEFINE_bool(log_gc, false,"Log heap samples on garbage collection for the hp2ps tool.") DEFINE_bool(log_handles, false,"Log global handle events.") DEFINE_bool(log_snapshot_positions, false,"log positions of (de)serialized objects in the snapshot.") DEFINE_bool(log_suspect, false,"Log suspect operations.") DEFINE_bool(prof, false,"Log statistical profiling information (implies --log-code).") DEFINE_bool(prof_auto, true,"Used with --prof, starts profiling automatically") DEFINE_bool(prof_lazy, false,"Used with --prof, only does sampling and logging"" when profiler is active (implies --noprof_auto).") DEFINE_bool(prof_browser_mode, true,"Used with --prof, turns on browser-compatible mode for profiling.") DEFINE_bool(log_regexp, false,"Log regular expression execution.") DEFINE_bool(sliding_state_window, false,"Update sliding state window counters.") DEFINE_string(logfile,"v8.log","Specify the name of the log file.") DEFINE_bool(ll_prof, false,"Enable low-level linux profiler.")#define FLAG DEFINE_bool(trace_elements_transitions, false,"trace elements transitions") DEFINE_bool(print_code_stubs, false,"print code stubs") DEFINE_bool(test_secondary_stub_cache, false,"test secondary stub cache by disabling the primary one") DEFINE_bool(test_primary_stub_cache, false,"test primary stub cache by disabling the secondary one") DEFINE_bool(print_code, false,"print generated code") DEFINE_bool(print_opt_code, false,"print optimized code") DEFINE_bool(print_unopt_code, false,"print unoptimized code before ""printing optimized code based on it") DEFINE_bool(print_code_verbose, false,"print more information for code") DEFINE_bool(print_builtin_code, false,"print generated code for builtins")#43"/Users/thlorenz/dev/dx/v8-perf/build/v8/src/flags.cc"2#define FLAG_MODE_DEFINE_DEFAULTS#1"/Users/thlorenz/dev/dx/v8-perf/build/v8/src/flag-definitions.h"1#define FLAG_FULL(ftype, ctype, nam, def, cmt)#define FLAG_READONLY(ftype, ctype, nam, def, cmt)#define DEFINE_implication(whenflag, thenflag)#define DEFINE_bool(nam, def, cmt)#define DEFINE_int(nam, def, cmt)#define DEFINE_float(nam, def, cmt)#define DEFINE_string(nam, def, cmt)#define DEFINE_args(nam, def, cmt)#define FLAG DEFINE_bool(use_strict, false,"enforce strict mode") DEFINE_bool(es5_readonly, false,"activate correct semantics for inheriting readonliness") DEFINE_bool(es52_globals, false,"activate new semantics for global var declarations") DEFINE_bool(harmony_typeof, false,"enable harmony semantics for typeof") DEFINE_bool(harmony_scoping, false,"enable harmony block scoping") DEFINE_bool(harmony_modules, false,"enable harmony modules (implies block scoping)") DEFINE_bool(harmony_proxies, false,"enable harmony proxies") DEFINE_bool(harmony_collections, false,"enable harmony collections (sets, maps, and weak maps)") DEFINE_bool(harmony, false,"enable all harmony features (except typeof)") DEFINE_implication(harmony, harmony_scoping) DEFINE_implication(harmony, harmony_modules) DEFINE_implication(harmony, harmony_proxies) DEFINE_implication(harmony, harmony_collections) DEFINE_implication(harmony_modules, harmony_scoping) DEFINE_bool(packed_arrays, false,"optimizes arrays that have no holes") DEFINE_bool(smi_only_arrays, true,"tracks arrays with only smi values") DEFINE_bool(clever_optimizations, true,"Optimize object size, Array shift, DOM strings and string +") DEFINE_bool(unbox_double_arrays, true,"automatically unbox arrays of doubles") DEFINE_bool(string_slices, true,"use string slices") DEFINE_bool(crankshaft, true,"use crankshaft") DEFINE_string(hydrogen_filter,"","optimization filter") DEFINE_bool(use_range, true,"use hydrogen range analysis") DEFINE_bool(eliminate_dead_phis, true,"eliminate dead phis") DEFINE_bool(use_gvn, true,"use hydrogen global value numbering") DEFINE_bool(use_canonicalizing, true,"use hydrogen instruction canonicalizing") DEFINE_bool(use_inlining, true,"use function inlining") DEFINE_int(max_inlined_source_size, 600,"maximum source size in bytes considered for a single inlining") DEFINE_int(max_inlined_nodes, 196,"maximum number of AST nodes considered for a single inlining") DEFINE_int(max_inlined_nodes_cumulative, 196,"maximum cumulative number of AST nodes considered for inlining") DEFINE_bool(loop_invariant_code_motion, true,"loop invariant code motion") DEFINE_bool(collect_megamorphic_maps_from_stub_cache, true,"crankshaft harvests type feedback from stub cache") DEFINE_bool(hydrogen_stats, false,"print statistics for hydrogen") DEFINE_bool(trace_hydrogen, false,"trace generated hydrogen to file") DEFINE_string(trace_phase,"Z","trace generated IR for specified phases") DEFINE_bool(trace_inlining, false,"trace inlining decisions") DEFINE_bool(trace_alloc, false,"trace register allocator") DEFINE_bool(trace_all_uses, false,"trace all use positions") DEFINE_bool(trace_range, false,"trace range analysis") DEFINE_bool(trace_gvn, false,"trace global value numbering") DEFINE_bool(trace_representation, false,"trace representation types") DEFINE_bool(stress_pointer_maps, false,"pointer map for every instruction") DEFINE_bool(stress_environments, false,"environment for every instruction") DEFINE_int(deopt_every_n_times, 0,"deoptimize every n times a deopt point is passed") DEFINE_bool(trap_on_deopt, false,"put a break point before deoptimizing") DEFINE_bool(deoptimize_uncommon_cases, true,"deoptimize uncommon cases") DEFINE_bool(polymorphic_inlining, true,"polymorphic inlining") DEFINE_bool(use_osr, true,"use on-stack replacement") DEFINE_bool(array_bounds_checks_elimination, false,"perform array bounds checks elimination") DEFINE_bool(array_index_dehoisting, false,"perform array index dehoisting") DEFINE_bool(trace_osr, false,"trace on-stack replacement") DEFINE_int(stress_runs, 0,"number of stress runs") DEFINE_bool(optimize_closures, true,"optimize closures") DEFINE_bool(inline_construct, true,"inline constructor calls") DEFINE_bool(inline_arguments, true,"inline functions with arguments object") DEFINE_int(loop_weight, 1,"loop weight for representation inference") DEFINE_bool(optimize_for_in, true,"optimize functions containing for-in loops") DEFINE_bool(experimental_profiler, true,"enable all profiler experiments") DEFINE_bool(watch_ic_patching, false,"profiler considers IC stability") DEFINE_int(frame_count, 1,"number of stack frames inspected by the profiler") DEFINE_bool(self_optimization, false,"primitive functions trigger their own optimization") DEFINE_bool(direct_self_opt, false,"call recompile stub directly when self-optimizing") DEFINE_bool(retry_self_opt, false,"re-try self-optimization if it failed") DEFINE_bool(count_based_interrupts, false,"trigger profiler ticks based on counting instead of timing") DEFINE_bool(interrupt_at_exit, false,"insert an interrupt check at function exit") DEFINE_bool(weighted_back_edges, false,"weight back edges by jump distance for interrupt triggering") DEFINE_int(interrupt_budget, 5900,"execution budget before interrupt is triggered") DEFINE_int(type_info_threshold, 15,"percentage of ICs that must have type info to allow optimization") DEFINE_int(self_opt_count, 130,"call count before self-optimization") DEFINE_implication(experimental_profiler, watch_ic_patching) DEFINE_implication(experimental_profiler, self_optimization) DEFINE_implication(experimental_profiler, retry_self_opt) DEFINE_implication(experimental_profiler, count_based_interrupts) DEFINE_implication(experimental_profiler, interrupt_at_exit) DEFINE_implication(experimental_profiler, weighted_back_edges) DEFINE_bool(trace_opt_verbose, false,"extra verbose compilation tracing") DEFINE_implication(trace_opt_verbose, trace_opt) DEFINE_bool(debug_code, false,"generate extra code (assertions) for debugging") DEFINE_bool(code_comments, false,"emit comments in code disassembly") DEFINE_bool(enable_sse2, true,"enable use of SSE2 instructions if available") DEFINE_bool(enable_sse3, true,"enable use of SSE3 instructions if available") DEFINE_bool(enable_sse4_1, true,"enable use of SSE4.1 instructions if available") DEFINE_bool(enable_cmov, true,"enable use of CMOV instruction if available") DEFINE_bool(enable_rdtsc, true,"enable use of RDTSC instruction if available") DEFINE_bool(enable_sahf, true,"enable use of SAHF instruction if available (X64 only)") DEFINE_bool(enable_vfp3, true,"enable use of VFP3 instructions if available - this implies ""enabling ARMv7 instructions (ARM only)") DEFINE_bool(enable_armv7, true,"enable use of ARMv7 instructions if available (ARM only)") DEFINE_bool(enable_fpu, true,"enable use of MIPS FPU instructions if available (MIPS only)") DEFINE_string(expose_natives_as, NULL,"expose natives in global object") DEFINE_string(expose_debug_as, NULL,"expose debug in global object") DEFINE_bool(expose_gc, false,"expose gc extension") DEFINE_bool(expose_externalize_string, false,"expose externalize string extension") DEFINE_int(stack_trace_limit, 10,"number of stack frames to capture") DEFINE_bool(builtins_in_stack_traces, false,"show built-in functions in stack traces") DEFINE_bool(disable_native_files, false,"disable builtin natives files") DEFINE_bool(inline_new, true,"use fast inline allocation") DEFINE_bool(stack_trace_on_abort, true,"print a stack trace if an assertion failure occurs") DEFINE_bool(trace, false,"trace function calls") DEFINE_bool(mask_constants_with_cookie, true,"use random jit cookie to mask large constants") DEFINE_bool(lazy, true,"use lazy compilation") DEFINE_bool(trace_opt, false,"trace lazy optimization") DEFINE_bool(trace_opt_stats, false,"trace lazy optimization statistics") DEFINE_bool(opt, true,"use adaptive optimizations") DEFINE_bool(always_opt, false,"always try to optimize functions") DEFINE_bool(prepare_always_opt, false,"prepare for turning on always opt") DEFINE_bool(trace_deopt, false,"trace deoptimization") DEFINE_int(min_preparse_length, 1024,"minimum length for automatic enable preparsing") DEFINE_bool(always_full_compiler, false,"try to use the dedicated run-once backend for all code") DEFINE_bool(trace_bailout, false,"print reasons for falling back to using the classic V8 backend") DEFINE_bool(compilation_cache, true,"enable compilation cache") DEFINE_bool(cache_prototype_transitions, true,"cache prototype transitions") DEFINE_bool(trace_debug_json, false,"trace debugging JSON request/response") DEFINE_bool(debugger_auto_break, true,"automatically set the debug break flag when debugger commands are ""in the queue") DEFINE_bool(enable_liveedit, true,"enable liveedit experimental feature") DEFINE_bool(break_on_abort, true,"always cause a debug break before aborting") DEFINE_int(stack_size, kPointerSize *123,"default size of stack region v8 is allowed to use (in kBytes)") DEFINE_int(max_stack_trace_source_length, 300,"maximum length of function source code printed in a stack trace.") DEFINE_bool(always_inline_smi_code, false,"always inline smi code in non-opt code") DEFINE_int(max_new_space_size, 0,"max size of the new generation (in kBytes)") DEFINE_int(max_old_space_size, 0,"max size of the old generation (in Mbytes)") DEFINE_int(max_executable_size, 0,"max size of executable memory (in Mbytes)") DEFINE_bool(gc_global, false,"always perform global GCs") DEFINE_int(gc_interval,-1,"garbage collect after <n> allocations") DEFINE_bool(trace_gc, false,"print one trace line following each garbage collection") DEFINE_bool(trace_gc_nvp, false,"print one detailed trace line in name=value format ""after each garbage collection") DEFINE_bool(print_cumulative_gc_stat, false,"print cumulative GC statistics in name=value format on exit") DEFINE_bool(trace_gc_verbose, false,"print more details following each garbage collection") DEFINE_bool(trace_fragmentation, false,"report fragmentation for old pointer and data pages") DEFINE_bool(collect_maps, true,"garbage collect maps from which no objects can be reached") DEFINE_bool(flush_code, true,"flush code that we expect not to use again before full gc") DEFINE_bool(incremental_marking, true,"use incremental marking") DEFINE_bool(incremental_marking_steps, true,"do incremental marking steps") DEFINE_bool(trace_incremental_marking, false,"trace progress of the incremental marking") DEFINE_bool(use_idle_notification, true,"Use idle notification to reduce memory footprint.") DEFINE_bool(send_idle_notification, false,"Send idle notifcation between stress runs.") DEFINE_bool(use_ic, true,"use inline caching") DEFINE_bool(native_code_counters, false,"generate extra code for manipulating stats counters") DEFINE_bool(always_compact, false,"Perform compaction on every full GC") DEFINE_bool(lazy_sweeping, true,"Use lazy sweeping for old pointer and data spaces") DEFINE_bool(never_compact, false,"Never perform compaction on full GC - testing only") DEFINE_bool(compact_code_space, true,"Compact code space on full non-incremental collections") DEFINE_bool(cleanup_code_caches_at_gc, true,"Flush inline caches prior to mark compact collection and ""flush code caches in maps during mark compact cycle.") DEFINE_int(random_seed, 0,"Default seed for initializing random generator ""(0, the default, means to use system random).") DEFINE_bool(use_verbose_printer, true,"allows verbose printing") DEFINE_bool(allow_natives_syntax, false,"allow natives syntax") DEFINE_bool(trace_sim, false,"Trace simulator execution") DEFINE_bool(check_icache, false,"Check icache flushes in ARM and MIPS simulator") DEFINE_int(stop_sim_at, 0,"Simulator stop after x number of instructions") DEFINE_int(sim_stack_alignment, 8,"Stack alingment in bytes in simulator (4 or 8, 8 is default)") DEFINE_bool(trace_exception, false,"print stack trace when throwing exceptions") DEFINE_bool(preallocate_message_memory, false,"preallocate some memory to build stack traces.") DEFINE_bool(randomize_hashes, true,"randomize hashes to avoid predictable hash collisions ""(with snapshots this option cannot override the baked-in seed)") DEFINE_int(hash_seed, 0,"Fixed seed to use to hash property keys (0 means random)""(with snapshots this option cannot override the baked-in seed)") DEFINE_bool(preemption, false,"activate a 100ms timer that switches between V8 threads") DEFINE_bool(regexp_optimization, true,"generate optimized regexp code") DEFINE_bool(testing_bool_flag, true,"testing_bool_flag") DEFINE_int(testing_int_flag, 13,"testing_int_flag") DEFINE_float(testing_float_flag, 2.5,"float-flag") DEFINE_string(testing_string_flag,"Hello, world!","string-flag") DEFINE_int(testing_prng_seed, 42,"Seed used for threading test randomness") DEFINE_string(testing_serialization_file,"/tmp/serdes","file in which to serialize heap") DEFINE_bool(help, false,"Print usage message, including flags, on console") DEFINE_bool(dump_counters, false,"Dump counters on exit") DEFINE_string(map_counters,"","Map counters to a file") DEFINE_args(js_arguments, JSARGUMENTS_INIT,"Pass all remaining arguments to the script. Alias for \"--\".") DEFINE_bool(debug_compile_events, true,"Enable debugger compile events") DEFINE_bool(debug_script_collected_events, true,"Enable debugger script collected events") DEFINE_bool(gdbjit, false,"enable GDBJIT interface (disables compacting GC)") DEFINE_bool(gdbjit_full, false,"enable GDBJIT interface for all code objects") DEFINE_bool(gdbjit_dump, false,"dump elf objects with debug info to disk") DEFINE_string(gdbjit_dump_filter,"","dump only objects containing this substring") DEFINE_bool(force_marking_deque_overflows, false,"force overflows of marking deque by reducing it's size ""to 64 words") DEFINE_bool(stress_compaction, false,"stress the GC compactor to flush out bugs (implies ""--force_marking_deque_overflows)")#define FLAG DEFINE_bool(enable_slow_asserts, false,"enable asserts that are slow to execute") DEFINE_bool(trace_codegen, false,"print name of functions for which code is generated") DEFINE_bool(print_source, false,"pretty print source code") DEFINE_bool(print_builtin_source, false,"pretty print source code for builtins") DEFINE_bool(print_ast, false,"print source AST") DEFINE_bool(print_builtin_ast, false,"print source AST for builtins") DEFINE_string(stop_at,"","function name where to insert a breakpoint") DEFINE_bool(print_builtin_scopes, false,"print scopes for builtins") DEFINE_bool(print_scopes, false,"print scopes") DEFINE_bool(trace_contexts, false,"trace contexts operations") DEFINE_bool(gc_greedy, false,"perform GC prior to some allocations") DEFINE_bool(gc_verbose, false,"print stuff during garbage collection") DEFINE_bool(heap_stats, false,"report heap statistics before and after GC") DEFINE_bool(code_stats, false,"report code statistics after GC") DEFINE_bool(verify_heap, false,"verify heap pointers before and after GC") DEFINE_bool(print_handles, false,"report handles after GC") DEFINE_bool(print_global_handles, false,"report global handles after GC") DEFINE_bool(trace_ic, false,"trace inline cache state transitions") DEFINE_bool(print_interfaces, false,"print interfaces") DEFINE_bool(print_interface_details, false,"print interface inference details") DEFINE_int(print_interface_depth, 5,"depth for printing interfaces") DEFINE_bool(trace_normalization, false,"prints when objects are turned into dictionaries.") DEFINE_bool(trace_lazy, false,"trace lazy compilation") DEFINE_bool(collect_heap_spill_statistics, false,"report heap spill statistics along with heap_stats ""(requires heap_stats)") DEFINE_bool(trace_isolates, false,"trace isolate state changes") DEFINE_bool(log_state_changes, false,"Log state changes.") DEFINE_bool(regexp_possessive_quantifier, false,"enable possessive quantifier syntax for testing") DEFINE_bool(trace_regexp_bytecodes, false,"trace regexp bytecode execution") DEFINE_bool(trace_regexp_assembler, false,"trace regexp macro assembler calls.")#define FLAG DEFINE_bool(log, false,"Minimal logging (no API, code, GC, suspect, or handles samples).") DEFINE_bool(log_all, false,"Log all events to the log file.") DEFINE_bool(log_runtime, false,"Activate runtime system %Log call.") DEFINE_bool(log_api, false,"Log API events to the log file.") DEFINE_bool(log_code, false,"Log code events to the log file without profiling.") DEFINE_bool(log_gc, false,"Log heap samples on garbage collection for the hp2ps tool.") DEFINE_bool(log_handles, false,"Log global handle events.") DEFINE_bool(log_snapshot_positions, false,"log positions of (de)serialized objects in the snapshot.") DEFINE_bool(log_suspect, false,"Log suspect operations.") DEFINE_bool(prof, false,"Log statistical profiling information (implies --log-code).") DEFINE_bool(prof_auto, true,"Used with --prof, starts profiling automatically") DEFINE_bool(prof_lazy, false,"Used with --prof, only does sampling and logging"" when profiler is active (implies --noprof_auto).") DEFINE_bool(prof_browser_mode, true,"Used with --prof, turns on browser-compatible mode for profiling.") DEFINE_bool(log_regexp, false,"Log regular expression execution.") DEFINE_bool(sliding_state_window, false,"Update sliding state window counters.") DEFINE_string(logfile,"v8.log","Specify the name of the log file.") DEFINE_bool(ll_prof, false,"Enable low-level linux profiler.")#define FLAG DEFINE_bool(trace_elements_transitions, false,"trace elements transitions") DEFINE_bool(print_code_stubs, false,"print code stubs") DEFINE_bool(test_secondary_stub_cache, false,"test secondary stub cache by disabling the primary one") DEFINE_bool(test_primary_stub_cache, false,"test primary stub cache by disabling the secondary one") DEFINE_bool(print_code, false,"print generated code") DEFINE_bool(print_opt_code, false,"print optimized code") DEFINE_bool(print_unopt_code, false,"print unoptimized code before ""printing optimized code based on it") DEFINE_bool(print_code_verbose, false,"print more information for code") DEFINE_bool(print_builtin_code, false,"print generated code for builtins")#47"/Users/thlorenz/dev/dx/v8-perf/build/v8/src/flags.cc"2 namespace{struct Flag{enum FlagType{TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING, TYPE_ARGS} name
Definition: flags.cc:1349
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:1809
static SharedFunctionInfo * cast(Object *obj)
StringInputBuffer *const buffer_
Vector< StackFrame * > CreateStackMap(Zone *zone)
Definition: frames.cc:1427
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:6026
static ScopeInfo * cast(Object *object)
uint8_t byte
Definition: globals.h:171
const Register sp
HANDLE HANDLE LPSTACKFRAME64 StackFrame
#define UNREACHABLE()
Definition: checks.h:50
Object * GetElementNoExceptionThrown(uint32_t index)
Definition: objects-inl.h:842
STATIC_ASSERT((FixedDoubleArray::kHeaderSize &kDoubleAlignmentMask)==0)
static int CompareIndex(Variable *const *v, Variable *const *w)
Definition: variables.cc:91
const int kPointerSize
Definition: globals.h:234
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:9663
static Code * GetCodeFromTargetAddress(Address address)
Definition: objects-inl.h:3380
static JavaScriptFrame * cast(StackFrame *frame)
Definition: frames.h:532
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:1818
const SwVfpRegister s1
static JSValue * cast(Object *obj)
Definition: objects-inl.h:4327
#define HEAP
Definition: isolate.h:1408
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 trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt 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 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
Definition: flags.cc:274
void USE(T)
Definition: globals.h:303
static void VisitAllOptimizedFunctions(OptimizedFunctionVisitor *visitor)
Definition: deoptimizer.cc:305
#define FACTORY
Definition: isolate.h:1409
const uint32_t kMaxUInt32
Definition: globals.h:227
const Register fp
void DeleteArray(T *array)
Definition: allocation.h:91
static void FatalProcessOutOfMemory(const char *location, bool take_snapshot=false)
FlagType type() const
Definition: flags.cc:1358
static DeoptimizationInputData * cast(Object *obj)
const int MB
Definition: globals.h:222
static JSFunction * cast(Object *obj)