The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / liveedit.cc @ f230a1cf

History | View | Annotate | Download (70.6 KB)

1
// Copyright 2012 the V8 project authors. All rights reserved.
2
// Redistribution and use in source and binary forms, with or without
3
// modification, are permitted provided that the following conditions are
4
// met:
5
//
6
//     * Redistributions of source code must retain the above copyright
7
//       notice, this list of conditions and the following disclaimer.
8
//     * Redistributions in binary form must reproduce the above
9
//       copyright notice, this list of conditions and the following
10
//       disclaimer in the documentation and/or other materials provided
11
//       with the distribution.
12
//     * Neither the name of Google Inc. nor the names of its
13
//       contributors may be used to endorse or promote products derived
14
//       from this software without specific prior written permission.
15
//
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27

    
28

    
29
#include "v8.h"
30

    
31
#include "liveedit.h"
32

    
33
#include "code-stubs.h"
34
#include "compilation-cache.h"
35
#include "compiler.h"
36
#include "debug.h"
37
#include "deoptimizer.h"
38
#include "global-handles.h"
39
#include "messages.h"
40
#include "parser.h"
41
#include "scopeinfo.h"
42
#include "scopes.h"
43
#include "v8memory.h"
44

    
45
namespace v8 {
46
namespace internal {
47

    
48

    
49
#ifdef ENABLE_DEBUGGER_SUPPORT
50

    
51

    
52
void SetElementNonStrict(Handle<JSObject> object,
53
                         uint32_t index,
54
                         Handle<Object> value) {
55
  // Ignore return value from SetElement. It can only be a failure if there
56
  // are element setters causing exceptions and the debugger context has none
57
  // of these.
58
  Handle<Object> no_failure =
59
      JSObject::SetElement(object, index, value, NONE, kNonStrictMode);
60
  ASSERT(!no_failure.is_null());
61
  USE(no_failure);
62
}
63

    
64

    
65
// A simple implementation of dynamic programming algorithm. It solves
66
// the problem of finding the difference of 2 arrays. It uses a table of results
67
// of subproblems. Each cell contains a number together with 2-bit flag
68
// that helps building the chunk list.
69
class Differencer {
70
 public:
71
  explicit Differencer(Comparator::Input* input)
72
      : input_(input), len1_(input->GetLength1()), len2_(input->GetLength2()) {
73
    buffer_ = NewArray<int>(len1_ * len2_);
74
  }
75
  ~Differencer() {
76
    DeleteArray(buffer_);
77
  }
78

    
79
  void Initialize() {
80
    int array_size = len1_ * len2_;
81
    for (int i = 0; i < array_size; i++) {
82
      buffer_[i] = kEmptyCellValue;
83
    }
84
  }
85

    
86
  // Makes sure that result for the full problem is calculated and stored
87
  // in the table together with flags showing a path through subproblems.
88
  void FillTable() {
89
    CompareUpToTail(0, 0);
90
  }
91

    
92
  void SaveResult(Comparator::Output* chunk_writer) {
93
    ResultWriter writer(chunk_writer);
94

    
95
    int pos1 = 0;
96
    int pos2 = 0;
97
    while (true) {
98
      if (pos1 < len1_) {
99
        if (pos2 < len2_) {
100
          Direction dir = get_direction(pos1, pos2);
101
          switch (dir) {
102
            case EQ:
103
              writer.eq();
104
              pos1++;
105
              pos2++;
106
              break;
107
            case SKIP1:
108
              writer.skip1(1);
109
              pos1++;
110
              break;
111
            case SKIP2:
112
            case SKIP_ANY:
113
              writer.skip2(1);
114
              pos2++;
115
              break;
116
            default:
117
              UNREACHABLE();
118
          }
119
        } else {
120
          writer.skip1(len1_ - pos1);
121
          break;
122
        }
123
      } else {
124
        if (len2_ != pos2) {
125
          writer.skip2(len2_ - pos2);
126
        }
127
        break;
128
      }
129
    }
130
    writer.close();
131
  }
132

    
133
 private:
134
  Comparator::Input* input_;
135
  int* buffer_;
136
  int len1_;
137
  int len2_;
138

    
139
  enum Direction {
140
    EQ = 0,
141
    SKIP1,
142
    SKIP2,
143
    SKIP_ANY,
144

    
145
    MAX_DIRECTION_FLAG_VALUE = SKIP_ANY
146
  };
147

    
148
  // Computes result for a subtask and optionally caches it in the buffer table.
149
  // All results values are shifted to make space for flags in the lower bits.
150
  int CompareUpToTail(int pos1, int pos2) {
151
    if (pos1 < len1_) {
152
      if (pos2 < len2_) {
153
        int cached_res = get_value4(pos1, pos2);
154
        if (cached_res == kEmptyCellValue) {
155
          Direction dir;
156
          int res;
157
          if (input_->Equals(pos1, pos2)) {
158
            res = CompareUpToTail(pos1 + 1, pos2 + 1);
159
            dir = EQ;
160
          } else {
161
            int res1 = CompareUpToTail(pos1 + 1, pos2) +
162
                (1 << kDirectionSizeBits);
163
            int res2 = CompareUpToTail(pos1, pos2 + 1) +
164
                (1 << kDirectionSizeBits);
165
            if (res1 == res2) {
166
              res = res1;
167
              dir = SKIP_ANY;
168
            } else if (res1 < res2) {
169
              res = res1;
170
              dir = SKIP1;
171
            } else {
172
              res = res2;
173
              dir = SKIP2;
174
            }
175
          }
176
          set_value4_and_dir(pos1, pos2, res, dir);
177
          cached_res = res;
178
        }
179
        return cached_res;
180
      } else {
181
        return (len1_ - pos1) << kDirectionSizeBits;
182
      }
183
    } else {
184
      return (len2_ - pos2) << kDirectionSizeBits;
185
    }
186
  }
187

    
188
  inline int& get_cell(int i1, int i2) {
189
    return buffer_[i1 + i2 * len1_];
190
  }
191

    
192
  // Each cell keeps a value plus direction. Value is multiplied by 4.
193
  void set_value4_and_dir(int i1, int i2, int value4, Direction dir) {
194
    ASSERT((value4 & kDirectionMask) == 0);
195
    get_cell(i1, i2) = value4 | dir;
196
  }
197

    
198
  int get_value4(int i1, int i2) {
199
    return get_cell(i1, i2) & (kMaxUInt32 ^ kDirectionMask);
200
  }
201
  Direction get_direction(int i1, int i2) {
202
    return static_cast<Direction>(get_cell(i1, i2) & kDirectionMask);
203
  }
204

    
205
  static const int kDirectionSizeBits = 2;
206
  static const int kDirectionMask = (1 << kDirectionSizeBits) - 1;
207
  static const int kEmptyCellValue = -1 << kDirectionSizeBits;
208

    
209
  // This method only holds static assert statement (unfortunately you cannot
210
  // place one in class scope).
211
  void StaticAssertHolder() {
212
    STATIC_ASSERT(MAX_DIRECTION_FLAG_VALUE < (1 << kDirectionSizeBits));
213
  }
214

    
215
  class ResultWriter {
216
   public:
217
    explicit ResultWriter(Comparator::Output* chunk_writer)
218
        : chunk_writer_(chunk_writer), pos1_(0), pos2_(0),
219
          pos1_begin_(-1), pos2_begin_(-1), has_open_chunk_(false) {
220
    }
221
    void eq() {
222
      FlushChunk();
223
      pos1_++;
224
      pos2_++;
225
    }
226
    void skip1(int len1) {
227
      StartChunk();
228
      pos1_ += len1;
229
    }
230
    void skip2(int len2) {
231
      StartChunk();
232
      pos2_ += len2;
233
    }
234
    void close() {
235
      FlushChunk();
236
    }
237

    
238
   private:
239
    Comparator::Output* chunk_writer_;
240
    int pos1_;
241
    int pos2_;
242
    int pos1_begin_;
243
    int pos2_begin_;
244
    bool has_open_chunk_;
245

    
246
    void StartChunk() {
247
      if (!has_open_chunk_) {
248
        pos1_begin_ = pos1_;
249
        pos2_begin_ = pos2_;
250
        has_open_chunk_ = true;
251
      }
252
    }
253

    
254
    void FlushChunk() {
255
      if (has_open_chunk_) {
256
        chunk_writer_->AddChunk(pos1_begin_, pos2_begin_,
257
                                pos1_ - pos1_begin_, pos2_ - pos2_begin_);
258
        has_open_chunk_ = false;
259
      }
260
    }
261
  };
262
};
263

    
264

    
265
void Comparator::CalculateDifference(Comparator::Input* input,
266
                                     Comparator::Output* result_writer) {
267
  Differencer differencer(input);
268
  differencer.Initialize();
269
  differencer.FillTable();
270
  differencer.SaveResult(result_writer);
271
}
272

    
273

    
274
static bool CompareSubstrings(Handle<String> s1, int pos1,
275
                              Handle<String> s2, int pos2, int len) {
276
  for (int i = 0; i < len; i++) {
277
    if (s1->Get(i + pos1) != s2->Get(i + pos2)) {
278
      return false;
279
    }
280
  }
281
  return true;
282
}
283

    
284

    
285
// Additional to Input interface. Lets switch Input range to subrange.
286
// More elegant way would be to wrap one Input as another Input object
287
// and translate positions there, but that would cost us additional virtual
288
// call per comparison.
289
class SubrangableInput : public Comparator::Input {
290
 public:
291
  virtual void SetSubrange1(int offset, int len) = 0;
292
  virtual void SetSubrange2(int offset, int len) = 0;
293
};
294

    
295

    
296
class SubrangableOutput : public Comparator::Output {
297
 public:
298
  virtual void SetSubrange1(int offset, int len) = 0;
299
  virtual void SetSubrange2(int offset, int len) = 0;
300
};
301

    
302

    
303
static int min(int a, int b) {
304
  return a < b ? a : b;
305
}
306

    
307

    
308
// Finds common prefix and suffix in input. This parts shouldn't take space in
309
// linear programming table. Enable subranging in input and output.
310
static void NarrowDownInput(SubrangableInput* input,
311
    SubrangableOutput* output) {
312
  const int len1 = input->GetLength1();
313
  const int len2 = input->GetLength2();
314

    
315
  int common_prefix_len;
316
  int common_suffix_len;
317

    
318
  {
319
    common_prefix_len = 0;
320
    int prefix_limit = min(len1, len2);
321
    while (common_prefix_len < prefix_limit &&
322
        input->Equals(common_prefix_len, common_prefix_len)) {
323
      common_prefix_len++;
324
    }
325

    
326
    common_suffix_len = 0;
327
    int suffix_limit = min(len1 - common_prefix_len, len2 - common_prefix_len);
328

    
329
    while (common_suffix_len < suffix_limit &&
330
        input->Equals(len1 - common_suffix_len - 1,
331
        len2 - common_suffix_len - 1)) {
332
      common_suffix_len++;
333
    }
334
  }
335

    
336
  if (common_prefix_len > 0 || common_suffix_len > 0) {
337
    int new_len1 = len1 - common_suffix_len - common_prefix_len;
338
    int new_len2 = len2 - common_suffix_len - common_prefix_len;
339

    
340
    input->SetSubrange1(common_prefix_len, new_len1);
341
    input->SetSubrange2(common_prefix_len, new_len2);
342

    
343
    output->SetSubrange1(common_prefix_len, new_len1);
344
    output->SetSubrange2(common_prefix_len, new_len2);
345
  }
346
}
347

    
348

    
349
// A helper class that writes chunk numbers into JSArray.
350
// Each chunk is stored as 3 array elements: (pos1_begin, pos1_end, pos2_end).
351
class CompareOutputArrayWriter {
352
 public:
353
  explicit CompareOutputArrayWriter(Isolate* isolate)
354
      : array_(isolate->factory()->NewJSArray(10)), current_size_(0) {}
355

    
356
  Handle<JSArray> GetResult() {
357
    return array_;
358
  }
359

    
360
  void WriteChunk(int char_pos1, int char_pos2, int char_len1, int char_len2) {
361
    Isolate* isolate = array_->GetIsolate();
362
    SetElementNonStrict(array_,
363
                        current_size_,
364
                        Handle<Object>(Smi::FromInt(char_pos1), isolate));
365
    SetElementNonStrict(array_,
366
                        current_size_ + 1,
367
                        Handle<Object>(Smi::FromInt(char_pos1 + char_len1),
368
                                       isolate));
369
    SetElementNonStrict(array_,
370
                        current_size_ + 2,
371
                        Handle<Object>(Smi::FromInt(char_pos2 + char_len2),
372
                                       isolate));
373
    current_size_ += 3;
374
  }
375

    
376
 private:
377
  Handle<JSArray> array_;
378
  int current_size_;
379
};
380

    
381

    
382
// Represents 2 strings as 2 arrays of tokens.
383
// TODO(LiveEdit): Currently it's actually an array of charactres.
384
//     Make array of tokens instead.
385
class TokensCompareInput : public Comparator::Input {
386
 public:
387
  TokensCompareInput(Handle<String> s1, int offset1, int len1,
388
                       Handle<String> s2, int offset2, int len2)
389
      : s1_(s1), offset1_(offset1), len1_(len1),
390
        s2_(s2), offset2_(offset2), len2_(len2) {
391
  }
392
  virtual int GetLength1() {
393
    return len1_;
394
  }
395
  virtual int GetLength2() {
396
    return len2_;
397
  }
398
  bool Equals(int index1, int index2) {
399
    return s1_->Get(offset1_ + index1) == s2_->Get(offset2_ + index2);
400
  }
401

    
402
 private:
403
  Handle<String> s1_;
404
  int offset1_;
405
  int len1_;
406
  Handle<String> s2_;
407
  int offset2_;
408
  int len2_;
409
};
410

    
411

    
412
// Stores compare result in JSArray. Converts substring positions
413
// to absolute positions.
414
class TokensCompareOutput : public Comparator::Output {
415
 public:
416
  TokensCompareOutput(CompareOutputArrayWriter* array_writer,
417
                      int offset1, int offset2)
418
        : array_writer_(array_writer), offset1_(offset1), offset2_(offset2) {
419
  }
420

    
421
  void AddChunk(int pos1, int pos2, int len1, int len2) {
422
    array_writer_->WriteChunk(pos1 + offset1_, pos2 + offset2_, len1, len2);
423
  }
424

    
425
 private:
426
  CompareOutputArrayWriter* array_writer_;
427
  int offset1_;
428
  int offset2_;
429
};
430

    
431

    
432
// Wraps raw n-elements line_ends array as a list of n+1 lines. The last line
433
// never has terminating new line character.
434
class LineEndsWrapper {
435
 public:
436
  explicit LineEndsWrapper(Handle<String> string)
437
      : ends_array_(CalculateLineEnds(string, false)),
438
        string_len_(string->length()) {
439
  }
440
  int length() {
441
    return ends_array_->length() + 1;
442
  }
443
  // Returns start for any line including start of the imaginary line after
444
  // the last line.
445
  int GetLineStart(int index) {
446
    if (index == 0) {
447
      return 0;
448
    } else {
449
      return GetLineEnd(index - 1);
450
    }
451
  }
452
  int GetLineEnd(int index) {
453
    if (index == ends_array_->length()) {
454
      // End of the last line is always an end of the whole string.
455
      // If the string ends with a new line character, the last line is an
456
      // empty string after this character.
457
      return string_len_;
458
    } else {
459
      return GetPosAfterNewLine(index);
460
    }
461
  }
462

    
463
 private:
464
  Handle<FixedArray> ends_array_;
465
  int string_len_;
466

    
467
  int GetPosAfterNewLine(int index) {
468
    return Smi::cast(ends_array_->get(index))->value() + 1;
469
  }
470
};
471

    
472

    
473
// Represents 2 strings as 2 arrays of lines.
474
class LineArrayCompareInput : public SubrangableInput {
475
 public:
476
  LineArrayCompareInput(Handle<String> s1, Handle<String> s2,
477
                        LineEndsWrapper line_ends1, LineEndsWrapper line_ends2)
478
      : s1_(s1), s2_(s2), line_ends1_(line_ends1),
479
        line_ends2_(line_ends2),
480
        subrange_offset1_(0), subrange_offset2_(0),
481
        subrange_len1_(line_ends1_.length()),
482
        subrange_len2_(line_ends2_.length()) {
483
  }
484
  int GetLength1() {
485
    return subrange_len1_;
486
  }
487
  int GetLength2() {
488
    return subrange_len2_;
489
  }
490
  bool Equals(int index1, int index2) {
491
    index1 += subrange_offset1_;
492
    index2 += subrange_offset2_;
493

    
494
    int line_start1 = line_ends1_.GetLineStart(index1);
495
    int line_start2 = line_ends2_.GetLineStart(index2);
496
    int line_end1 = line_ends1_.GetLineEnd(index1);
497
    int line_end2 = line_ends2_.GetLineEnd(index2);
498
    int len1 = line_end1 - line_start1;
499
    int len2 = line_end2 - line_start2;
500
    if (len1 != len2) {
501
      return false;
502
    }
503
    return CompareSubstrings(s1_, line_start1, s2_, line_start2,
504
                             len1);
505
  }
506
  void SetSubrange1(int offset, int len) {
507
    subrange_offset1_ = offset;
508
    subrange_len1_ = len;
509
  }
510
  void SetSubrange2(int offset, int len) {
511
    subrange_offset2_ = offset;
512
    subrange_len2_ = len;
513
  }
514

    
515
 private:
516
  Handle<String> s1_;
517
  Handle<String> s2_;
518
  LineEndsWrapper line_ends1_;
519
  LineEndsWrapper line_ends2_;
520
  int subrange_offset1_;
521
  int subrange_offset2_;
522
  int subrange_len1_;
523
  int subrange_len2_;
524
};
525

    
526

    
527
// Stores compare result in JSArray. For each chunk tries to conduct
528
// a fine-grained nested diff token-wise.
529
class TokenizingLineArrayCompareOutput : public SubrangableOutput {
530
 public:
531
  TokenizingLineArrayCompareOutput(LineEndsWrapper line_ends1,
532
                                   LineEndsWrapper line_ends2,
533
                                   Handle<String> s1, Handle<String> s2)
534
      : array_writer_(s1->GetIsolate()),
535
        line_ends1_(line_ends1), line_ends2_(line_ends2), s1_(s1), s2_(s2),
536
        subrange_offset1_(0), subrange_offset2_(0) {
537
  }
538

    
539
  void AddChunk(int line_pos1, int line_pos2, int line_len1, int line_len2) {
540
    line_pos1 += subrange_offset1_;
541
    line_pos2 += subrange_offset2_;
542

    
543
    int char_pos1 = line_ends1_.GetLineStart(line_pos1);
544
    int char_pos2 = line_ends2_.GetLineStart(line_pos2);
545
    int char_len1 = line_ends1_.GetLineStart(line_pos1 + line_len1) - char_pos1;
546
    int char_len2 = line_ends2_.GetLineStart(line_pos2 + line_len2) - char_pos2;
547

    
548
    if (char_len1 < CHUNK_LEN_LIMIT && char_len2 < CHUNK_LEN_LIMIT) {
549
      // Chunk is small enough to conduct a nested token-level diff.
550
      HandleScope subTaskScope(s1_->GetIsolate());
551

    
552
      TokensCompareInput tokens_input(s1_, char_pos1, char_len1,
553
                                      s2_, char_pos2, char_len2);
554
      TokensCompareOutput tokens_output(&array_writer_, char_pos1,
555
                                          char_pos2);
556

    
557
      Comparator::CalculateDifference(&tokens_input, &tokens_output);
558
    } else {
559
      array_writer_.WriteChunk(char_pos1, char_pos2, char_len1, char_len2);
560
    }
561
  }
562
  void SetSubrange1(int offset, int len) {
563
    subrange_offset1_ = offset;
564
  }
565
  void SetSubrange2(int offset, int len) {
566
    subrange_offset2_ = offset;
567
  }
568

    
569
  Handle<JSArray> GetResult() {
570
    return array_writer_.GetResult();
571
  }
572

    
573
 private:
574
  static const int CHUNK_LEN_LIMIT = 800;
575

    
576
  CompareOutputArrayWriter array_writer_;
577
  LineEndsWrapper line_ends1_;
578
  LineEndsWrapper line_ends2_;
579
  Handle<String> s1_;
580
  Handle<String> s2_;
581
  int subrange_offset1_;
582
  int subrange_offset2_;
583
};
584

    
585

    
586
Handle<JSArray> LiveEdit::CompareStrings(Handle<String> s1,
587
                                         Handle<String> s2) {
588
  s1 = FlattenGetString(s1);
589
  s2 = FlattenGetString(s2);
590

    
591
  LineEndsWrapper line_ends1(s1);
592
  LineEndsWrapper line_ends2(s2);
593

    
594
  LineArrayCompareInput input(s1, s2, line_ends1, line_ends2);
595
  TokenizingLineArrayCompareOutput output(line_ends1, line_ends2, s1, s2);
596

    
597
  NarrowDownInput(&input, &output);
598

    
599
  Comparator::CalculateDifference(&input, &output);
600

    
601
  return output.GetResult();
602
}
603

    
604

    
605
static void CompileScriptForTracker(Isolate* isolate, Handle<Script> script) {
606
  // TODO(635): support extensions.
607
  PostponeInterruptsScope postpone(isolate);
608

    
609
  // Build AST.
610
  CompilationInfoWithZone info(script);
611
  info.MarkAsGlobal();
612
  // Parse and don't allow skipping lazy functions.
613
  if (Parser::Parse(&info)) {
614
    // Compile the code.
615
    LiveEditFunctionTracker tracker(info.isolate(), info.function());
616
    if (Compiler::MakeCodeForLiveEdit(&info)) {
617
      ASSERT(!info.code().is_null());
618
      tracker.RecordRootFunctionInfo(info.code());
619
    } else {
620
      info.isolate()->StackOverflow();
621
    }
622
  }
623
}
624

    
625

    
626
// Unwraps JSValue object, returning its field "value"
627
static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) {
628
  return Handle<Object>(jsValue->value(), jsValue->GetIsolate());
629
}
630

    
631

    
632
// Wraps any object into a OpaqueReference, that will hide the object
633
// from JavaScript.
634
static Handle<JSValue> WrapInJSValue(Handle<HeapObject> object) {
635
  Isolate* isolate = object->GetIsolate();
636
  Handle<JSFunction> constructor = isolate->opaque_reference_function();
637
  Handle<JSValue> result =
638
      Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
639
  result->set_value(*object);
640
  return result;
641
}
642

    
643

    
644
static Handle<SharedFunctionInfo> UnwrapSharedFunctionInfoFromJSValue(
645
    Handle<JSValue> jsValue) {
646
  Object* shared = jsValue->value();
647
  CHECK(shared->IsSharedFunctionInfo());
648
  return Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(shared));
649
}
650

    
651

    
652
static int GetArrayLength(Handle<JSArray> array) {
653
  Object* length = array->length();
654
  CHECK(length->IsSmi());
655
  return Smi::cast(length)->value();
656
}
657

    
658

    
659
// Simple helper class that creates more or less typed structures over
660
// JSArray object. This is an adhoc method of passing structures from C++
661
// to JavaScript.
662
template<typename S>
663
class JSArrayBasedStruct {
664
 public:
665
  static S Create(Isolate* isolate) {
666
    Factory* factory = isolate->factory();
667
    Handle<JSArray> array = factory->NewJSArray(S::kSize_);
668
    return S(array);
669
  }
670
  static S cast(Object* object) {
671
    JSArray* array = JSArray::cast(object);
672
    Handle<JSArray> array_handle(array);
673
    return S(array_handle);
674
  }
675
  explicit JSArrayBasedStruct(Handle<JSArray> array) : array_(array) {
676
  }
677
  Handle<JSArray> GetJSArray() {
678
    return array_;
679
  }
680
  Isolate* isolate() const {
681
    return array_->GetIsolate();
682
  }
683

    
684
 protected:
685
  void SetField(int field_position, Handle<Object> value) {
686
    SetElementNonStrict(array_, field_position, value);
687
  }
688
  void SetSmiValueField(int field_position, int value) {
689
    SetElementNonStrict(array_,
690
                        field_position,
691
                        Handle<Smi>(Smi::FromInt(value), isolate()));
692
  }
693
  Object* GetField(int field_position) {
694
    return array_->GetElementNoExceptionThrown(isolate(), field_position);
695
  }
696
  int GetSmiValueField(int field_position) {
697
    Object* res = GetField(field_position);
698
    CHECK(res->IsSmi());
699
    return Smi::cast(res)->value();
700
  }
701

    
702
 private:
703
  Handle<JSArray> array_;
704
};
705

    
706

    
707
// Represents some function compilation details. This structure will be used
708
// from JavaScript. It contains Code object, which is kept wrapped
709
// into a BlindReference for sanitizing reasons.
710
class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
711
 public:
