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