~evarlast/ubuntu/utopic/mongodb/upstart-workaround-debian-bug-718702

« back to all changes in this revision

Viewing changes to src/third_party/v8/src/liveedit.cc

  • Committer: Package Import Robot
  • Author(s): James Page, James Page, Robie Basak
  • Date: 2013-05-29 17:44:42 UTC
  • mfrom: (44.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20130529174442-z0a4qmoww4y0t458
Tags: 1:2.4.3-1ubuntu1
[ James Page ]
* Merge from Debian unstable, remaining changes:
  - Enable SSL support:
    + d/control: Add libssl-dev to BD's.
    + d/rules: Enabled --ssl option.
    + d/mongodb.conf: Add example SSL configuration options.
  - d/mongodb-server.mongodb.upstart: Add upstart configuration.
  - d/rules: Don't strip binaries during scons build for Ubuntu.
  - d/control: Add armhf to target archs.
  - d/p/SConscript.client.patch: fixup install of client libraries.
  - d/p/0010-install-libs-to-usr-lib-not-usr-lib64-Closes-588557.patch:
    Install libraries to lib not lib64.
* Dropped changes:
  - d/p/arm-support.patch: Included in Debian.
  - d/p/double-alignment.patch: Included in Debian.
  - d/rules,control: Debian also builds with avaliable system libraries
    now.
* Fix FTBFS due to gcc and boost upgrades in saucy:
  - d/p/0008-ignore-unused-local-typedefs.patch: Add -Wno-unused-typedefs
    to unbreak building with g++-4.8.
  - d/p/0009-boost-1.53.patch: Fixup signed/unsigned casting issue.

[ Robie Basak ]
* d/p/0011-Use-a-signed-char-to-store-BSONType-enumerations.patch: Fixup
  build failure on ARM due to missing signed'ness of char cast.

Show diffs side-by-side

added added

removed removed

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