712
  explicit FunctionInfoWrapper(Handle<JSArray> array)
713
      : JSArrayBasedStruct<FunctionInfoWrapper>(array) {
714
  }
715
  void SetInitialProperties(Handle<String> name, int start_position,
716
                            int end_position, int param_num,
717
                            int literal_count, int parent_index) {
718
    HandleScope scope(isolate());
719
    this->SetField(kFunctionNameOffset_, name);
720
    this->SetSmiValueField(kStartPositionOffset_, start_position);
721
    this->SetSmiValueField(kEndPositionOffset_, end_position);
722
    this->SetSmiValueField(kParamNumOffset_, param_num);
723
    this->SetSmiValueField(kLiteralNumOffset_, literal_count);
724
    this->SetSmiValueField(kParentIndexOffset_, parent_index);
725
  }
726
  void SetFunctionCode(Handle<Code> function_code,
727
      Handle<HeapObject> code_scope_info) {
728
    Handle<JSValue> code_wrapper = WrapInJSValue(function_code);
729
    this->SetField(kCodeOffset_, code_wrapper);
730

    
731
    Handle<JSValue> scope_wrapper = WrapInJSValue(code_scope_info);
732
    this->SetField(kCodeScopeInfoOffset_, scope_wrapper);
733
  }
734
  void SetFunctionScopeInfo(Handle<Object> scope_info_array) {
735
    this->SetField(kFunctionScopeInfoOffset_, scope_info_array);
736
  }
737
  void SetSharedFunctionInfo(Handle<SharedFunctionInfo> info) {
738
    Handle<JSValue> info_holder = WrapInJSValue(info);
739
    this->SetField(kSharedFunctionInfoOffset_, info_holder);
740
  }
741
  int GetLiteralCount() {
742
    return this->GetSmiValueField(kLiteralNumOffset_);
743
  }
744
  int GetParentIndex() {
745
    return this->GetSmiValueField(kParentIndexOffset_);
746
  }
747
  Handle<Code> GetFunctionCode() {
748
    Object* element = this->GetField(kCodeOffset_);
749
    CHECK(element->IsJSValue());
750
    Handle<JSValue> value_wrapper(JSValue::cast(element));
751
    Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
752
    CHECK(raw_result->IsCode());
753
    return Handle<Code>::cast(raw_result);
754
  }
755
  Handle<Object> GetCodeScopeInfo() {
756
    Object* element = this->GetField(kCodeScopeInfoOffset_);
757
    CHECK(element->IsJSValue());
758
    return UnwrapJSValue(Handle<JSValue>(JSValue::cast(element)));
759
  }
760
  int GetStartPosition() {
761
    return this->GetSmiValueField(kStartPositionOffset_);
762
  }
763
  int GetEndPosition() {
764
    return this->GetSmiValueField(kEndPositionOffset_);
765
  }
766

    
767
 private:
768
  static const int kFunctionNameOffset_ = 0;
769
  static const int kStartPositionOffset_ = 1;
770
  static const int kEndPositionOffset_ = 2;
771
  static const int kParamNumOffset_ = 3;
772
  static const int kCodeOffset_ = 4;
773
  static const int kCodeScopeInfoOffset_ = 5;
774
  static const int kFunctionScopeInfoOffset_ = 6;
775
  static const int kParentIndexOffset_ = 7;
776
  static const int kSharedFunctionInfoOffset_ = 8;
777
  static const int kLiteralNumOffset_ = 9;
778
  static const int kSize_ = 10;
779

    
780
  friend class JSArrayBasedStruct<FunctionInfoWrapper>;
781
};
782

    
783

    
784
// Wraps SharedFunctionInfo along with some of its fields for passing it
785
// back to JavaScript. SharedFunctionInfo object itself is additionally
786
// wrapped into BlindReference for sanitizing reasons.
787
class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> {
788
 public:
789
  static bool IsInstance(Handle<JSArray> array) {
790
    return array->length() == Smi::FromInt(kSize_) &&
791
        array->GetElementNoExceptionThrown(
792
            array->GetIsolate(), kSharedInfoOffset_)->IsJSValue();
793
  }
794

    
795
  explicit SharedInfoWrapper(Handle<JSArray> array)
796
      : JSArrayBasedStruct<SharedInfoWrapper>(array) {
797
  }
798

    
799
  void SetProperties(Handle<String> name, int start_position, int end_position,
800
                     Handle<SharedFunctionInfo> info) {
801
    HandleScope scope(isolate());
802
    this->SetField(kFunctionNameOffset_, name);
803
    Handle<JSValue> info_holder = WrapInJSValue(info);
804
    this->SetField(kSharedInfoOffset_, info_holder);
805
    this->SetSmiValueField(kStartPositionOffset_, start_position);
806
    this->SetSmiValueField(kEndPositionOffset_, end_position);
807
  }
808
  Handle<SharedFunctionInfo> GetInfo() {
809
    Object* element = this->GetField(kSharedInfoOffset_);
810
    CHECK(element->IsJSValue());
811
    Handle<JSValue> value_wrapper(JSValue::cast(element));
812
    return UnwrapSharedFunctionInfoFromJSValue(value_wrapper);
813
  }
814

    
815
 private:
816
  static const int kFunctionNameOffset_ = 0;
817
  static const int kStartPositionOffset_ = 1;
818
  static const int kEndPositionOffset_ = 2;
819
  static const int kSharedInfoOffset_ = 3;
820
  static const int kSize_ = 4;
821

    
822
  friend class JSArrayBasedStruct<SharedInfoWrapper>;
823
};
824

    
825

    
826
class FunctionInfoListener {
827
 public:
828
  explicit FunctionInfoListener(Isolate* isolate) {
829
    current_parent_index_ = -1;
830
    len_ = 0;
831
    result_ = isolate->factory()->NewJSArray(10);
832
  }
833

    
834
  void FunctionStarted(FunctionLiteral* fun) {
835
    HandleScope scope(isolate());
836
    FunctionInfoWrapper info = FunctionInfoWrapper::Create(isolate());
837
    info.SetInitialProperties(fun->name(), fun->start_position(),
838
                              fun->end_position(), fun->parameter_count(),
839
                              fun->materialized_literal_count(),
840
                              current_parent_index_);
841
    current_parent_index_ = len_;
842
    SetElementNonStrict(result_, len_, info.GetJSArray());
843
    len_++;
844
  }
845

    
846
  void FunctionDone() {
847
    HandleScope scope(isolate());
848
    FunctionInfoWrapper info =
849
        FunctionInfoWrapper::cast(
850
            result_->GetElementNoExceptionThrown(
851
                isolate(), current_parent_index_));
852
    current_parent_index_ = info.GetParentIndex();
853
  }
854

    
855
  // Saves only function code, because for a script function we
856
  // may never create a SharedFunctionInfo object.
857
  void FunctionCode(Handle<Code> function_code) {
858
    FunctionInfoWrapper info =
859
        FunctionInfoWrapper::cast(
860
            result_->GetElementNoExceptionThrown(
861
                isolate(), current_parent_index_));
862
    info.SetFunctionCode(function_code,
863
                         Handle<HeapObject>(isolate()->heap()->null_value()));
864
  }
865

    
866
  // Saves full information about a function: its code, its scope info
867
  // and a SharedFunctionInfo object.
868
  void FunctionInfo(Handle<SharedFunctionInfo> shared, Scope* scope,
869
                    Zone* zone) {
870
    if (!shared->IsSharedFunctionInfo()) {
871
      return;
872
    }
873
    FunctionInfoWrapper info =
874
        FunctionInfoWrapper::cast(
875
            result_->GetElementNoExceptionThrown(
876
                isolate(), current_parent_index_));
877
    info.SetFunctionCode(Handle<Code>(shared->code()),
878
                         Handle<HeapObject>(shared->scope_info()));
879
    info.SetSharedFunctionInfo(shared);
880

    
881
    Handle<Object> scope_info_list(SerializeFunctionScope(scope, zone),
882
                                   isolate());
883
    info.SetFunctionScopeInfo(scope_info_list);
884
  }
885

    
886
  Handle<JSArray> GetResult() { return result_; }
887

    
888
 private:
889
  Isolate* isolate() const { return result_->GetIsolate(); }
890

    
891
  Object* SerializeFunctionScope(Scope* scope, Zone* zone) {
892
    HandleScope handle_scope(isolate());
893

    
894
    Handle<JSArray> scope_info_list = isolate()->factory()->NewJSArray(10);
895
    int scope_info_length = 0;
896

    
897
    // Saves some description of scope. It stores name and indexes of
898
    // variables in the whole scope chain. Null-named slots delimit
899
    // scopes of this chain.
900
    Scope* current_scope = scope;
901
    while (current_scope != NULL) {
902
      ZoneList<Variable*> stack_list(current_scope->StackLocalCount(), zone);
903
      ZoneList<Variable*> context_list(
904
          current_scope->ContextLocalCount(), zone);
905
      current_scope->CollectStackAndContextLocals(&stack_list, &context_list);
906
      context_list.Sort(&Variable::CompareIndex);
907

    
908
      for (int i = 0; i < context_list.length(); i++) {
909
        SetElementNonStrict(scope_info_list,
910
                            scope_info_length,
911
                            context_list[i]->name());
912
        scope_info_length++;
913
        SetElementNonStrict(
914
            scope_info_list,
915
            scope_info_length,
916
            Handle<Smi>(Smi::FromInt(context_list[i]->index()), isolate()));
917
        scope_info_length++;
918
      }
919
      SetElementNonStrict(scope_info_list,
920
                          scope_info_length,
921
                          Handle<Object>(isolate()->heap()->null_value(),
922
                                         isolate()));
923
      scope_info_length++;
924

    
925
      current_scope = current_scope->outer_scope();
926
    }
927

    
928
    return *scope_info_list;
929
  }
930

    
931
  Handle<JSArray> result_;
932
  int len_;
933
  int current_parent_index_;
934
};
935

    
936

    
937
JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script,
938
                                     Handle<String> source) {
939
  Isolate* isolate = script->GetIsolate();
940

    
941
  FunctionInfoListener listener(isolate);
942
  Handle<Object> original_source =
943
      Handle<Object>(script->source(), isolate);
944
  script->set_source(*source);
945
  isolate->set_active_function_info_listener(&listener);
946

    
947
  {
948
    // Creating verbose TryCatch from public API is currently the only way to
949
    // force code save location. We do not use this the object directly.
950
    v8::TryCatch try_catch;
951
    try_catch.SetVerbose(true);
952

    
953
    // A logical 'try' section.
954
    CompileScriptForTracker(isolate, script);
955
  }
956

    
957
  // A logical 'catch' section.
958
  Handle<JSObject> rethrow_exception;
959
  if (isolate->has_pending_exception()) {
960
    Handle<Object> exception(isolate->pending_exception()->ToObjectChecked(),
961
                             isolate);
962
    MessageLocation message_location = isolate->GetMessageLocation();
963

    
964
    isolate->clear_pending_message();
965
    isolate->clear_pending_exception();
966

    
967
    // If possible, copy positions from message object to exception object.
968
    if (exception->IsJSObject() && !message_location.script().is_null()) {
969
      rethrow_exception = Handle<JSObject>::cast(exception);
970

    
971
      Factory* factory = isolate->factory();
972
      Handle<String> start_pos_key = factory->InternalizeOneByteString(
973
          STATIC_ASCII_VECTOR("startPosition"));
974
      Handle<String> end_pos_key = factory->InternalizeOneByteString(
975
          STATIC_ASCII_VECTOR("endPosition"));
976
      Handle<String> script_obj_key = factory->InternalizeOneByteString(
977
          STATIC_ASCII_VECTOR("scriptObject"));
978
      Handle<Smi> start_pos(
979
          Smi::FromInt(message_location.start_pos()), isolate);
980
      Handle<Smi> end_pos(Smi::FromInt(message_location.end_pos()), isolate);
981
      Handle<JSValue> script_obj = GetScriptWrapper(message_location.script());
982
      JSReceiver::SetProperty(
983
          rethrow_exception, start_pos_key, start_pos, NONE, kNonStrictMode);
984
      JSReceiver::SetProperty(
985
          rethrow_exception, end_pos_key, end_pos, NONE, kNonStrictMode);
986
      JSReceiver::SetProperty(
987
          rethrow_exception, script_obj_key, script_obj, NONE, kNonStrictMode);
988
    }
989
  }
990

    
991
  // A logical 'finally' section.
992
  isolate->set_active_function_info_listener(NULL);
993
  script->set_source(*original_source);
994

    
995
  if (rethrow_exception.is_null()) {
996
    return *(listener.GetResult());
997
  } else {
998
    isolate->Throw(*rethrow_exception);
999
    return 0;
1000
  }
1001
}
1002

    
1003

    
1004
void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> array) {
1005
  Isolate* isolate = array->GetIsolate();
1006
  HandleScope scope(isolate);
1007
  int len = GetArrayLength(array);
1008
  for (int i = 0; i < len; i++) {
1009
    Handle<SharedFunctionInfo> info(
1010
        SharedFunctionInfo::cast(
1011
            array->GetElementNoExceptionThrown(isolate, i)));
1012
    SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create(isolate);
1013
    Handle<String> name_handle(String::cast(info->name()));
1014
    info_wrapper.SetProperties(name_handle, info->start_position(),
1015
                               info->end_position(), info);
1016
    SetElementNonStrict(array, i, info_wrapper.GetJSArray());
1017
  }
1018
}
1019

    
1020

    
1021
// Visitor that finds all references to a particular code object,
1022
// including "CODE_TARGET" references in other code objects and replaces
1023
// them on the fly.
1024
class ReplacingVisitor : public ObjectVisitor {
1025
 public:
1026
  explicit ReplacingVisitor(Code* original, Code* substitution)
1027
    : original_(original), substitution_(substitution) {
1028
  }
1029

    
1030
  virtual void VisitPointers(Object** start, Object** end) {
1031
    for (Object** p = start; p < end; p++) {
1032
      if (*p == original_) {
1033
        *p = substitution_;
1034
      }
1035
    }
1036
  }
1037

    
1038
  virtual void VisitCodeEntry(Address entry) {
1039
    if (Code::GetObjectFromEntryAddress(entry) == original_) {
1040
      Address substitution_entry = substitution_->instruction_start();
1041
      Memory::Address_at(entry) = substitution_entry;
1042
    }
1043
  }
1044

    
1045
  virtual void VisitCodeTarget(RelocInfo* rinfo) {
1046
    if (RelocInfo::IsCodeTarget(rinfo->rmode()) &&
1047
        Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) {
1048
      Address substitution_entry = substitution_->instruction_start();
1049
      rinfo->set_target_address(substitution_entry);
1050
    }
1051
  }
1052

    
1053
  virtual void VisitDebugTarget(RelocInfo* rinfo) {
1054
    VisitCodeTarget(rinfo);
1055
  }
1056

    
1057
 private:
1058
  Code* original_;
1059
  Code* substitution_;
1060
};
1061

    
1062

    
1063
// Finds all references to original and replaces them with substitution.
1064
static void ReplaceCodeObject(Handle<Code> original,
1065
                              Handle<Code> substitution) {
1066
  // Perform a full GC in order to ensure that we are not in the middle of an
1067
  // incremental marking phase when we are replacing the code object.
1068
  // Since we are not in an incremental marking phase we can write pointers
1069
  // to code objects (that are never in new space) without worrying about
1070
  // write barriers.
1071
  Heap* heap = original->GetHeap();
1072
  heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1073
                          "liveedit.cc ReplaceCodeObject");
1074

    
1075
  ASSERT(!heap->InNewSpace(*substitution));
1076

    
1077
  DisallowHeapAllocation no_allocation;
1078

    
1079
  ReplacingVisitor visitor(*original, *substitution);
1080

    
1081
  // Iterate over all roots. Stack frames may have pointer into original code,
1082
  // so temporary replace the pointers with offset numbers
1083
  // in prologue/epilogue.
1084
  heap->IterateRoots(&visitor, VISIT_ALL);
1085

    
1086
  // Now iterate over all pointers of all objects, including code_target
1087
  // implicit pointers.
1088
  HeapIterator iterator(heap);
1089
  for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1090
    obj->Iterate(&visitor);
1091
  }
1092
}
1093

    
1094

    
1095
// Patch function literals.
1096
// Name 'literals' is a misnomer. Rather it's a cache for complex object
1097
// boilerplates and for a native context. We must clean cached values.
1098
// Additionally we may need to allocate a new array if number of literals
1099
// changed.
1100
class LiteralFixer {
1101
 public:
1102
  static void PatchLiterals(FunctionInfoWrapper* compile_info_wrapper,
1103
                            Handle<SharedFunctionInfo> shared_info,
1104
                            Isolate* isolate) {
1105
    int new_literal_count = compile_info_wrapper->GetLiteralCount();
1106
    if (new_literal_count > 0) {
1107
      new_literal_count += JSFunction::kLiteralsPrefixSize;
1108
    }
1109
    int old_literal_count = shared_info->num_literals();
1110

    
1111
    if (old_literal_count == new_literal_count) {
1112
      // If literal count didn't change, simply go over all functions
1113
      // and clear literal arrays.
1114
      ClearValuesVisitor visitor;
1115
      IterateJSFunctions(*shared_info, &visitor);
1116
    } else {
1117
      // When literal count changes, we have to create new array instances.
1118
      // Since we cannot create instances when iterating heap, we should first
1119
      // collect all functions and fix their literal arrays.
1120
      Handle<FixedArray> function_instances =
1121
          CollectJSFunctions(shared_info, isolate);
1122
      for (int i = 0; i < function_instances->length(); i++) {
1123
        Handle<JSFunction> fun(JSFunction::cast(function_instances->get(i)));
1124
        Handle<FixedArray> old_literals(fun->literals());
1125
        Handle<FixedArray> new_literals =
1126
            isolate->factory()->NewFixedArray(new_literal_count);
1127
        if (new_literal_count > 0) {
1128
          Handle<Context> native_context;
1129
          if (old_literals->length() >
1130
              JSFunction::kLiteralNativeContextIndex) {
1131
            native_context = Handle<Context>(
1132
                JSFunction::NativeContextFromLiterals(fun->literals()));
1133
          } else {
1134
            native_context = Handle<Context>(fun->context()->native_context());
1135
          }
1136
          new_literals->set(JSFunction::kLiteralNativeContextIndex,
1137
              *native_context);
1138
        }
1139
        fun->set_literals(*new_literals);
1140
      }
1141

    
1142
      shared_info->set_num_literals(new_literal_count);
1143
    }
1144
  }
1145

    
1146
 private:
1147
  // Iterates all function instances in the HEAP that refers to the
1148
  // provided shared_info.
1149
  template<typename Visitor>
1150
  static void IterateJSFunctions(SharedFunctionInfo* shared_info,
1151
                                 Visitor* visitor) {
1152
    DisallowHeapAllocation no_allocation;
1153

    
1154
    HeapIterator iterator(shared_info->GetHeap());
1155
    for (HeapObject* obj = iterator.next(); obj != NULL;
1156
        obj = iterator.next()) {
1157
      if (obj->IsJSFunction()) {
1158
        JSFunction* function = JSFunction::cast(obj);
1159
        if (function->shared() == shared_info) {
1160
          visitor->visit(function);
1161
        }
1162
      }
1163
    }
1164
  }
1165

    
1166
  // Finds all instances of JSFunction that refers to the provided shared_info
1167
  // and returns array with them.
1168
  static Handle<FixedArray> CollectJSFunctions(
1169
      Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
1170
    CountVisitor count_visitor;
1171
    count_visitor.count = 0;
1172
    IterateJSFunctions(*shared_info, &count_visitor);
1173
    int size = count_visitor.count;
1174

    
1175
    Handle<FixedArray> result = isolate->factory()->NewFixedArray(size);
1176
    if (size > 0) {
1177
      CollectVisitor collect_visitor(result);
1178
      IterateJSFunctions(*shared_info, &collect_visitor);
1179
    }
1180
    return result;
1181
  }
1182

    
1183
  class ClearValuesVisitor {
1184
   public:
1185
    void visit(JSFunction* fun) {
1186
      FixedArray* literals = fun->literals();
1187
      int len = literals->length();
1188
      for (int j = JSFunction::kLiteralsPrefixSize; j < len; j++) {
1189
        literals->set_undefined(j);
1190
      }
1191
    }
1192
  };
1193

    
1194
  class CountVisitor {
1195
   public:
1196
    void visit(JSFunction* fun) {
1197
      count++;
1198
    }
1199
    int count;
1200
  };
1201

    
1202
  class CollectVisitor {
1203
   public:
1204
    explicit CollectVisitor(Handle<FixedArray> output)
1205
        : m_output(output), m_pos(0) {}
1206

    
1207
    void visit(JSFunction* fun) {
1208
      m_output->set(m_pos, fun);
1209
      m_pos++;
1210
    }
1211
   private:
1212
    Handle<FixedArray> m_output;
1213
    int m_pos;
1214
  };
1215
};
1216

    
1217

    
1218
// Check whether the code is natural function code (not a lazy-compile stub
1219
// code).
1220
static bool IsJSFunctionCode(Code* code) {
1221
  return code->kind() == Code::FUNCTION;
1222
}
1223

    
1224

    
1225
// Returns true if an instance of candidate were inlined into function's code.
1226
static bool IsInlined(JSFunction* function, SharedFunctionInfo* candidate) {
1227
  DisallowHeapAllocation no_gc;
1228

    
1229
  if (function->code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
1230

    
1231
  DeoptimizationInputData* data =
1232
      DeoptimizationInputData::cast(function->code()->deoptimization_data());
1233

    
1234
  if (data == function->GetIsolate()->heap()->empty_fixed_array()) {
1235
    return false;
1236
  }
1237

    
1238
  FixedArray* literals = data->LiteralArray();
1239

    
1240
  int inlined_count = data->InlinedFunctionCount()->value();
1241
  for (int i = 0; i < inlined_count; ++i) {
1242
    JSFunction* inlined = JSFunction::cast(literals->get(i));
1243
    if (inlined->shared() == candidate) return true;
1244
  }
1245

    
1246
  return false;
1247
}
1248

    
1249

    
1250
// Marks code that shares the same shared function info or has inlined
1251
// code that shares the same function info.
1252
class DependentFunctionMarker: public OptimizedFunctionVisitor {
1253
 public:
1254
  SharedFunctionInfo* shared_info_;
1255
  bool found_;
1256

    
1257
  explicit DependentFunctionMarker(SharedFunctionInfo* shared_info)
1258
    : shared_info_(shared_info), found_(false) { }
1259

    
1260
  virtual void EnterContext(Context* context) { }  // Don't care.
1261
  virtual void LeaveContext(Context* context)  { }  // Don't care.
1262
  virtual void VisitFunction(JSFunction* function) {
1263
    // It should be guaranteed by the iterator that everything is optimized.
1264
    ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
1265
    if (shared_info_ == function->shared() ||
1266
        IsInlined(function, shared_info_)) {
1267
      // Mark the code for deoptimization.
1268
      function->code()->set_marked_for_deoptimization(true);
1269
      found_ = true;
1270
    }
1271
  }
1272
};
1273

    
1274

    
1275
static void DeoptimizeDependentFunctions(SharedFunctionInfo* function_info) {
1276
  DisallowHeapAllocation no_allocation;
1277
  DependentFunctionMarker marker(function_info);
1278
  // TODO(titzer): need to traverse all optimized code to find OSR code here.
1279
  Deoptimizer::VisitAllOptimizedFunctions(function_info->GetIsolate(), &marker);
1280

    
1281
  if (marker.found_) {
1282
    // Only go through with the deoptimization if something was found.
1283
    Deoptimizer::DeoptimizeMarkedCode(function_info->GetIsolate());
1284
  }
1285
}
1286

    
1287

    
1288
MaybeObject* LiveEdit::ReplaceFunctionCode(
1289
    Handle<JSArray> new_compile_info_array,
1290
    Handle<JSArray> shared_info_array) {
1291
  Isolate* isolate = new_compile_info_array->GetIsolate();
1292
  HandleScope scope(isolate);
1293

    
1294
  if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
1295
    return isolate->ThrowIllegalOperation();
1296
  }
1297

    
1298
  FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
1299
  SharedInfoWrapper shared_info_wrapper(shared_info_array);
1300

    
1301
  Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
1302

    
1303
  isolate->heap()->EnsureHeapIsIterable();
1304

    
1305
  if (IsJSFunctionCode(shared_info->code())) {
1306
    Handle<Code> code = compile_info_wrapper.GetFunctionCode();
1307
    ReplaceCodeObject(Handle<Code>(shared_info->code()), code);
1308
    Handle<Object> code_scope_info = compile_info_wrapper.GetCodeScopeInfo();
1309
    if (code_scope_info->IsFixedArray()) {
1310
      shared_info->set_scope_info(ScopeInfo::cast(*code_scope_info));
1311
    }
1312
    shared_info->DisableOptimization(kLiveEdit);
1313
  }
1314

    
1315
  if (shared_info->debug_info()->IsDebugInfo()) {
1316
    Handle<DebugInfo> debug_info(DebugInfo::cast(shared_info->debug_info()));
1317
    Handle<Code> new_original_code =
1318
        isolate->factory()->CopyCode(compile_info_wrapper.GetFunctionCode());
1319
    debug_info->set_original_code(*new_original_code);
1320
  }
1321

    
1322
  int start_position = compile_info_wrapper.GetStartPosition();
1323
  int end_position = compile_info_wrapper.GetEndPosition();
1324
  shared_info->set_start_position(start_position);
1325
  shared_info->set_end_position(end_position);
1326

    
1327
  LiteralFixer::PatchLiterals(&compile_info_wrapper, shared_info, isolate);
1328

    
1329
  shared_info->set_construct_stub(
1330
      isolate->builtins()->builtin(Builtins::kJSConstructStubGeneric));
1331

    
1332
  DeoptimizeDependentFunctions(*shared_info);
1333
  isolate->compilation_cache()->Remove(shared_info);
1334

    
1335
  return isolate->heap()->undefined_value();
1336
}
1337

    
1338

    
1339
MaybeObject* LiveEdit::FunctionSourceUpdated(
1340
    Handle<JSArray> shared_info_array) {
1341
  Isolate* isolate = shared_info_array->GetIsolate();
1342
  HandleScope scope(isolate);
1343

    
1344
  if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
1345
    return isolate->ThrowIllegalOperation();
1346
  }
1347

    
1348
  SharedInfoWrapper shared_info_wrapper(shared_info_array);
1349
  Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
1350

    
1351
  DeoptimizeDependentFunctions(*shared_info);
1352
  isolate->compilation_cache()->Remove(shared_info);
1353

    
1354
  return isolate->heap()->undefined_value();
1355
}
1356

    
1357

    
1358
void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
1359
                                 Handle<Object> script_handle) {
1360
  Handle<SharedFunctionInfo> shared_info =
1361
      UnwrapSharedFunctionInfoFromJSValue(function_wrapper);
1362
  CHECK(script_handle->IsScript() || script_handle->IsUndefined());
1363
  shared_info->set_script(*script_handle);
1364

    
1365
  function_wrapper->GetIsolate()->compilation_cache()->Remove(shared_info);
1366
}
1367

    
1368

    
1369
// For a script text change (defined as position_change_array), translates
1370
// position in unchanged text to position in changed text.
1371
// Text change is a set of non-overlapping regions in text, that have changed
1372
// their contents and length. It is specified as array of groups of 3 numbers:
1373
// (change_begin, change_end, change_end_new_position).
1374
// Each group describes a change in text; groups are sorted by change_begin.
1375
// Only position in text beyond any changes may be successfully translated.
1376
// If a positions is inside some region that changed, result is currently
1377
// undefined.
1378
static int TranslatePosition(int original_position,
1379
                             Handle<JSArray> position_change_array) {
1380
  int position_diff = 0;
1381
  int array_len = GetArrayLength(position_change_array);
1382
  Isolate* isolate = position_change_array->GetIsolate();
1383
  // TODO(635): binary search may be used here
1384
  for (int i = 0; i < array_len; i += 3) {
1385
    Object* element =
1386
        position_change_array->GetElementNoExceptionThrown(isolate, i);
1387
    CHECK(element->IsSmi());
1388
    int chunk_start = Smi::cast(element)->value();
1389
    if (original_position < chunk_start) {
1390
      break;
1391
    }
1392
    element = position_change_array->GetElementNoExceptionThrown(isolate,
1393
                                                                 i + 1);
1394
    CHECK(element->IsSmi());
1395
    int chunk_end = Smi::cast(element)->value();
1396
    // Position mustn't be inside a chunk.
1397
    ASSERT(original_position >= chunk_end);
1398
    element = position_change_array->GetElementNoExceptionThrown(isolate,
1399
                                                                 i + 2);
1400
    CHECK(element->IsSmi());
1401
    int chunk_changed_end = Smi::cast(element)->value();
1402
    position_diff = chunk_changed_end - chunk_end;
1403
  }
1404

    
1405
  return original_position + position_diff;
1406
}
1407

    
1408

    
1409
// Auto-growing buffer for writing relocation info code section. This buffer
1410
// is a simplified version of buffer from Assembler. Unlike Assembler, this
1411
// class is platform-independent and it works without dealing with instructions.
1412
// As specified by RelocInfo format, the buffer is filled in reversed order:
1413
// from upper to lower addresses.
1414
// It uses NewArray/DeleteArray for memory management.
1415
class RelocInfoBuffer {
1416
 public:
1417
  RelocInfoBuffer(int buffer_initial_capicity, byte* pc) {
1418
    buffer_size_ = buffer_initial_capicity + kBufferGap;
1419
    buffer_ = NewArray<byte>(buffer_size_);
1420

    
1421
    reloc_info_writer_.Reposition(buffer_ + buffer_size_, pc);
1422
  }
1423
  ~RelocInfoBuffer() {
1424
    DeleteArray(buffer_);
1425
  }
1426

    
1427
  // As specified by RelocInfo format, the buffer is filled in reversed order:
1428
  // from upper to lower addresses.
1429
  void Write(const RelocInfo* rinfo) {
1430
    if (buffer_ + kBufferGap >= reloc_info_writer_.pos()) {
1431
      Grow();
1432
    }
1433
    reloc_info_writer_.Write(rinfo);
1434
  }
1435

    
1436
  Vector<byte> GetResult() {
1437
    // Return the bytes from pos up to end of buffer.
1438
    int result_size =
1439
        static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer_.pos());
1440
    return Vector<byte>(reloc_info_writer_.pos(), result_size);
1441
  }
1442

    
1443
 private:
1444
  void Grow() {
1445
    // Compute new buffer size.
1446
    int new_buffer_size;
1447
    if (buffer_size_ < 2 * KB) {
1448
      new_buffer_size = 4 * KB;
1449
    } else {
1450
      new_buffer_size = 2 * buffer_size_;
1451
    }
1452
    // Some internal data structures overflow for very large buffers,
1453
    // they must ensure that kMaximalBufferSize is not too large.
1454
    if (new_buffer_size > kMaximalBufferSize) {
1455
      V8::FatalProcessOutOfMemory("RelocInfoBuffer::GrowBuffer");
1456
    }
1457

    
1458
    // Set up new buffer.
1459
    byte* new_buffer = NewArray<byte>(new_buffer_size);
1460

    
1461
    // Copy the data.
1462
    int curently_used_size =
1463
        static_cast<int>(buffer_ + buffer_size_ - reloc_info_writer_.pos());
1464
    OS::MemMove(new_buffer + new_buffer_size - curently_used_size,
1465
                reloc_info_writer_.pos(), curently_used_size);
1466

    
1467
    reloc_info_writer_.Reposition(
1468
        new_buffer + new_buffer_size - curently_used_size,
1469
        reloc_info_writer_.last_pc());
1470

    
1471
    DeleteArray(buffer_);
1472
    buffer_ = new_buffer;
1473
    buffer_size_ = new_buffer_size;
1474
  }
1475

    
1476
  RelocInfoWriter reloc_info_writer_;
1477
  byte* buffer_;
1478
  int buffer_size_;
1479

    
1480
  static const int kBufferGap = RelocInfoWriter::kMaxSize;
1481
  static const int kMaximalBufferSize = 512*MB;
1482
};
1483

    
1484

    
1485
// Patch positions in code (changes relocation info section) and possibly
1486
// returns new instance of code.
1487
static Handle<Code> PatchPositionsInCode(
1488
    Handle<Code> code,
1489
    Handle<JSArray> position_change_array) {
1490
  Isolate* isolate = code->GetIsolate();
1491

    
1492
  RelocInfoBuffer buffer_writer(code->relocation_size(),
1493
                                code->instruction_start());
1494

    
1495
  {
1496
    DisallowHeapAllocation no_allocation;
1497
    for (RelocIterator it(*code); !it.done(); it.next()) {
1498
      RelocInfo* rinfo = it.rinfo();
1499
      if (RelocInfo::IsPosition(rinfo->rmode())) {
1500
        int position = static_cast<int>(rinfo->data());
1501
        int new_position = TranslatePosition(position,
1502
                                             position_change_array);
1503
        if (position != new_position) {
1504
          RelocInfo info_copy(rinfo->pc(), rinfo->rmode(), new_position, NULL);
1505
          buffer_writer.Write(&info_copy);
1506
          continue;
1507
        }
1508
      }
1509
      if (RelocInfo::IsRealRelocMode(rinfo->rmode())) {
1510
        buffer_writer.Write(it.rinfo());
1511
      }
1512
    }
1513
  }
1514

    
1515
  Vector<byte> buffer = buffer_writer.GetResult();
1516

    
1517
  if (buffer.length() == code->relocation_size()) {
1518
    // Simply patch relocation area of code.
1519
    OS::MemCopy(code->relocation_start(), buffer.start(), buffer.length());
1520
    return code;
1521
  } else {
1522
    // Relocation info section now has different size. We cannot simply
1523
    // rewrite it inside code object. Instead we have to create a new
1524
    // code object.
1525
    Handle<Code> result(isolate->factory()->CopyCode(code, buffer));
1526
    return result;
1527
  }
1528
}
1529

    
1530

    
1531
MaybeObject* LiveEdit::PatchFunctionPositions(
1532
    Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array) {
1533
  if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
1534
    return shared_info_array->GetIsolate()->ThrowIllegalOperation();
1535
  }
1536

    
1537
  SharedInfoWrapper shared_info_wrapper(shared_info_array);
1538
  Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo();
1539

    
1540
  int old_function_start = info->start_position();
1541
  int new_function_start = TranslatePosition(old_function_start,
1542
                                             position_change_array);
1543
  int new_function_end = TranslatePosition(info->end_position(),
1544
                                           position_change_array);
1545
  int new_function_token_pos =
1546
      TranslatePosition(info->function_token_position(), position_change_array);
1547

    
1548
  info->set_start_position(new_function_start);
1549
  info->set_end_position(new_function_end);
1550
  info->set_function_token_position(new_function_token_pos);
1551

    
1552
  info->GetIsolate()->heap()->EnsureHeapIsIterable();
1553

    
1554
  if (IsJSFunctionCode(info->code())) {
1555
    // Patch relocation info section of the code.
1556
    Handle<Code> patched_code = PatchPositionsInCode(Handle<Code>(info->code()),
1557
                                                     position_change_array);
1558
    if (*patched_code != info->code()) {
1559
      // Replace all references to the code across the heap. In particular,
1560
      // some stubs may refer to this code and this code may be being executed
1561
      // on stack (it is safe to substitute the code object on stack, because
1562
      // we only change the structure of rinfo and leave instructions
1563
      // untouched).
1564
      ReplaceCodeObject(Handle<Code>(info->code()), patched_code);
1565
    }
1566
  }
1567

    
1568
  return info->GetIsolate()->heap()->undefined_value();
1569
}
1570

    
1571

    
1572
static Handle<Script> CreateScriptCopy(Handle<Script> original) {
1573
  Isolate* isolate = original->GetIsolate();
1574

    
1575
  Handle<String> original_source(String::cast(original->source()));
1576
  Handle<Script> copy = isolate->factory()->NewScript(original_source);
1577

    
1578
  copy->set_name(original->name());
1579
  copy->set_line_offset(original->line_offset());
1580
  copy->set_column_offset(original->column_offset());
1581
  copy->set_data(original->data());
1582
  copy->set_type(original->type());
1583
  copy->set_context_data(original->context_data());
1584
  copy->set_eval_from_shared(original->eval_from_shared());
1585
  copy->set_eval_from_instructions_offset(
1586
      original->eval_from_instructions_offset());
1587

    
1588
  // Copy all the flags, but clear compilation state.
1589
  copy->set_flags(original->flags());
1590
  copy->set_compilation_state(Script::COMPILATION_STATE_INITIAL);
1591

    
1592
  return copy;
1593
}
1594

    
1595

    
1596
Object* LiveEdit::ChangeScriptSource(Handle<Script> original_script,
1597
                                     Handle<String> new_source,
1598
                                     Handle<Object> old_script_name) {
1599
  Isolate* isolate = original_script->GetIsolate();
1600
  Handle<Object> old_script_object;
1601
  if (old_script_name->IsString()) {
1602
    Handle<Script> old_script = CreateScriptCopy(original_script);
1603
    old_script->set_name(String::cast(*old_script_name));
1604
    old_script_object = old_script;
1605
    isolate->debugger()->OnAfterCompile(
1606
        old_script, Debugger::SEND_WHEN_DEBUGGING);
1607
  } else {
1608
    old_script_object = isolate->factory()->null_value();
1609
  }
1610

    
1611
  original_script->set_source(*new_source);
1612

    
1613
  // Drop line ends so that they will be recalculated.
1614
  original_script->set_line_ends(isolate->heap()->undefined_value());
1615

    
1616
  return *old_script_object;
1617
}
1618

    
1619

    
1620

    
1621
void LiveEdit::ReplaceRefToNestedFunction(
1622
    Handle<JSValue> parent_function_wrapper,
1623
    Handle<JSValue> orig_function_wrapper,
1624
    Handle<JSValue> subst_function_wrapper) {
1625

    
1626
  Handle<SharedFunctionInfo> parent_shared =
1627
      UnwrapSharedFunctionInfoFromJSValue(parent_function_wrapper);
1628
  Handle<SharedFunctionInfo> orig_shared =
1629
      UnwrapSharedFunctionInfoFromJSValue(orig_function_wrapper);
1630
  Handle<SharedFunctionInfo> subst_shared =
1631
      UnwrapSharedFunctionInfoFromJSValue(subst_function_wrapper);
1632

    
1633
  for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) {
1634
    if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) {
1635
      if (it.rinfo()->target_object() == *orig_shared) {
1636
        it.rinfo()->set_target_object(*subst_shared);
1637
      }
1638
    }
1639
  }
1640
}
1641

    
1642

    
1643
// Check an activation against list of functions. If there is a function
1644
// that matches, its status in result array is changed to status argument value.
1645
static bool CheckActivation(Handle<JSArray> shared_info_array,
1646
                            Handle<JSArray> result,
1647
                            StackFrame* frame,
1648
                            LiveEdit::FunctionPatchabilityStatus status) {
1649
  if (!frame->is_java_script()) return false;
1650

    
1651
  Handle<JSFunction> function(JavaScriptFrame::cast(frame)->function());
1652

    
1653
  Isolate* isolate = shared_info_array->GetIsolate();
1654
  int len = GetArrayLength(shared_info_array);
1655
  for (int i = 0; i < len; i++) {
1656
    Object* element =
1657
        shared_info_array->GetElementNoExceptionThrown(isolate, i);
1658
    CHECK(element->IsJSValue());
1659
    Handle<JSValue> jsvalue(JSValue::cast(element));
1660
    Handle<SharedFunctionInfo> shared =
1661
        UnwrapSharedFunctionInfoFromJSValue(jsvalue);
1662

    
1663
    if (function->shared() == *shared || IsInlined(*function, *shared)) {
1664
      SetElementNonStrict(result, i, Handle<Smi>(Smi::FromInt(status),
1665
                                                 isolate));
1666
      return true;
1667
    }
1668
  }
1669
  return false;
1670
}
1671

    
1672

    
1673
// Iterates over handler chain and removes all elements that are inside
1674
// frames being dropped.
1675
static bool FixTryCatchHandler(StackFrame* top_frame,
1676
                               StackFrame* bottom_frame) {
1677
  Address* pointer_address =
1678
      &Memory::Address_at(top_frame->isolate()->get_address_from_id(
1679
          Isolate::kHandlerAddress));
1680

    
1681
  while (*pointer_address < top_frame->sp()) {
1682
    pointer_address = &Memory::Address_at(*pointer_address);
1683
  }
1684
  Address* above_frame_address = pointer_address;
1685
  while (*pointer_address < bottom_frame->fp()) {
1686
    pointer_address = &Memory::Address_at(*pointer_address);
1687
  }
1688
  bool change = *above_frame_address != *pointer_address;
1689
  *above_frame_address = *pointer_address;
1690
  return change;
1691
}
1692

    
1693

    
1694
// Removes specified range of frames from stack. There may be 1 or more
1695
// frames in range. Anyway the bottom frame is restarted rather than dropped,
1696
// and therefore has to be a JavaScript frame.
1697
// Returns error message or NULL.
1698
static const char* DropFrames(Vector<StackFrame*> frames,
1699
                              int top_frame_index,
1700
                              int bottom_js_frame_index,
1701
                              Debug::FrameDropMode* mode,
1702
                              Object*** restarter_frame_function_pointer) {
1703
  if (!Debug::kFrameDropperSupported) {
1704
    return "Stack manipulations are not supported in this architecture.";
1705
  }
1706

    
1707
  StackFrame* pre_top_frame = frames[top_frame_index - 1];
1708
  StackFrame* top_frame = frames[top_frame_index];
1709
  StackFrame* bottom_js_frame = frames[bottom_js_frame_index];
1710

    
1711
  ASSERT(bottom_js_frame->is_java_script());
1712

    
1713
  // Check the nature of the top frame.
1714
  Isolate* isolate = bottom_js_frame->isolate();
1715
  Code* pre_top_frame_code = pre_top_frame->LookupCode();
1716
  bool frame_has_padding;
1717
  if (pre_top_frame_code->is_inline_cache_stub() &&
1718
      pre_top_frame_code->is_debug_stub()) {
1719
    // OK, we can drop inline cache calls.
1720
    *mode = Debug::FRAME_DROPPED_IN_IC_CALL;
1721
    frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
1722
  } else if (pre_top_frame_code ==
1723
             isolate->debug()->debug_break_slot()) {
1724
    // OK, we can drop debug break slot.
1725
    *mode = Debug::FRAME_DROPPED_IN_DEBUG_SLOT_CALL;
1726
    frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
1727
  } else if (pre_top_frame_code ==
1728
      isolate->builtins()->builtin(
1729
          Builtins::kFrameDropper_LiveEdit)) {
1730
    // OK, we can drop our own code.
1731
    pre_top_frame = frames[top_frame_index - 2];
1732
    top_frame = frames[top_frame_index - 1];
1733
    *mode = Debug::CURRENTLY_SET_MODE;
1734
    frame_has_padding = false;
1735
  } else if (pre_top_frame_code ==
1736
      isolate->builtins()->builtin(Builtins::kReturn_DebugBreak)) {
1737
    *mode = Debug::FRAME_DROPPED_IN_RETURN_CALL;
1738
    frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
1739
  } else if (pre_top_frame_code->kind() == Code::STUB &&
1740
      pre_top_frame_code->major_key() == CodeStub::CEntry) {
1741
    // Entry from our unit tests on 'debugger' statement.
1742
    // It's fine, we support this case.
1743
    *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
1744
    // We don't have a padding from 'debugger' statement call.
1745
    // Here the stub is CEntry, it's not debug-only and can't be padded.
1746
    // If anyone would complain, a proxy padded stub could be added.
1747
    frame_has_padding = false;
1748
  } else if (pre_top_frame->type() == StackFrame::ARGUMENTS_ADAPTOR) {
1749
    // This must be adaptor that remain from the frame dropping that
1750
    // is still on stack. A frame dropper frame must be above it.
1751
    ASSERT(frames[top_frame_index - 2]->LookupCode() ==
1752
        isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit));
1753
    pre_top_frame = frames[top_frame_index - 3];
1754
    top_frame = frames[top_frame_index - 2];
1755
    *mode = Debug::CURRENTLY_SET_MODE;
1756
    frame_has_padding = false;
1757
  } else {
1758
    return "Unknown structure of stack above changing function";
1759
  }
1760

    
1761
  Address unused_stack_top = top_frame->sp();
1762
  Address unused_stack_bottom = bottom_js_frame->fp()
1763
      - Debug::kFrameDropperFrameSize * kPointerSize  // Size of the new frame.
1764
      + kPointerSize;  // Bigger address end is exclusive.
1765

    
1766
  Address* top_frame_pc_address = top_frame->pc_address();
1767

    
1768
  // top_frame may be damaged below this point. Do not used it.
1769
  ASSERT(!(top_frame = NULL));
1770

    
1771
  if (unused_stack_top > unused_stack_bottom) {
1772
    if (frame_has_padding) {
1773
      int shortage_bytes =
1774
          static_cast<int>(unused_stack_top - unused_stack_bottom);
1775

    
1776
      Address padding_start = pre_top_frame->fp() -
1777
          Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize;
1778

    
1779
      Address padding_pointer = padding_start;
1780
      Smi* padding_object =
1781
          Smi::FromInt(Debug::FramePaddingLayout::kPaddingValue);
1782
      while (Memory::Object_at(padding_pointer) == padding_object) {
1783
        padding_pointer -= kPointerSize;
1784
      }
1785
      int padding_counter =
1786
          Smi::cast(Memory::Object_at(padding_pointer))->value();
1787
      if (padding_counter * kPointerSize < shortage_bytes) {
1788
        return "Not enough space for frame dropper frame "
1789
            "(even with padding frame)";
1790
      }
1791
      Memory::Object_at(padding_pointer) =
1792
          Smi::FromInt(padding_counter - shortage_bytes / kPointerSize);
1793

    
1794
      StackFrame* pre_pre_frame = frames[top_frame_index - 2];
1795

    
1796
      OS::MemMove(padding_start + kPointerSize - shortage_bytes,
1797
                  padding_start + kPointerSize,
1798
                  Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize);
1799

    
1800
      pre_top_frame->UpdateFp(pre_top_frame->fp() - shortage_bytes);
1801
      pre_pre_frame->SetCallerFp(pre_top_frame->fp());
1802
      unused_stack_top -= shortage_bytes;
1803

    
1804
      STATIC_ASSERT(sizeof(Address) == kPointerSize);
1805
      top_frame_pc_address -= shortage_bytes / kPointerSize;
1806
    } else {
1807
      return "Not enough space for frame dropper frame";
1808
    }
1809
  }
1810

    
1811
  // Committing now. After this point we should return only NULL value.
1812

    
1813
  FixTryCatchHandler(pre_top_frame, bottom_js_frame);
1814
  // Make sure FixTryCatchHandler is idempotent.
1815
  ASSERT(!FixTryCatchHandler(pre_top_frame, bottom_js_frame));
1816

    
1817
  Handle<Code> code = isolate->builtins()->FrameDropper_LiveEdit();
1818
  *top_frame_pc_address = code->entry();
1819
  pre_top_frame->SetCallerFp(bottom_js_frame->fp());
1820

    
1821
  *restarter_frame_function_pointer =
1822
      Debug::SetUpFrameDropperFrame(bottom_js_frame, code);
1823

    
1824
  ASSERT((**restarter_frame_function_pointer)->IsJSFunction());
1825

    
1826
  for (Address a = unused_stack_top;
1827
      a < unused_stack_bottom;
1828
      a += kPointerSize) {
1829
    Memory::Object_at(a) = Smi::FromInt(0);
1830
  }
1831

    
1832
  return NULL;
1833
}
1834

    
1835

    
1836
static bool IsDropableFrame(StackFrame* frame) {
1837
  return !frame->is_exit();
1838
}
1839

    
1840

    
1841
// Describes a set of call frames that execute any of listed functions.
1842
// Finding no such frames does not mean error.
1843
class MultipleFunctionTarget {
1844
 public:
1845
  MultipleFunctionTarget(Handle<JSArray> shared_info_array,
1846
      Handle<JSArray> result)
1847
      : m_shared_info_array(shared_info_array),
1848
        m_result(result) {}
1849
  bool MatchActivation(StackFrame* frame,
1850
      LiveEdit::FunctionPatchabilityStatus status) {
1851
    return CheckActivation(m_shared_info_array, m_result, frame, status);
1852
  }
1853
  const char* GetNotFoundMessage() {
1854
    return NULL;
1855
  }
1856
 private:
1857
  Handle<JSArray> m_shared_info_array;
1858
  Handle<JSArray> m_result;
1859
};
1860

    
1861

    
1862
// Drops all call frame matched by target and all frames above them.
1863
template<typename TARGET>
1864
static const char* DropActivationsInActiveThreadImpl(
1865
    Isolate* isolate, TARGET& target, bool do_drop) {
1866
  Debug* debug = isolate->debug();
1867
  Zone zone(isolate);
1868
  Vector<StackFrame*> frames = CreateStackMap(isolate, &zone);
1869

    
1870

    
1871
  int top_frame_index = -1;
1872
  int frame_index = 0;
1873
  for (; frame_index < frames.length(); frame_index++) {
1874
    StackFrame* frame = frames[frame_index];
1875
    if (frame->id() == debug->break_frame_id()) {
1876
      top_frame_index = frame_index;
1877
      break;
1878
    }
1879
    if (target.MatchActivation(
1880
            frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
1881
      // We are still above break_frame. It is not a target frame,
1882
      // it is a problem.
1883
      return "Debugger mark-up on stack is not found";
1884
    }
1885
  }
1886

    
1887
  if (top_frame_index == -1) {
1888
    // We haven't found break frame, but no function is blocking us anyway.
1889
    return target.GetNotFoundMessage();
1890
  }
1891

    
1892
  bool target_frame_found = false;
1893
  int bottom_js_frame_index = top_frame_index;
1894
  bool c_code_found = false;
1895

    
1896
  for (; frame_index < frames.length(); frame_index++) {
1897
    StackFrame* frame = frames[frame_index];
1898
    if (!IsDropableFrame(frame)) {
1899
      c_code_found = true;
1900
      break;
1901
    }
1902
    if (target.MatchActivation(
1903
            frame, LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
1904
      target_frame_found = true;
1905
      bottom_js_frame_index = frame_index;
1906
    }
1907
  }
1908

    
1909
  if (c_code_found) {
1910
    // There is a C frames on stack. Check that there are no target frames
1911
    // below them.
1912
    for (; frame_index < frames.length(); frame_index++) {
1913
      StackFrame* frame = frames[frame_index];
1914
      if (frame->is_java_script()) {
1915
        if (target.MatchActivation(
1916
                frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
1917
          // Cannot drop frame under C frames.
1918
          return NULL;
1919
        }
1920
      }
1921
    }
1922
  }
1923

    
1924
  if (!do_drop) {
1925
    // We are in check-only mode.
1926
    return NULL;
1927
  }
1928

    
1929
  if (!target_frame_found) {
1930
    // Nothing to drop.
1931
    return target.GetNotFoundMessage();
1932
  }
1933

    
1934
  Debug::FrameDropMode drop_mode = Debug::FRAMES_UNTOUCHED;
1935
  Object** restarter_frame_function_pointer = NULL;
1936
  const char* error_message = DropFrames(frames, top_frame_index,
1937
                                         bottom_js_frame_index, &drop_mode,
1938
                                         &restarter_frame_function_pointer);
1939

    
1940
  if (error_message != NULL) {
1941
    return error_message;
1942
  }
1943

    
1944
  // Adjust break_frame after some frames has been dropped.
1945
  StackFrame::Id new_id = StackFrame::NO_ID;
1946
  for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) {
1947
    if (frames[i]->type() == StackFrame::JAVA_SCRIPT) {
1948
      new_id = frames[i]->id();
1949
      break;
1950
    }
1951
  }
1952
  debug->FramesHaveBeenDropped(new_id, drop_mode,
1953
                               restarter_frame_function_pointer);
1954
  return NULL;
1955
}
1956

    
1957

    
1958
// Fills result array with statuses of functions. Modifies the stack
1959
// removing all listed function if possible and if do_drop is true.
1960
static const char* DropActivationsInActiveThread(
1961
    Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop) {
1962
  MultipleFunctionTarget target(shared_info_array, result);
1963

    
1964
  const char* message = DropActivationsInActiveThreadImpl(
1965
      shared_info_array->GetIsolate(), target, do_drop);
1966
  if (message) {
1967
    return message;
1968
  }
1969

    
1970
  Isolate* isolate = shared_info_array->GetIsolate();
1971
  int array_len = GetArrayLength(shared_info_array);
1972

    
1973
  // Replace "blocked on active" with "replaced on active" status.
1974
  for (int i = 0; i < array_len; i++) {
1975
    if (result->GetElement(result->GetIsolate(), i) ==
1976
        Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
1977
      Handle<Object> replaced(
1978
          Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK), isolate);
1979
      SetElementNonStrict(result, i, replaced);
1980
    }
1981
  }
1982
  return NULL;
1983
}
1984

    
1985

    
1986
class InactiveThreadActivationsChecker : public ThreadVisitor {
1987
 public:
1988
  InactiveThreadActivationsChecker(Handle<JSArray> shared_info_array,
1989
                                   Handle<JSArray> result)
1990
      : shared_info_array_(shared_info_array), result_(result),
1991
        has_blocked_functions_(false) {
1992
  }
1993
  void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1994
    for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1995
      has_blocked_functions_ |= CheckActivation(
1996
          shared_info_array_, result_, it.frame(),
1997
          LiveEdit::FUNCTION_BLOCKED_ON_OTHER_STACK);
1998
    }
1999
  }
2000
  bool HasBlockedFunctions() {
2001
    return has_blocked_functions_;
2002
  }
2003

    
2004
 private:
2005
  Handle<JSArray> shared_info_array_;
2006
  Handle<JSArray> result_;
2007
  bool has_blocked_functions_;
2008
};
2009

    
2010

    
2011
Handle<JSArray> LiveEdit::CheckAndDropActivations(
2012
    Handle<JSArray> shared_info_array, bool do_drop) {
2013
  Isolate* isolate = shared_info_array->GetIsolate();
2014
  int len = GetArrayLength(shared_info_array);
2015

    
2016
  Handle<JSArray> result = isolate->factory()->NewJSArray(len);
2017

    
2018
  // Fill the default values.
2019
  for (int i = 0; i < len; i++) {
2020
    SetElementNonStrict(
2021
        result,
2022
        i,
2023
        Handle<Smi>(Smi::FromInt(FUNCTION_AVAILABLE_FOR_PATCH), isolate));
2024
  }
2025

    
2026

    
2027
  // First check inactive threads. Fail if some functions are blocked there.
2028
  InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array,
2029
                                                            result);
2030
  isolate->thread_manager()->IterateArchivedThreads(
2031
      &inactive_threads_checker);
2032
  if (inactive_threads_checker.HasBlockedFunctions()) {
2033
    return result;
2034
  }
2035

    
2036
  // Try to drop activations from the current stack.
2037
  const char* error_message =
2038
      DropActivationsInActiveThread(shared_info_array, result, do_drop);
2039
  if (error_message != NULL) {
2040
    // Add error message as an array extra element.
2041
    Vector<const char> vector_message(error_message, StrLength(error_message));
2042
    Handle<String> str = isolate->factory()->NewStringFromAscii(vector_message);
2043
    SetElementNonStrict(result, len, str);
2044
  }
2045
  return result;
2046
}
2047

    
2048

    
2049
// Describes a single callframe a target. Not finding this frame
2050
// means an error.
2051
class SingleFrameTarget {
2052
 public:
2053
  explicit SingleFrameTarget(JavaScriptFrame* frame)
2054
      : m_frame(frame),
2055
        m_saved_status(LiveEdit::FUNCTION_AVAILABLE_FOR_PATCH) {}
2056

    
2057
  bool MatchActivation(StackFrame* frame,
2058
      LiveEdit::FunctionPatchabilityStatus status) {
2059
    if (frame->fp() == m_frame->fp()) {
2060
      m_saved_status = status;
2061
      return true;
2062
    }
2063
    return false;
2064
  }
2065
  const char* GetNotFoundMessage() {
2066
    return "Failed to found requested frame";
2067
  }
2068
  LiveEdit::FunctionPatchabilityStatus saved_status() {
2069
    return m_saved_status;
2070
  }
2071
 private:
2072
  JavaScriptFrame* m_frame;
2073
  LiveEdit::FunctionPatchabilityStatus m_saved_status;
2074
};
2075

    
2076

    
2077
// Finds a drops required frame and all frames above.
2078
// Returns error message or NULL.
2079
const char* LiveEdit::RestartFrame(JavaScriptFrame* frame) {
2080
  SingleFrameTarget target(frame);
2081

    
2082
  const char* result = DropActivationsInActiveThreadImpl(
2083
      frame->isolate(), target, true);
2084
  if (result != NULL) {
2085
    return result;
2086
  }
2087
  if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE) {
2088
    return "Function is blocked under native code";
2089
  }
2090
  return NULL;
2091
}
2092

    
2093

    
2094
LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
2095
                                                 FunctionLiteral* fun)
2096
    : isolate_(isolate) {
2097
  if (isolate_->active_function_info_listener() != NULL) {
2098
    isolate_->active_function_info_listener()->FunctionStarted(fun);
2099
  }
2100
}
2101

    
2102

    
2103
LiveEditFunctionTracker::~LiveEditFunctionTracker() {
2104
  if (isolate_->active_function_info_listener() != NULL) {
2105
    isolate_->active_function_info_listener()->FunctionDone();
2106
  }
2107
}
2108

    
2109

    
2110
void LiveEditFunctionTracker::RecordFunctionInfo(
2111
    Handle<SharedFunctionInfo> info, FunctionLiteral* lit,
2112
    Zone* zone) {
2113
  if (isolate_->active_function_info_listener() != NULL) {
2114
    isolate_->active_function_info_listener()->FunctionInfo(info, lit->scope(),
2115
                                                            zone);
2116
  }
2117
}
2118

    
2119

    
2120
void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
2121
  isolate_->active_function_info_listener()->FunctionCode(code);
2122
}
2123

    
2124

    
2125
bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
2126
  return isolate->active_function_info_listener() != NULL;
2127
}
2128

    
2129

    
2130
#else  // ENABLE_DEBUGGER_SUPPORT
2131

    
2132
// This ifdef-else-endif section provides working or stub implementation of
2133
// LiveEditFunctionTracker.
2134
LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
2135
                                                 FunctionLiteral* fun) {
2136
}
2137

    
2138

    
2139
LiveEditFunctionTracker::~LiveEditFunctionTracker() {
2140
}
2141

    
2142

    
2143
void LiveEditFunctionTracker::RecordFunctionInfo(
2144
    Handle<SharedFunctionInfo> info, FunctionLiteral* lit,
2145
    Zone* zone) {
2146
}
2147

    
2148

    
2149
void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
2150
}
2151

    
2152

    
2153
bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
2154
  return false;
2155
}
2156

    
2157
#endif  // ENABLE_DEBUGGER_SUPPORT
2158

    
2159

    
2160

    
2161
} }  // namespace v8::internal