blob: 3ec2da33270abd1a0b48d49d7ca99da2e2c8c158 [file] [log] [blame]
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +00002// 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"
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000032
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000033#include "code-stubs.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000034#include "compilation-cache.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000035#include "compiler.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000036#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "deoptimizer.h"
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000038#include "global-handles.h"
mmassi@chromium.org49a44672012-12-04 13:52:03 +000039#include "messages.h"
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000040#include "parser.h"
41#include "scopeinfo.h"
42#include "scopes.h"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000043#include "v8memory.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000044
45namespace v8 {
46namespace internal {
47
48
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000049#ifdef ENABLE_DEBUGGER_SUPPORT
50
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000051
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000052void 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.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000058 Handle<Object> no_failure =
59 JSObject::SetElement(object, index, value, NONE, kNonStrictMode);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000060 ASSERT(!no_failure.is_null());
61 USE(no_failure);
62}
63
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000064// A simple implementation of dynamic programming algorithm. It solves
65// the problem of finding the difference of 2 arrays. It uses a table of results
66// of subproblems. Each cell contains a number together with 2-bit flag
67// that helps building the chunk list.
68class Differencer {
69 public:
lrn@chromium.orgc34f5802010-04-28 12:53:43 +000070 explicit Differencer(Comparator::Input* input)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000071 : input_(input), len1_(input->GetLength1()), len2_(input->GetLength2()) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000072 buffer_ = NewArray<int>(len1_ * len2_);
73 }
74 ~Differencer() {
75 DeleteArray(buffer_);
76 }
77
78 void Initialize() {
79 int array_size = len1_ * len2_;
80 for (int i = 0; i < array_size; i++) {
81 buffer_[i] = kEmptyCellValue;
82 }
83 }
84
85 // Makes sure that result for the full problem is calculated and stored
86 // in the table together with flags showing a path through subproblems.
87 void FillTable() {
88 CompareUpToTail(0, 0);
89 }
90
lrn@chromium.orgc34f5802010-04-28 12:53:43 +000091 void SaveResult(Comparator::Output* chunk_writer) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000092 ResultWriter writer(chunk_writer);
93
94 int pos1 = 0;
95 int pos2 = 0;
96 while (true) {
97 if (pos1 < len1_) {
98 if (pos2 < len2_) {
99 Direction dir = get_direction(pos1, pos2);
100 switch (dir) {
101 case EQ:
102 writer.eq();
103 pos1++;
104 pos2++;
105 break;
106 case SKIP1:
107 writer.skip1(1);
108 pos1++;
109 break;
110 case SKIP2:
111 case SKIP_ANY:
112 writer.skip2(1);
113 pos2++;
114 break;
115 default:
116 UNREACHABLE();
117 }
118 } else {
119 writer.skip1(len1_ - pos1);
120 break;
121 }
122 } else {
123 if (len2_ != pos2) {
124 writer.skip2(len2_ - pos2);
125 }
126 break;
127 }
128 }
129 writer.close();
130 }
131
132 private:
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000133 Comparator::Input* input_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000134 int* buffer_;
135 int len1_;
136 int len2_;
137
138 enum Direction {
139 EQ = 0,
140 SKIP1,
141 SKIP2,
142 SKIP_ANY,
143
144 MAX_DIRECTION_FLAG_VALUE = SKIP_ANY
145 };
146
147 // Computes result for a subtask and optionally caches it in the buffer table.
148 // All results values are shifted to make space for flags in the lower bits.
149 int CompareUpToTail(int pos1, int pos2) {
150 if (pos1 < len1_) {
151 if (pos2 < len2_) {
152 int cached_res = get_value4(pos1, pos2);
153 if (cached_res == kEmptyCellValue) {
154 Direction dir;
155 int res;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000156 if (input_->Equals(pos1, pos2)) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000157 res = CompareUpToTail(pos1 + 1, pos2 + 1);
158 dir = EQ;
159 } else {
160 int res1 = CompareUpToTail(pos1 + 1, pos2) +
161 (1 << kDirectionSizeBits);
162 int res2 = CompareUpToTail(pos1, pos2 + 1) +
163 (1 << kDirectionSizeBits);
164 if (res1 == res2) {
165 res = res1;
166 dir = SKIP_ANY;
167 } else if (res1 < res2) {
168 res = res1;
169 dir = SKIP1;
170 } else {
171 res = res2;
172 dir = SKIP2;
173 }
174 }
175 set_value4_and_dir(pos1, pos2, res, dir);
176 cached_res = res;
177 }
178 return cached_res;
179 } else {
180 return (len1_ - pos1) << kDirectionSizeBits;
181 }
182 } else {
183 return (len2_ - pos2) << kDirectionSizeBits;
184 }
185 }
186
187 inline int& get_cell(int i1, int i2) {
188 return buffer_[i1 + i2 * len1_];
189 }
190
191 // Each cell keeps a value plus direction. Value is multiplied by 4.
192 void set_value4_and_dir(int i1, int i2, int value4, Direction dir) {
193 ASSERT((value4 & kDirectionMask) == 0);
194 get_cell(i1, i2) = value4 | dir;
195 }
196
197 int get_value4(int i1, int i2) {
198 return get_cell(i1, i2) & (kMaxUInt32 ^ kDirectionMask);
199 }
200 Direction get_direction(int i1, int i2) {
201 return static_cast<Direction>(get_cell(i1, i2) & kDirectionMask);
202 }
203
204 static const int kDirectionSizeBits = 2;
205 static const int kDirectionMask = (1 << kDirectionSizeBits) - 1;
206 static const int kEmptyCellValue = -1 << kDirectionSizeBits;
207
208 // This method only holds static assert statement (unfortunately you cannot
209 // place one in class scope).
210 void StaticAssertHolder() {
211 STATIC_ASSERT(MAX_DIRECTION_FLAG_VALUE < (1 << kDirectionSizeBits));
212 }
213
214 class ResultWriter {
215 public:
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000216 explicit ResultWriter(Comparator::Output* chunk_writer)
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000217 : chunk_writer_(chunk_writer), pos1_(0), pos2_(0),
218 pos1_begin_(-1), pos2_begin_(-1), has_open_chunk_(false) {
219 }
220 void eq() {
221 FlushChunk();
222 pos1_++;
223 pos2_++;
224 }
225 void skip1(int len1) {
226 StartChunk();
227 pos1_ += len1;
228 }
229 void skip2(int len2) {
230 StartChunk();
231 pos2_ += len2;
232 }
233 void close() {
234 FlushChunk();
235 }
236
237 private:
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000238 Comparator::Output* chunk_writer_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000239 int pos1_;
240 int pos2_;
241 int pos1_begin_;
242 int pos2_begin_;
243 bool has_open_chunk_;
244
245 void StartChunk() {
246 if (!has_open_chunk_) {
247 pos1_begin_ = pos1_;
248 pos2_begin_ = pos2_;
249 has_open_chunk_ = true;
250 }
251 }
252
253 void FlushChunk() {
254 if (has_open_chunk_) {
255 chunk_writer_->AddChunk(pos1_begin_, pos2_begin_,
256 pos1_ - pos1_begin_, pos2_ - pos2_begin_);
257 has_open_chunk_ = false;
258 }
259 }
260 };
261};
262
263
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000264void Comparator::CalculateDifference(Comparator::Input* input,
265 Comparator::Output* result_writer) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000266 Differencer differencer(input);
267 differencer.Initialize();
268 differencer.FillTable();
269 differencer.SaveResult(result_writer);
270}
271
272
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000273static bool CompareSubstrings(Handle<String> s1, int pos1,
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000274 Handle<String> s2, int pos2, int len) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000275 for (int i = 0; i < len; i++) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000276 if (s1->Get(i + pos1) != s2->Get(i + pos2)) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000277 return false;
278 }
279 }
280 return true;
281}
282
283
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000284// Additional to Input interface. Lets switch Input range to subrange.
285// More elegant way would be to wrap one Input as another Input object
286// and translate positions there, but that would cost us additional virtual
287// call per comparison.
288class SubrangableInput : public Comparator::Input {
289 public:
290 virtual void SetSubrange1(int offset, int len) = 0;
291 virtual void SetSubrange2(int offset, int len) = 0;
292};
293
294
295class SubrangableOutput : public Comparator::Output {
296 public:
297 virtual void SetSubrange1(int offset, int len) = 0;
298 virtual void SetSubrange2(int offset, int len) = 0;
299};
300
301
302static int min(int a, int b) {
303 return a < b ? a : b;
304}
305
306
307// Finds common prefix and suffix in input. This parts shouldn't take space in
308// linear programming table. Enable subranging in input and output.
309static void NarrowDownInput(SubrangableInput* input,
310 SubrangableOutput* output) {
311 const int len1 = input->GetLength1();
312 const int len2 = input->GetLength2();
313
314 int common_prefix_len;
315 int common_suffix_len;
316
317 {
318 common_prefix_len = 0;
319 int prefix_limit = min(len1, len2);
320 while (common_prefix_len < prefix_limit &&
321 input->Equals(common_prefix_len, common_prefix_len)) {
322 common_prefix_len++;
323 }
324
325 common_suffix_len = 0;
326 int suffix_limit = min(len1 - common_prefix_len, len2 - common_prefix_len);
327
328 while (common_suffix_len < suffix_limit &&
329 input->Equals(len1 - common_suffix_len - 1,
330 len2 - common_suffix_len - 1)) {
331 common_suffix_len++;
332 }
333 }
334
335 if (common_prefix_len > 0 || common_suffix_len > 0) {
336 int new_len1 = len1 - common_suffix_len - common_prefix_len;
337 int new_len2 = len2 - common_suffix_len - common_prefix_len;
338
339 input->SetSubrange1(common_prefix_len, new_len1);
340 input->SetSubrange2(common_prefix_len, new_len2);
341
342 output->SetSubrange1(common_prefix_len, new_len1);
343 output->SetSubrange2(common_prefix_len, new_len2);
344 }
345}
346
347
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000348// A helper class that writes chunk numbers into JSArray.
349// Each chunk is stored as 3 array elements: (pos1_begin, pos1_end, pos2_end).
350class CompareOutputArrayWriter {
351 public:
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000352 explicit CompareOutputArrayWriter(Isolate* isolate)
353 : array_(isolate->factory()->NewJSArray(10)), current_size_(0) {}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000354
355 Handle<JSArray> GetResult() {
356 return array_;
357 }
358
359 void WriteChunk(int char_pos1, int char_pos2, int char_len1, int char_len2) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000360 Isolate* isolate = array_->GetIsolate();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000361 SetElementNonStrict(array_,
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000362 current_size_,
363 Handle<Object>(Smi::FromInt(char_pos1), isolate));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000364 SetElementNonStrict(array_,
365 current_size_ + 1,
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000366 Handle<Object>(Smi::FromInt(char_pos1 + char_len1),
367 isolate));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000368 SetElementNonStrict(array_,
369 current_size_ + 2,
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000370 Handle<Object>(Smi::FromInt(char_pos2 + char_len2),
371 isolate));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000372 current_size_ += 3;
373 }
374
375 private:
376 Handle<JSArray> array_;
377 int current_size_;
378};
379
380
381// Represents 2 strings as 2 arrays of tokens.
382// TODO(LiveEdit): Currently it's actually an array of charactres.
383// Make array of tokens instead.
384class TokensCompareInput : public Comparator::Input {
385 public:
386 TokensCompareInput(Handle<String> s1, int offset1, int len1,
387 Handle<String> s2, int offset2, int len2)
388 : s1_(s1), offset1_(offset1), len1_(len1),
389 s2_(s2), offset2_(offset2), len2_(len2) {
390 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000391 virtual int GetLength1() {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000392 return len1_;
393 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000394 virtual int GetLength2() {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000395 return len2_;
396 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000397 bool Equals(int index1, int index2) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000398 return s1_->Get(offset1_ + index1) == s2_->Get(offset2_ + index2);
399 }
400
401 private:
402 Handle<String> s1_;
403 int offset1_;
404 int len1_;
405 Handle<String> s2_;
406 int offset2_;
407 int len2_;
408};
409
410
411// Stores compare result in JSArray. Converts substring positions
412// to absolute positions.
413class TokensCompareOutput : public Comparator::Output {
414 public:
415 TokensCompareOutput(CompareOutputArrayWriter* array_writer,
416 int offset1, int offset2)
417 : array_writer_(array_writer), offset1_(offset1), offset2_(offset2) {
418 }
419
420 void AddChunk(int pos1, int pos2, int len1, int len2) {
421 array_writer_->WriteChunk(pos1 + offset1_, pos2 + offset2_, len1, len2);
422 }
423
424 private:
425 CompareOutputArrayWriter* array_writer_;
426 int offset1_;
427 int offset2_;
428};
429
430
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000431// Wraps raw n-elements line_ends array as a list of n+1 lines. The last line
432// never has terminating new line character.
433class LineEndsWrapper {
434 public:
435 explicit LineEndsWrapper(Handle<String> string)
436 : ends_array_(CalculateLineEnds(string, false)),
437 string_len_(string->length()) {
438 }
439 int length() {
440 return ends_array_->length() + 1;
441 }
442 // Returns start for any line including start of the imaginary line after
443 // the last line.
444 int GetLineStart(int index) {
445 if (index == 0) {
446 return 0;
447 } else {
448 return GetLineEnd(index - 1);
449 }
450 }
451 int GetLineEnd(int index) {
452 if (index == ends_array_->length()) {
453 // End of the last line is always an end of the whole string.
454 // If the string ends with a new line character, the last line is an
455 // empty string after this character.
456 return string_len_;
457 } else {
458 return GetPosAfterNewLine(index);
459 }
460 }
461
462 private:
463 Handle<FixedArray> ends_array_;
464 int string_len_;
465
466 int GetPosAfterNewLine(int index) {
467 return Smi::cast(ends_array_->get(index))->value() + 1;
468 }
469};
470
471
472// Represents 2 strings as 2 arrays of lines.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000473class LineArrayCompareInput : public SubrangableInput {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000474 public:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000475 LineArrayCompareInput(Handle<String> s1, Handle<String> s2,
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000476 LineEndsWrapper line_ends1, LineEndsWrapper line_ends2)
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000477 : s1_(s1), s2_(s2), line_ends1_(line_ends1),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000478 line_ends2_(line_ends2),
479 subrange_offset1_(0), subrange_offset2_(0),
480 subrange_len1_(line_ends1_.length()),
481 subrange_len2_(line_ends2_.length()) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000482 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000483 int GetLength1() {
484 return subrange_len1_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000485 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000486 int GetLength2() {
487 return subrange_len2_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000488 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000489 bool Equals(int index1, int index2) {
490 index1 += subrange_offset1_;
491 index2 += subrange_offset2_;
492
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000493 int line_start1 = line_ends1_.GetLineStart(index1);
494 int line_start2 = line_ends2_.GetLineStart(index2);
495 int line_end1 = line_ends1_.GetLineEnd(index1);
496 int line_end2 = line_ends2_.GetLineEnd(index2);
497 int len1 = line_end1 - line_start1;
498 int len2 = line_end2 - line_start2;
499 if (len1 != len2) {
500 return false;
501 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000502 return CompareSubstrings(s1_, line_start1, s2_, line_start2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000503 len1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000504 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000505 void SetSubrange1(int offset, int len) {
506 subrange_offset1_ = offset;
507 subrange_len1_ = len;
508 }
509 void SetSubrange2(int offset, int len) {
510 subrange_offset2_ = offset;
511 subrange_len2_ = len;
512 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000513
514 private:
515 Handle<String> s1_;
516 Handle<String> s2_;
517 LineEndsWrapper line_ends1_;
518 LineEndsWrapper line_ends2_;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000519 int subrange_offset1_;
520 int subrange_offset2_;
521 int subrange_len1_;
522 int subrange_len2_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000523};
524
525
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000526// Stores compare result in JSArray. For each chunk tries to conduct
527// a fine-grained nested diff token-wise.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000528class TokenizingLineArrayCompareOutput : public SubrangableOutput {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000529 public:
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000530 TokenizingLineArrayCompareOutput(LineEndsWrapper line_ends1,
531 LineEndsWrapper line_ends2,
532 Handle<String> s1, Handle<String> s2)
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000533 : array_writer_(s1->GetIsolate()),
534 line_ends1_(line_ends1), line_ends2_(line_ends2), s1_(s1), s2_(s2),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000535 subrange_offset1_(0), subrange_offset2_(0) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000536 }
537
538 void AddChunk(int line_pos1, int line_pos2, int line_len1, int line_len2) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000539 line_pos1 += subrange_offset1_;
540 line_pos2 += subrange_offset2_;
541
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000542 int char_pos1 = line_ends1_.GetLineStart(line_pos1);
543 int char_pos2 = line_ends2_.GetLineStart(line_pos2);
544 int char_len1 = line_ends1_.GetLineStart(line_pos1 + line_len1) - char_pos1;
545 int char_len2 = line_ends2_.GetLineStart(line_pos2 + line_len2) - char_pos2;
546
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000547 if (char_len1 < CHUNK_LEN_LIMIT && char_len2 < CHUNK_LEN_LIMIT) {
548 // Chunk is small enough to conduct a nested token-level diff.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000549 HandleScope subTaskScope(s1_->GetIsolate());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000550
551 TokensCompareInput tokens_input(s1_, char_pos1, char_len1,
552 s2_, char_pos2, char_len2);
553 TokensCompareOutput tokens_output(&array_writer_, char_pos1,
554 char_pos2);
555
556 Comparator::CalculateDifference(&tokens_input, &tokens_output);
557 } else {
558 array_writer_.WriteChunk(char_pos1, char_pos2, char_len1, char_len2);
559 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000560 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000561 void SetSubrange1(int offset, int len) {
562 subrange_offset1_ = offset;
563 }
564 void SetSubrange2(int offset, int len) {
565 subrange_offset2_ = offset;
566 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000567
568 Handle<JSArray> GetResult() {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000569 return array_writer_.GetResult();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000570 }
571
572 private:
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000573 static const int CHUNK_LEN_LIMIT = 800;
574
575 CompareOutputArrayWriter array_writer_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000576 LineEndsWrapper line_ends1_;
577 LineEndsWrapper line_ends2_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000578 Handle<String> s1_;
579 Handle<String> s2_;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000580 int subrange_offset1_;
581 int subrange_offset2_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000582};
583
584
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000585Handle<JSArray> LiveEdit::CompareStrings(Handle<String> s1,
586 Handle<String> s2) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000587 s1 = FlattenGetString(s1);
588 s2 = FlattenGetString(s2);
589
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000590 LineEndsWrapper line_ends1(s1);
591 LineEndsWrapper line_ends2(s2);
592
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000593 LineArrayCompareInput input(s1, s2, line_ends1, line_ends2);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000594 TokenizingLineArrayCompareOutput output(line_ends1, line_ends2, s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000595
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000596 NarrowDownInput(&input, &output);
597
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000598 Comparator::CalculateDifference(&input, &output);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000599
600 return output.GetResult();
601}
602
603
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000604static void CompileScriptForTracker(Isolate* isolate, Handle<Script> script) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000605 // TODO(635): support extensions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000606 PostponeInterruptsScope postpone(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000607
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000608 // Build AST.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000609 CompilationInfoWithZone info(script);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000610 info.MarkAsGlobal();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000611 // Parse and don't allow skipping lazy functions.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000612 if (Parser::Parse(&info)) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000613 // Compile the code.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 LiveEditFunctionTracker tracker(info.isolate(), info.function());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000615 if (Compiler::MakeCodeForLiveEdit(&info)) {
616 ASSERT(!info.code().is_null());
617 tracker.RecordRootFunctionInfo(info.code());
618 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 info.isolate()->StackOverflow();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000620 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000621 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000622}
623
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000624
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000625// Unwraps JSValue object, returning its field "value"
626static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000627 return Handle<Object>(jsValue->value(), jsValue->GetIsolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000628}
629
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000630
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000631// Wraps any object into a OpaqueReference, that will hide the object
632// from JavaScript.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000633static Handle<JSValue> WrapInJSValue(Handle<Object> object) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000634 Isolate* isolate = Isolate::Current();
635 Handle<JSFunction> constructor = isolate->opaque_reference_function();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000636 Handle<JSValue> result =
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000637 Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000638 result->set_value(*object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000639 return result;
640}
641
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000642
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000643static Handle<SharedFunctionInfo> UnwrapSharedFunctionInfoFromJSValue(
644 Handle<JSValue> jsValue) {
645 Object* shared = jsValue->value();
646 CHECK(shared->IsSharedFunctionInfo());
647 return Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(shared));
648}
649
650
651static int GetArrayLength(Handle<JSArray> array) {
652 Object* length = array->length();
653 CHECK(length->IsSmi());
654 return Smi::cast(length)->value();
655}
656
657
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000658// Simple helper class that creates more or less typed structures over
659// JSArray object. This is an adhoc method of passing structures from C++
660// to JavaScript.
661template<typename S>
662class JSArrayBasedStruct {
663 public:
664 static S Create() {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000665 Factory* factory = Isolate::Current()->factory();
666 Handle<JSArray> array = factory->NewJSArray(S::kSize_);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000667 return S(array);
668 }
669 static S cast(Object* object) {
670 JSArray* array = JSArray::cast(object);
671 Handle<JSArray> array_handle(array);
672 return S(array_handle);
673 }
674 explicit JSArrayBasedStruct(Handle<JSArray> array) : array_(array) {
675 }
676 Handle<JSArray> GetJSArray() {
677 return array_;
678 }
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000679 Isolate* isolate() const {
680 return array_->GetIsolate();
681 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000682
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000683 protected:
684 void SetField(int field_position, Handle<Object> value) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000685 SetElementNonStrict(array_, field_position, value);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000686 }
687 void SetSmiValueField(int field_position, int value) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000688 SetElementNonStrict(array_,
689 field_position,
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000690 Handle<Smi>(Smi::FromInt(value), isolate()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000691 }
692 Object* GetField(int field_position) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000693 return array_->GetElementNoExceptionThrown(field_position);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000694 }
695 int GetSmiValueField(int field_position) {
696 Object* res = GetField(field_position);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000697 CHECK(res->IsSmi());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000698 return Smi::cast(res)->value();
699 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000700
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000701 private:
702 Handle<JSArray> array_;
703};
704
705
706// Represents some function compilation details. This structure will be used
707// from JavaScript. It contains Code object, which is kept wrapped
708// into a BlindReference for sanitizing reasons.
709class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
710 public:
711 explicit FunctionInfoWrapper(Handle<JSArray> array)
712 : JSArrayBasedStruct<FunctionInfoWrapper>(array) {
713 }
714 void SetInitialProperties(Handle<String> name, int start_position,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000715 int end_position, int param_num,
716 int literal_count, int parent_index) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000717 HandleScope scope(isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000718 this->SetField(kFunctionNameOffset_, name);
719 this->SetSmiValueField(kStartPositionOffset_, start_position);
720 this->SetSmiValueField(kEndPositionOffset_, end_position);
721 this->SetSmiValueField(kParamNumOffset_, param_num);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000722 this->SetSmiValueField(kLiteralNumOffset_, literal_count);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000723 this->SetSmiValueField(kParentIndexOffset_, parent_index);
724 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000725 void SetFunctionCode(Handle<Code> function_code,
726 Handle<Object> code_scope_info) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000727 Handle<JSValue> code_wrapper = WrapInJSValue(function_code);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000728 this->SetField(kCodeOffset_, code_wrapper);
729
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000730 Handle<JSValue> scope_wrapper = WrapInJSValue(code_scope_info);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000731 this->SetField(kCodeScopeInfoOffset_, scope_wrapper);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000732 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000733 void SetOuterScopeInfo(Handle<Object> scope_info_array) {
734 this->SetField(kOuterScopeInfoOffset_, scope_info_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000735 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000736 void SetSharedFunctionInfo(Handle<SharedFunctionInfo> info) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000737 Handle<JSValue> info_holder = WrapInJSValue(info);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000738 this->SetField(kSharedFunctionInfoOffset_, info_holder);
739 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000740 int GetLiteralCount() {
741 return this->GetSmiValueField(kLiteralNumOffset_);
742 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000743 int GetParentIndex() {
744 return this->GetSmiValueField(kParentIndexOffset_);
745 }
746 Handle<Code> GetFunctionCode() {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000747 Object* element = this->GetField(kCodeOffset_);
748 CHECK(element->IsJSValue());
749 Handle<JSValue> value_wrapper(JSValue::cast(element));
750 Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
751 CHECK(raw_result->IsCode());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000752 return Handle<Code>::cast(raw_result);
753 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000754 Handle<Object> GetCodeScopeInfo() {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000755 Object* element = this->GetField(kCodeScopeInfoOffset_);
756 CHECK(element->IsJSValue());
757 return UnwrapJSValue(Handle<JSValue>(JSValue::cast(element)));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000758 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000759 int GetStartPosition() {
760 return this->GetSmiValueField(kStartPositionOffset_);
761 }
762 int GetEndPosition() {
763 return this->GetSmiValueField(kEndPositionOffset_);
764 }
765
766 private:
767 static const int kFunctionNameOffset_ = 0;
768 static const int kStartPositionOffset_ = 1;
769 static const int kEndPositionOffset_ = 2;
770 static const int kParamNumOffset_ = 3;
771 static const int kCodeOffset_ = 4;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000772 static const int kCodeScopeInfoOffset_ = 5;
773 static const int kOuterScopeInfoOffset_ = 6;
774 static const int kParentIndexOffset_ = 7;
775 static const int kSharedFunctionInfoOffset_ = 8;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000776 static const int kLiteralNumOffset_ = 9;
777 static const int kSize_ = 10;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000778
779 friend class JSArrayBasedStruct<FunctionInfoWrapper>;
780};
781
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000782
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000783// Wraps SharedFunctionInfo along with some of its fields for passing it
784// back to JavaScript. SharedFunctionInfo object itself is additionally
785// wrapped into BlindReference for sanitizing reasons.
786class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> {
787 public:
ager@chromium.orgac091b72010-05-05 07:34:42 +0000788 static bool IsInstance(Handle<JSArray> array) {
789 return array->length() == Smi::FromInt(kSize_) &&
lrn@chromium.org303ada72010-10-27 09:33:13 +0000790 array->GetElementNoExceptionThrown(kSharedInfoOffset_)->IsJSValue();
ager@chromium.orgac091b72010-05-05 07:34:42 +0000791 }
792
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000793 explicit SharedInfoWrapper(Handle<JSArray> array)
794 : JSArrayBasedStruct<SharedInfoWrapper>(array) {
795 }
796
797 void SetProperties(Handle<String> name, int start_position, int end_position,
798 Handle<SharedFunctionInfo> info) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000799 HandleScope scope(isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000800 this->SetField(kFunctionNameOffset_, name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000801 Handle<JSValue> info_holder = WrapInJSValue(info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000802 this->SetField(kSharedInfoOffset_, info_holder);
803 this->SetSmiValueField(kStartPositionOffset_, start_position);
804 this->SetSmiValueField(kEndPositionOffset_, end_position);
805 }
806 Handle<SharedFunctionInfo> GetInfo() {
807 Object* element = this->GetField(kSharedInfoOffset_);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000808 CHECK(element->IsJSValue());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000809 Handle<JSValue> value_wrapper(JSValue::cast(element));
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000810 return UnwrapSharedFunctionInfoFromJSValue(value_wrapper);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000811 }
812
813 private:
814 static const int kFunctionNameOffset_ = 0;
815 static const int kStartPositionOffset_ = 1;
816 static const int kEndPositionOffset_ = 2;
817 static const int kSharedInfoOffset_ = 3;
818 static const int kSize_ = 4;
819
820 friend class JSArrayBasedStruct<SharedInfoWrapper>;
821};
822
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000823
ager@chromium.org5c838252010-02-19 08:53:10 +0000824class FunctionInfoListener {
825 public:
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000826 explicit FunctionInfoListener(Isolate* isolate) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000827 current_parent_index_ = -1;
828 len_ = 0;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000829 result_ = isolate->factory()->NewJSArray(10);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000830 }
831
ager@chromium.org5c838252010-02-19 08:53:10 +0000832 void FunctionStarted(FunctionLiteral* fun) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000833 HandleScope scope(isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000834 FunctionInfoWrapper info = FunctionInfoWrapper::Create();
835 info.SetInitialProperties(fun->name(), fun->start_position(),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000836 fun->end_position(), fun->parameter_count(),
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000837 fun->materialized_literal_count(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000838 current_parent_index_);
839 current_parent_index_ = len_;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000840 SetElementNonStrict(result_, len_, info.GetJSArray());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000841 len_++;
ager@chromium.org5c838252010-02-19 08:53:10 +0000842 }
843
844 void FunctionDone() {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000845 HandleScope scope(isolate());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000846 FunctionInfoWrapper info =
847 FunctionInfoWrapper::cast(
848 result_->GetElementNoExceptionThrown(current_parent_index_));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000849 current_parent_index_ = info.GetParentIndex();
ager@chromium.org5c838252010-02-19 08:53:10 +0000850 }
851
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000852 // Saves only function code, because for a script function we
853 // may never create a SharedFunctionInfo object.
854 void FunctionCode(Handle<Code> function_code) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000855 FunctionInfoWrapper info =
856 FunctionInfoWrapper::cast(
857 result_->GetElementNoExceptionThrown(current_parent_index_));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000858 info.SetFunctionCode(function_code,
859 Handle<Object>(isolate()->heap()->null_value(),
860 isolate()));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000861 }
862
863 // Saves full information about a function: its code, its scope info
864 // and a SharedFunctionInfo object.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000865 void FunctionInfo(Handle<SharedFunctionInfo> shared, Scope* scope,
866 Zone* zone) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000867 if (!shared->IsSharedFunctionInfo()) {
868 return;
869 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000870 FunctionInfoWrapper info =
871 FunctionInfoWrapper::cast(
872 result_->GetElementNoExceptionThrown(current_parent_index_));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000873 info.SetFunctionCode(Handle<Code>(shared->code()),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000874 Handle<Object>(shared->scope_info(), isolate()));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000875 info.SetSharedFunctionInfo(shared);
876
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000877 Handle<Object> scope_info_list(SerializeFunctionScope(scope, zone),
878 isolate());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000879 info.SetOuterScopeInfo(scope_info_list);
880 }
881
882 Handle<JSArray> GetResult() { return result_; }
883
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000884 private:
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000885 Isolate* isolate() const { return result_->GetIsolate(); }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000886
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000887 Object* SerializeFunctionScope(Scope* scope, Zone* zone) {
888 HandleScope handle_scope(isolate());
889
890 Handle<JSArray> scope_info_list = isolate()->factory()->NewJSArray(10);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000891 int scope_info_length = 0;
892
893 // Saves some description of scope. It stores name and indexes of
894 // variables in the whole scope chain. Null-named slots delimit
895 // scopes of this chain.
896 Scope* outer_scope = scope->outer_scope();
897 if (outer_scope == NULL) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000898 return isolate()->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000899 }
900 do {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000901 ZoneList<Variable*> stack_list(outer_scope->StackLocalCount(), zone);
902 ZoneList<Variable*> context_list(outer_scope->ContextLocalCount(), zone);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000903 outer_scope->CollectStackAndContextLocals(&stack_list, &context_list);
904 context_list.Sort(&Variable::CompareIndex);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000905
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000906 for (int i = 0; i < context_list.length(); i++) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000907 SetElementNonStrict(scope_info_list,
908 scope_info_length,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000909 context_list[i]->name());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000910 scope_info_length++;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000911 SetElementNonStrict(
912 scope_info_list,
913 scope_info_length,
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000914 Handle<Smi>(Smi::FromInt(context_list[i]->index()), isolate()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000915 scope_info_length++;
916 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000917 SetElementNonStrict(scope_info_list,
918 scope_info_length,
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000919 Handle<Object>(isolate()->heap()->null_value(),
920 isolate()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000921 scope_info_length++;
922
923 outer_scope = outer_scope->outer_scope();
924 } while (outer_scope != NULL);
925
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000926 return *scope_info_list;
ager@chromium.org5c838252010-02-19 08:53:10 +0000927 }
928
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000929 Handle<JSArray> result_;
930 int len_;
931 int current_parent_index_;
ager@chromium.org5c838252010-02-19 08:53:10 +0000932};
933
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000934
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000935JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script,
936 Handle<String> source) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000937 Isolate* isolate = Isolate::Current();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000938
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000939 FunctionInfoListener listener(isolate);
940 Handle<Object> original_source =
941 Handle<Object>(script->source(), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000942 script->set_source(*source);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000943 isolate->set_active_function_info_listener(&listener);
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000944
945 {
946 // Creating verbose TryCatch from public API is currently the only way to
947 // force code save location. We do not use this the object directly.
948 v8::TryCatch try_catch;
949 try_catch.SetVerbose(true);
950
951 // A logical 'try' section.
952 CompileScriptForTracker(isolate, script);
953 }
954
955 // A logical 'catch' section.
956 Handle<JSObject> rethrow_exception;
957 if (isolate->has_pending_exception()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000958 Handle<Object> exception(isolate->pending_exception()->ToObjectChecked(),
959 isolate);
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000960 MessageLocation message_location = isolate->GetMessageLocation();
961
962 isolate->clear_pending_message();
963 isolate->clear_pending_exception();
964
965 // If possible, copy positions from message object to exception object.
966 if (exception->IsJSObject() && !message_location.script().is_null()) {
967 rethrow_exception = Handle<JSObject>::cast(exception);
968
969 Factory* factory = isolate->factory();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000970 Handle<String> start_pos_key = factory->InternalizeOneByteString(
971 STATIC_ASCII_VECTOR("startPosition"));
972 Handle<String> end_pos_key = factory->InternalizeOneByteString(
973 STATIC_ASCII_VECTOR("endPosition"));
974 Handle<String> script_obj_key = factory->InternalizeOneByteString(
975 STATIC_ASCII_VECTOR("scriptObject"));
976 Handle<Smi> start_pos(
977 Smi::FromInt(message_location.start_pos()), isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000978 Handle<Smi> end_pos(Smi::FromInt(message_location.end_pos()), isolate);
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000979 Handle<JSValue> script_obj = GetScriptWrapper(message_location.script());
980 JSReceiver::SetProperty(
981 rethrow_exception, start_pos_key, start_pos, NONE, kNonStrictMode);
982 JSReceiver::SetProperty(
983 rethrow_exception, end_pos_key, end_pos, NONE, kNonStrictMode);
984 JSReceiver::SetProperty(
985 rethrow_exception, script_obj_key, script_obj, NONE, kNonStrictMode);
986 }
987 }
988
989 // A logical 'finally' section.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000990 isolate->set_active_function_info_listener(NULL);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000991 script->set_source(*original_source);
992
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000993 if (rethrow_exception.is_null()) {
994 return *(listener.GetResult());
995 } else {
996 isolate->Throw(*rethrow_exception);
997 return 0;
998 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000999}
1000
1001
1002void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> array) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001003 HandleScope scope(array->GetIsolate());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001004 int len = GetArrayLength(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001005 for (int i = 0; i < len; i++) {
1006 Handle<SharedFunctionInfo> info(
lrn@chromium.org303ada72010-10-27 09:33:13 +00001007 SharedFunctionInfo::cast(array->GetElementNoExceptionThrown(i)));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001008 SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create();
1009 Handle<String> name_handle(String::cast(info->name()));
1010 info_wrapper.SetProperties(name_handle, info->start_position(),
1011 info->end_position(), info);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001012 SetElementNonStrict(array, i, info_wrapper.GetJSArray());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001013 }
1014}
1015
1016
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001017// Visitor that finds all references to a particular code object,
1018// including "CODE_TARGET" references in other code objects and replaces
1019// them on the fly.
1020class ReplacingVisitor : public ObjectVisitor {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001021 public:
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001022 explicit ReplacingVisitor(Code* original, Code* substitution)
1023 : original_(original), substitution_(substitution) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001024 }
1025
1026 virtual void VisitPointers(Object** start, Object** end) {
1027 for (Object** p = start; p < end; p++) {
1028 if (*p == original_) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001029 *p = substitution_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001030 }
1031 }
1032 }
1033
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001034 virtual void VisitCodeEntry(Address entry) {
1035 if (Code::GetObjectFromEntryAddress(entry) == original_) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001036 Address substitution_entry = substitution_->instruction_start();
1037 Memory::Address_at(entry) = substitution_entry;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001038 }
1039 }
1040
1041 virtual void VisitCodeTarget(RelocInfo* rinfo) {
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001042 if (RelocInfo::IsCodeTarget(rinfo->rmode()) &&
1043 Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001044 Address substitution_entry = substitution_->instruction_start();
1045 rinfo->set_target_address(substitution_entry);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001046 }
1047 }
1048
1049 virtual void VisitDebugTarget(RelocInfo* rinfo) {
1050 VisitCodeTarget(rinfo);
1051 }
1052
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001053 private:
1054 Code* original_;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001055 Code* substitution_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001056};
1057
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001058
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001059// Finds all references to original and replaces them with substitution.
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +00001060static void ReplaceCodeObject(Handle<Code> original,
1061 Handle<Code> substitution) {
1062 // Perform a full GC in order to ensure that we are not in the middle of an
1063 // incremental marking phase when we are replacing the code object.
1064 // Since we are not in an incremental marking phase we can write pointers
1065 // to code objects (that are never in new space) without worrying about
1066 // write barriers.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001067 Heap* heap = original->GetHeap();
1068 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +00001069 "liveedit.cc ReplaceCodeObject");
1070
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001071 ASSERT(!heap->InNewSpace(*substitution));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001072
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001073 DisallowHeapAllocation no_allocation;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001074
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +00001075 ReplacingVisitor visitor(*original, *substitution);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001076
1077 // Iterate over all roots. Stack frames may have pointer into original code,
1078 // so temporary replace the pointers with offset numbers
1079 // in prologue/epilogue.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001080 heap->IterateRoots(&visitor, VISIT_ALL);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001081
1082 // Now iterate over all pointers of all objects, including code_target
1083 // implicit pointers.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001084 HeapIterator iterator(heap);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001085 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1086 obj->Iterate(&visitor);
1087 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001088}
1089
1090
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001091// Patch function literals.
1092// Name 'literals' is a misnomer. Rather it's a cache for complex object
1093// boilerplates and for a native context. We must clean cached values.
1094// Additionally we may need to allocate a new array if number of literals
1095// changed.
1096class LiteralFixer {
1097 public:
1098 static void PatchLiterals(FunctionInfoWrapper* compile_info_wrapper,
1099 Handle<SharedFunctionInfo> shared_info,
1100 Isolate* isolate) {
1101 int new_literal_count = compile_info_wrapper->GetLiteralCount();
1102 if (new_literal_count > 0) {
1103 new_literal_count += JSFunction::kLiteralsPrefixSize;
1104 }
1105 int old_literal_count = shared_info->num_literals();
1106
1107 if (old_literal_count == new_literal_count) {
1108 // If literal count didn't change, simply go over all functions
1109 // and clear literal arrays.
1110 ClearValuesVisitor visitor;
1111 IterateJSFunctions(*shared_info, &visitor);
1112 } else {
1113 // When literal count changes, we have to create new array instances.
1114 // Since we cannot create instances when iterating heap, we should first
1115 // collect all functions and fix their literal arrays.
1116 Handle<FixedArray> function_instances =
1117 CollectJSFunctions(shared_info, isolate);
1118 for (int i = 0; i < function_instances->length(); i++) {
1119 Handle<JSFunction> fun(JSFunction::cast(function_instances->get(i)));
1120 Handle<FixedArray> old_literals(fun->literals());
1121 Handle<FixedArray> new_literals =
1122 isolate->factory()->NewFixedArray(new_literal_count);
1123 if (new_literal_count > 0) {
1124 Handle<Context> native_context;
1125 if (old_literals->length() >
1126 JSFunction::kLiteralNativeContextIndex) {
1127 native_context = Handle<Context>(
1128 JSFunction::NativeContextFromLiterals(fun->literals()));
1129 } else {
1130 native_context = Handle<Context>(fun->context()->native_context());
1131 }
1132 new_literals->set(JSFunction::kLiteralNativeContextIndex,
1133 *native_context);
1134 }
1135 fun->set_literals(*new_literals);
1136 }
1137
1138 shared_info->set_num_literals(new_literal_count);
1139 }
1140 }
1141
1142 private:
1143 // Iterates all function instances in the HEAP that refers to the
1144 // provided shared_info.
1145 template<typename Visitor>
1146 static void IterateJSFunctions(SharedFunctionInfo* shared_info,
1147 Visitor* visitor) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001148 DisallowHeapAllocation no_allocation;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001149
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001150 HeapIterator iterator(shared_info->GetHeap());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001151 for (HeapObject* obj = iterator.next(); obj != NULL;
1152 obj = iterator.next()) {
1153 if (obj->IsJSFunction()) {
1154 JSFunction* function = JSFunction::cast(obj);
1155 if (function->shared() == shared_info) {
1156 visitor->visit(function);
1157 }
1158 }
1159 }
1160 }
1161
1162 // Finds all instances of JSFunction that refers to the provided shared_info
1163 // and returns array with them.
1164 static Handle<FixedArray> CollectJSFunctions(
1165 Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
1166 CountVisitor count_visitor;
1167 count_visitor.count = 0;
1168 IterateJSFunctions(*shared_info, &count_visitor);
1169 int size = count_visitor.count;
1170
1171 Handle<FixedArray> result = isolate->factory()->NewFixedArray(size);
1172 if (size > 0) {
1173 CollectVisitor collect_visitor(result);
1174 IterateJSFunctions(*shared_info, &collect_visitor);
1175 }
1176 return result;
1177 }
1178
1179 class ClearValuesVisitor {
1180 public:
1181 void visit(JSFunction* fun) {
1182 FixedArray* literals = fun->literals();
1183 int len = literals->length();
1184 for (int j = JSFunction::kLiteralsPrefixSize; j < len; j++) {
1185 literals->set_undefined(j);
1186 }
1187 }
1188 };
1189
1190 class CountVisitor {
1191 public:
1192 void visit(JSFunction* fun) {
1193 count++;
1194 }
1195 int count;
1196 };
1197
1198 class CollectVisitor {
1199 public:
1200 explicit CollectVisitor(Handle<FixedArray> output)
1201 : m_output(output), m_pos(0) {}
1202
1203 void visit(JSFunction* fun) {
1204 m_output->set(m_pos, fun);
1205 m_pos++;
1206 }
1207 private:
1208 Handle<FixedArray> m_output;
1209 int m_pos;
1210 };
1211};
1212
1213
ager@chromium.org357bf652010-04-12 11:30:10 +00001214// Check whether the code is natural function code (not a lazy-compile stub
1215// code).
1216static bool IsJSFunctionCode(Code* code) {
1217 return code->kind() == Code::FUNCTION;
1218}
1219
1220
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001221// Returns true if an instance of candidate were inlined into function's code.
1222static bool IsInlined(JSFunction* function, SharedFunctionInfo* candidate) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001223 DisallowHeapAllocation no_gc;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001224
1225 if (function->code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
1226
1227 DeoptimizationInputData* data =
1228 DeoptimizationInputData::cast(function->code()->deoptimization_data());
1229
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001230 if (data == HEAP->empty_fixed_array()) return false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001231
1232 FixedArray* literals = data->LiteralArray();
1233
1234 int inlined_count = data->InlinedFunctionCount()->value();
1235 for (int i = 0; i < inlined_count; ++i) {
1236 JSFunction* inlined = JSFunction::cast(literals->get(i));
1237 if (inlined->shared() == candidate) return true;
1238 }
1239
1240 return false;
1241}
1242
1243
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001244class DependentFunctionFilter : public OptimizedFunctionFilter {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001245 public:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001246 explicit DependentFunctionFilter(
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001247 SharedFunctionInfo* function_info)
1248 : function_info_(function_info) {}
1249
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001250 virtual bool TakeFunction(JSFunction* function) {
1251 return (function->shared() == function_info_ ||
1252 IsInlined(function, function_info_));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001253 }
1254
1255 private:
1256 SharedFunctionInfo* function_info_;
1257};
1258
1259
1260static void DeoptimizeDependentFunctions(SharedFunctionInfo* function_info) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001261 DisallowHeapAllocation no_allocation;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001262
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001263 DependentFunctionFilter filter(function_info);
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00001264 Deoptimizer::DeoptimizeAllFunctionsWith(function_info->GetIsolate(), &filter);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001265}
1266
1267
lrn@chromium.org303ada72010-10-27 09:33:13 +00001268MaybeObject* LiveEdit::ReplaceFunctionCode(
1269 Handle<JSArray> new_compile_info_array,
1270 Handle<JSArray> shared_info_array) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001271 Isolate* isolate = Isolate::Current();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001272 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001273
ager@chromium.orgac091b72010-05-05 07:34:42 +00001274 if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001275 return isolate->ThrowIllegalOperation();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001276 }
1277
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001278 FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
1279 SharedInfoWrapper shared_info_wrapper(shared_info_array);
1280
1281 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
1282
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001283 isolate->heap()->EnsureHeapIsIterable();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001284
ager@chromium.org357bf652010-04-12 11:30:10 +00001285 if (IsJSFunctionCode(shared_info->code())) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001286 Handle<Code> code = compile_info_wrapper.GetFunctionCode();
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +00001287 ReplaceCodeObject(Handle<Code>(shared_info->code()), code);
1288 Handle<Object> code_scope_info = compile_info_wrapper.GetCodeScopeInfo();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001289 if (code_scope_info->IsFixedArray()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001290 shared_info->set_scope_info(ScopeInfo::cast(*code_scope_info));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001291 }
ager@chromium.org357bf652010-04-12 11:30:10 +00001292 }
1293
1294 if (shared_info->debug_info()->IsDebugInfo()) {
1295 Handle<DebugInfo> debug_info(DebugInfo::cast(shared_info->debug_info()));
1296 Handle<Code> new_original_code =
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001297 isolate->factory()->CopyCode(compile_info_wrapper.GetFunctionCode());
ager@chromium.org357bf652010-04-12 11:30:10 +00001298 debug_info->set_original_code(*new_original_code);
1299 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001300
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001301 int start_position = compile_info_wrapper.GetStartPosition();
1302 int end_position = compile_info_wrapper.GetEndPosition();
1303 shared_info->set_start_position(start_position);
1304 shared_info->set_end_position(end_position);
ager@chromium.org357bf652010-04-12 11:30:10 +00001305
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001306 LiteralFixer::PatchLiterals(&compile_info_wrapper, shared_info, isolate);
1307
ager@chromium.org357bf652010-04-12 11:30:10 +00001308 shared_info->set_construct_stub(
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001309 isolate->builtins()->builtin(Builtins::kJSConstructStubGeneric));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001310
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001311 DeoptimizeDependentFunctions(*shared_info);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001312 isolate->compilation_cache()->Remove(shared_info);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001313
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001314 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001315}
1316
1317
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001318MaybeObject* LiveEdit::FunctionSourceUpdated(
1319 Handle<JSArray> shared_info_array) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001320 Isolate* isolate = shared_info_array->GetIsolate();
1321 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001322
1323 if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001324 return isolate->ThrowIllegalOperation();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001325 }
1326
1327 SharedInfoWrapper shared_info_wrapper(shared_info_array);
1328 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
1329
1330 DeoptimizeDependentFunctions(*shared_info);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001331 isolate->compilation_cache()->Remove(shared_info);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001332
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001333 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001334}
1335
1336
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001337void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
1338 Handle<Object> script_handle) {
1339 Handle<SharedFunctionInfo> shared_info =
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001340 UnwrapSharedFunctionInfoFromJSValue(function_wrapper);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001341 CHECK(script_handle->IsScript() || script_handle->IsUndefined());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001342 shared_info->set_script(*script_handle);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001344 Isolate::Current()->compilation_cache()->Remove(shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001345}
1346
1347
1348// For a script text change (defined as position_change_array), translates
1349// position in unchanged text to position in changed text.
1350// Text change is a set of non-overlapping regions in text, that have changed
1351// their contents and length. It is specified as array of groups of 3 numbers:
1352// (change_begin, change_end, change_end_new_position).
1353// Each group describes a change in text; groups are sorted by change_begin.
1354// Only position in text beyond any changes may be successfully translated.
1355// If a positions is inside some region that changed, result is currently
1356// undefined.
1357static int TranslatePosition(int original_position,
1358 Handle<JSArray> position_change_array) {
1359 int position_diff = 0;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001360 int array_len = GetArrayLength(position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001361 // TODO(635): binary search may be used here
1362 for (int i = 0; i < array_len; i += 3) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001363 Object* element = position_change_array->GetElementNoExceptionThrown(i);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001364 CHECK(element->IsSmi());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001365 int chunk_start = Smi::cast(element)->value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001366 if (original_position < chunk_start) {
1367 break;
1368 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001369 element = position_change_array->GetElementNoExceptionThrown(i + 1);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001370 CHECK(element->IsSmi());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001371 int chunk_end = Smi::cast(element)->value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001372 // Position mustn't be inside a chunk.
1373 ASSERT(original_position >= chunk_end);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001374 element = position_change_array->GetElementNoExceptionThrown(i + 2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001375 CHECK(element->IsSmi());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001376 int chunk_changed_end = Smi::cast(element)->value();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001377 position_diff = chunk_changed_end - chunk_end;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001378 }
1379
1380 return original_position + position_diff;
1381}
1382
1383
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001384// Auto-growing buffer for writing relocation info code section. This buffer
1385// is a simplified version of buffer from Assembler. Unlike Assembler, this
1386// class is platform-independent and it works without dealing with instructions.
1387// As specified by RelocInfo format, the buffer is filled in reversed order:
1388// from upper to lower addresses.
1389// It uses NewArray/DeleteArray for memory management.
1390class RelocInfoBuffer {
1391 public:
1392 RelocInfoBuffer(int buffer_initial_capicity, byte* pc) {
1393 buffer_size_ = buffer_initial_capicity + kBufferGap;
1394 buffer_ = NewArray<byte>(buffer_size_);
1395
1396 reloc_info_writer_.Reposition(buffer_ + buffer_size_, pc);
1397 }
1398 ~RelocInfoBuffer() {
1399 DeleteArray(buffer_);
1400 }
1401
1402 // As specified by RelocInfo format, the buffer is filled in reversed order:
1403 // from upper to lower addresses.
1404 void Write(const RelocInfo* rinfo) {
1405 if (buffer_ + kBufferGap >= reloc_info_writer_.pos()) {
1406 Grow();
1407 }
1408 reloc_info_writer_.Write(rinfo);
1409 }
1410
1411 Vector<byte> GetResult() {
1412 // Return the bytes from pos up to end of buffer.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001413 int result_size =
1414 static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer_.pos());
1415 return Vector<byte>(reloc_info_writer_.pos(), result_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001416 }
1417
1418 private:
1419 void Grow() {
1420 // Compute new buffer size.
1421 int new_buffer_size;
1422 if (buffer_size_ < 2 * KB) {
1423 new_buffer_size = 4 * KB;
1424 } else {
1425 new_buffer_size = 2 * buffer_size_;
1426 }
1427 // Some internal data structures overflow for very large buffers,
1428 // they must ensure that kMaximalBufferSize is not too large.
1429 if (new_buffer_size > kMaximalBufferSize) {
1430 V8::FatalProcessOutOfMemory("RelocInfoBuffer::GrowBuffer");
1431 }
1432
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001433 // Set up new buffer.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001434 byte* new_buffer = NewArray<byte>(new_buffer_size);
1435
1436 // Copy the data.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001437 int curently_used_size =
1438 static_cast<int>(buffer_ + buffer_size_ - reloc_info_writer_.pos());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001439 OS::MemMove(new_buffer + new_buffer_size - curently_used_size,
1440 reloc_info_writer_.pos(), curently_used_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001441
1442 reloc_info_writer_.Reposition(
1443 new_buffer + new_buffer_size - curently_used_size,
1444 reloc_info_writer_.last_pc());
1445
1446 DeleteArray(buffer_);
1447 buffer_ = new_buffer;
1448 buffer_size_ = new_buffer_size;
1449 }
1450
1451 RelocInfoWriter reloc_info_writer_;
1452 byte* buffer_;
1453 int buffer_size_;
1454
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001455 static const int kBufferGap = RelocInfoWriter::kMaxSize;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001456 static const int kMaximalBufferSize = 512*MB;
1457};
1458
1459// Patch positions in code (changes relocation info section) and possibly
1460// returns new instance of code.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001461static Handle<Code> PatchPositionsInCode(
1462 Handle<Code> code,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001463 Handle<JSArray> position_change_array) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001464 Isolate* isolate = code->GetIsolate();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001465
1466 RelocInfoBuffer buffer_writer(code->relocation_size(),
1467 code->instruction_start());
1468
1469 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001470 DisallowHeapAllocation no_allocation;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001471 for (RelocIterator it(*code); !it.done(); it.next()) {
1472 RelocInfo* rinfo = it.rinfo();
1473 if (RelocInfo::IsPosition(rinfo->rmode())) {
1474 int position = static_cast<int>(rinfo->data());
1475 int new_position = TranslatePosition(position,
1476 position_change_array);
1477 if (position != new_position) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001478 RelocInfo info_copy(rinfo->pc(), rinfo->rmode(), new_position, NULL);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001479 buffer_writer.Write(&info_copy);
1480 continue;
1481 }
1482 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001483 if (RelocInfo::IsRealRelocMode(rinfo->rmode())) {
1484 buffer_writer.Write(it.rinfo());
1485 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001486 }
1487 }
1488
1489 Vector<byte> buffer = buffer_writer.GetResult();
1490
1491 if (buffer.length() == code->relocation_size()) {
1492 // Simply patch relocation area of code.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001493 OS::MemCopy(code->relocation_start(), buffer.start(), buffer.length());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001494 return code;
1495 } else {
1496 // Relocation info section now has different size. We cannot simply
1497 // rewrite it inside code object. Instead we have to create a new
1498 // code object.
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001499 Handle<Code> result(isolate->factory()->CopyCode(code, buffer));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001500 return result;
1501 }
1502}
1503
1504
lrn@chromium.org303ada72010-10-27 09:33:13 +00001505MaybeObject* LiveEdit::PatchFunctionPositions(
ager@chromium.org357bf652010-04-12 11:30:10 +00001506 Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001507 if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001508 return Isolate::Current()->ThrowIllegalOperation();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001509 }
1510
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001511 SharedInfoWrapper shared_info_wrapper(shared_info_array);
1512 Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo();
1513
ager@chromium.org357bf652010-04-12 11:30:10 +00001514 int old_function_start = info->start_position();
1515 int new_function_start = TranslatePosition(old_function_start,
1516 position_change_array);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001517 int new_function_end = TranslatePosition(info->end_position(),
1518 position_change_array);
1519 int new_function_token_pos =
1520 TranslatePosition(info->function_token_position(), position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001522 info->set_start_position(new_function_start);
1523 info->set_end_position(new_function_end);
1524 info->set_function_token_position(new_function_token_pos);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001525
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001526 HEAP->EnsureHeapIsIterable();
1527
ager@chromium.org357bf652010-04-12 11:30:10 +00001528 if (IsJSFunctionCode(info->code())) {
1529 // Patch relocation info section of the code.
1530 Handle<Code> patched_code = PatchPositionsInCode(Handle<Code>(info->code()),
1531 position_change_array);
1532 if (*patched_code != info->code()) {
1533 // Replace all references to the code across the heap. In particular,
1534 // some stubs may refer to this code and this code may be being executed
1535 // on stack (it is safe to substitute the code object on stack, because
1536 // we only change the structure of rinfo and leave instructions
1537 // untouched).
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +00001538 ReplaceCodeObject(Handle<Code>(info->code()), patched_code);
ager@chromium.org357bf652010-04-12 11:30:10 +00001539 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001540 }
ager@chromium.orgac091b72010-05-05 07:34:42 +00001541
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001542 return HEAP->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001543}
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001544
ager@chromium.org357bf652010-04-12 11:30:10 +00001545
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001546static Handle<Script> CreateScriptCopy(Handle<Script> original) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001547 Isolate* isolate = original->GetIsolate();
ager@chromium.org357bf652010-04-12 11:30:10 +00001548
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001549 Handle<String> original_source(String::cast(original->source()));
1550 Handle<Script> copy = isolate->factory()->NewScript(original_source);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001551
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001552 copy->set_name(original->name());
1553 copy->set_line_offset(original->line_offset());
1554 copy->set_column_offset(original->column_offset());
1555 copy->set_data(original->data());
1556 copy->set_type(original->type());
1557 copy->set_context_data(original->context_data());
1558 copy->set_compilation_type(original->compilation_type());
1559 copy->set_eval_from_shared(original->eval_from_shared());
1560 copy->set_eval_from_instructions_offset(
1561 original->eval_from_instructions_offset());
1562
1563 return copy;
1564}
1565
1566
1567Object* LiveEdit::ChangeScriptSource(Handle<Script> original_script,
1568 Handle<String> new_source,
1569 Handle<Object> old_script_name) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001570 Isolate* isolate = original_script->GetIsolate();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001571 Handle<Object> old_script_object;
1572 if (old_script_name->IsString()) {
1573 Handle<Script> old_script = CreateScriptCopy(original_script);
1574 old_script->set_name(String::cast(*old_script_name));
1575 old_script_object = old_script;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001576 isolate->debugger()->OnAfterCompile(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001577 old_script, Debugger::SEND_WHEN_DEBUGGING);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001578 } else {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001579 old_script_object = isolate->factory()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001580 }
1581
1582 original_script->set_source(*new_source);
1583
1584 // Drop line ends so that they will be recalculated.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001585 original_script->set_line_ends(HEAP->undefined_value());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001586
1587 return *old_script_object;
1588}
1589
1590
1591
1592void LiveEdit::ReplaceRefToNestedFunction(
1593 Handle<JSValue> parent_function_wrapper,
1594 Handle<JSValue> orig_function_wrapper,
1595 Handle<JSValue> subst_function_wrapper) {
1596
1597 Handle<SharedFunctionInfo> parent_shared =
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001598 UnwrapSharedFunctionInfoFromJSValue(parent_function_wrapper);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001599 Handle<SharedFunctionInfo> orig_shared =
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001600 UnwrapSharedFunctionInfoFromJSValue(orig_function_wrapper);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001601 Handle<SharedFunctionInfo> subst_shared =
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001602 UnwrapSharedFunctionInfoFromJSValue(subst_function_wrapper);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001603
1604 for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) {
1605 if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) {
1606 if (it.rinfo()->target_object() == *orig_shared) {
1607 it.rinfo()->set_target_object(*subst_shared);
ager@chromium.org357bf652010-04-12 11:30:10 +00001608 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001609 }
1610 }
ager@chromium.org357bf652010-04-12 11:30:10 +00001611}
1612
1613
1614// Check an activation against list of functions. If there is a function
1615// that matches, its status in result array is changed to status argument value.
1616static bool CheckActivation(Handle<JSArray> shared_info_array,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001617 Handle<JSArray> result,
1618 StackFrame* frame,
ager@chromium.org357bf652010-04-12 11:30:10 +00001619 LiveEdit::FunctionPatchabilityStatus status) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001620 if (!frame->is_java_script()) return false;
1621
1622 Handle<JSFunction> function(
1623 JSFunction::cast(JavaScriptFrame::cast(frame)->function()));
1624
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001625 Isolate* isolate = shared_info_array->GetIsolate();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001626 int len = GetArrayLength(shared_info_array);
ager@chromium.org357bf652010-04-12 11:30:10 +00001627 for (int i = 0; i < len; i++) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001628 Object* element = shared_info_array->GetElementNoExceptionThrown(i);
1629 CHECK(element->IsJSValue());
1630 Handle<JSValue> jsvalue(JSValue::cast(element));
1631 Handle<SharedFunctionInfo> shared =
1632 UnwrapSharedFunctionInfoFromJSValue(jsvalue);
ager@chromium.org357bf652010-04-12 11:30:10 +00001633
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001634 if (function->shared() == *shared || IsInlined(*function, *shared)) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001635 SetElementNonStrict(result, i, Handle<Smi>(Smi::FromInt(status),
1636 isolate));
ager@chromium.org357bf652010-04-12 11:30:10 +00001637 return true;
1638 }
1639 }
1640 return false;
1641}
1642
1643
1644// Iterates over handler chain and removes all elements that are inside
1645// frames being dropped.
1646static bool FixTryCatchHandler(StackFrame* top_frame,
1647 StackFrame* bottom_frame) {
1648 Address* pointer_address =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 &Memory::Address_at(Isolate::Current()->get_address_from_id(
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001650 Isolate::kHandlerAddress));
ager@chromium.org357bf652010-04-12 11:30:10 +00001651
1652 while (*pointer_address < top_frame->sp()) {
1653 pointer_address = &Memory::Address_at(*pointer_address);
1654 }
1655 Address* above_frame_address = pointer_address;
1656 while (*pointer_address < bottom_frame->fp()) {
1657 pointer_address = &Memory::Address_at(*pointer_address);
1658 }
1659 bool change = *above_frame_address != *pointer_address;
1660 *above_frame_address = *pointer_address;
1661 return change;
1662}
1663
1664
1665// Removes specified range of frames from stack. There may be 1 or more
1666// frames in range. Anyway the bottom frame is restarted rather than dropped,
1667// and therefore has to be a JavaScript frame.
1668// Returns error message or NULL.
1669static const char* DropFrames(Vector<StackFrame*> frames,
1670 int top_frame_index,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001671 int bottom_js_frame_index,
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001672 Debug::FrameDropMode* mode,
1673 Object*** restarter_frame_function_pointer) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001674 if (!Debug::kFrameDropperSupported) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001675 return "Stack manipulations are not supported in this architecture.";
1676 }
1677
ager@chromium.org357bf652010-04-12 11:30:10 +00001678 StackFrame* pre_top_frame = frames[top_frame_index - 1];
1679 StackFrame* top_frame = frames[top_frame_index];
1680 StackFrame* bottom_js_frame = frames[bottom_js_frame_index];
1681
1682 ASSERT(bottom_js_frame->is_java_script());
1683
1684 // Check the nature of the top frame.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001685 Isolate* isolate = Isolate::Current();
1686 Code* pre_top_frame_code = pre_top_frame->LookupCode();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001687 bool frame_has_padding;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001688 if (pre_top_frame_code->is_inline_cache_stub() &&
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00001689 pre_top_frame_code->is_debug_break()) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001690 // OK, we can drop inline cache calls.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001691 *mode = Debug::FRAME_DROPPED_IN_IC_CALL;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001692 frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001693 } else if (pre_top_frame_code ==
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001694 isolate->debug()->debug_break_slot()) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001695 // OK, we can drop debug break slot.
1696 *mode = Debug::FRAME_DROPPED_IN_DEBUG_SLOT_CALL;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001697 frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001698 } else if (pre_top_frame_code ==
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001699 isolate->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001700 Builtins::kFrameDropper_LiveEdit)) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001701 // OK, we can drop our own code.
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00001702 pre_top_frame = frames[top_frame_index - 2];
1703 top_frame = frames[top_frame_index - 1];
1704 *mode = Debug::CURRENTLY_SET_MODE;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001705 frame_has_padding = false;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001706 } else if (pre_top_frame_code ==
1707 isolate->builtins()->builtin(Builtins::kReturn_DebugBreak)) {
1708 *mode = Debug::FRAME_DROPPED_IN_RETURN_CALL;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001709 frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001710 } else if (pre_top_frame_code->kind() == Code::STUB &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001711 pre_top_frame_code->major_key() == CodeStub::CEntry) {
1712 // Entry from our unit tests on 'debugger' statement.
1713 // It's fine, we support this case.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001714 *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001715 // We don't have a padding from 'debugger' statement call.
1716 // Here the stub is CEntry, it's not debug-only and can't be padded.
1717 // If anyone would complain, a proxy padded stub could be added.
1718 frame_has_padding = false;
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00001719 } else if (pre_top_frame->type() == StackFrame::ARGUMENTS_ADAPTOR) {
1720 // This must be adaptor that remain from the frame dropping that
1721 // is still on stack. A frame dropper frame must be above it.
1722 ASSERT(frames[top_frame_index - 2]->LookupCode() ==
1723 isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit));
1724 pre_top_frame = frames[top_frame_index - 3];
1725 top_frame = frames[top_frame_index - 2];
1726 *mode = Debug::CURRENTLY_SET_MODE;
1727 frame_has_padding = false;
ager@chromium.org357bf652010-04-12 11:30:10 +00001728 } else {
1729 return "Unknown structure of stack above changing function";
1730 }
1731
1732 Address unused_stack_top = top_frame->sp();
1733 Address unused_stack_bottom = bottom_js_frame->fp()
1734 - Debug::kFrameDropperFrameSize * kPointerSize // Size of the new frame.
1735 + kPointerSize; // Bigger address end is exclusive.
1736
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001737 Address* top_frame_pc_address = top_frame->pc_address();
1738
1739 // top_frame may be damaged below this point. Do not used it.
1740 ASSERT(!(top_frame = NULL));
1741
ager@chromium.org357bf652010-04-12 11:30:10 +00001742 if (unused_stack_top > unused_stack_bottom) {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001743 if (frame_has_padding) {
1744 int shortage_bytes =
1745 static_cast<int>(unused_stack_top - unused_stack_bottom);
1746
1747 Address padding_start = pre_top_frame->fp() -
1748 Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize;
1749
1750 Address padding_pointer = padding_start;
1751 Smi* padding_object =
1752 Smi::FromInt(Debug::FramePaddingLayout::kPaddingValue);
1753 while (Memory::Object_at(padding_pointer) == padding_object) {
1754 padding_pointer -= kPointerSize;
1755 }
1756 int padding_counter =
1757 Smi::cast(Memory::Object_at(padding_pointer))->value();
1758 if (padding_counter * kPointerSize < shortage_bytes) {
1759 return "Not enough space for frame dropper frame "
1760 "(even with padding frame)";
1761 }
1762 Memory::Object_at(padding_pointer) =
1763 Smi::FromInt(padding_counter - shortage_bytes / kPointerSize);
1764
1765 StackFrame* pre_pre_frame = frames[top_frame_index - 2];
1766
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001767 OS::MemMove(padding_start + kPointerSize - shortage_bytes,
1768 padding_start + kPointerSize,
1769 Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001770
1771 pre_top_frame->UpdateFp(pre_top_frame->fp() - shortage_bytes);
1772 pre_pre_frame->SetCallerFp(pre_top_frame->fp());
1773 unused_stack_top -= shortage_bytes;
1774
1775 STATIC_ASSERT(sizeof(Address) == kPointerSize);
1776 top_frame_pc_address -= shortage_bytes / kPointerSize;
1777 } else {
1778 return "Not enough space for frame dropper frame";
1779 }
ager@chromium.org357bf652010-04-12 11:30:10 +00001780 }
1781
1782 // Committing now. After this point we should return only NULL value.
1783
1784 FixTryCatchHandler(pre_top_frame, bottom_js_frame);
1785 // Make sure FixTryCatchHandler is idempotent.
1786 ASSERT(!FixTryCatchHandler(pre_top_frame, bottom_js_frame));
1787
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001788 Handle<Code> code = Isolate::Current()->builtins()->FrameDropper_LiveEdit();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001789 *top_frame_pc_address = code->entry();
ager@chromium.org357bf652010-04-12 11:30:10 +00001790 pre_top_frame->SetCallerFp(bottom_js_frame->fp());
1791
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001792 *restarter_frame_function_pointer =
1793 Debug::SetUpFrameDropperFrame(bottom_js_frame, code);
1794
1795 ASSERT((**restarter_frame_function_pointer)->IsJSFunction());
ager@chromium.org357bf652010-04-12 11:30:10 +00001796
1797 for (Address a = unused_stack_top;
1798 a < unused_stack_bottom;
1799 a += kPointerSize) {
1800 Memory::Object_at(a) = Smi::FromInt(0);
1801 }
1802
1803 return NULL;
1804}
1805
1806
1807static bool IsDropableFrame(StackFrame* frame) {
1808 return !frame->is_exit();
1809}
1810
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001811
1812// Describes a set of call frames that execute any of listed functions.
1813// Finding no such frames does not mean error.
1814class MultipleFunctionTarget {
1815 public:
1816 MultipleFunctionTarget(Handle<JSArray> shared_info_array,
1817 Handle<JSArray> result)
1818 : m_shared_info_array(shared_info_array),
1819 m_result(result) {}
1820 bool MatchActivation(StackFrame* frame,
1821 LiveEdit::FunctionPatchabilityStatus status) {
1822 return CheckActivation(m_shared_info_array, m_result, frame, status);
1823 }
1824 const char* GetNotFoundMessage() {
1825 return NULL;
1826 }
1827 private:
1828 Handle<JSArray> m_shared_info_array;
1829 Handle<JSArray> m_result;
1830};
1831
1832// Drops all call frame matched by target and all frames above them.
1833template<typename TARGET>
1834static const char* DropActivationsInActiveThreadImpl(
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001835 TARGET& target, bool do_drop) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001836 Isolate* isolate = Isolate::Current();
1837 Debug* debug = isolate->debug();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001838 Zone zone(isolate);
1839 Vector<StackFrame*> frames = CreateStackMap(isolate, &zone);
ager@chromium.org357bf652010-04-12 11:30:10 +00001840
ager@chromium.org357bf652010-04-12 11:30:10 +00001841
1842 int top_frame_index = -1;
1843 int frame_index = 0;
1844 for (; frame_index < frames.length(); frame_index++) {
1845 StackFrame* frame = frames[frame_index];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001846 if (frame->id() == debug->break_frame_id()) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001847 top_frame_index = frame_index;
1848 break;
1849 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001850 if (target.MatchActivation(
1851 frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001852 // We are still above break_frame. It is not a target frame,
1853 // it is a problem.
1854 return "Debugger mark-up on stack is not found";
1855 }
1856 }
1857
1858 if (top_frame_index == -1) {
1859 // We haven't found break frame, but no function is blocking us anyway.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001860 return target.GetNotFoundMessage();
ager@chromium.org357bf652010-04-12 11:30:10 +00001861 }
1862
1863 bool target_frame_found = false;
1864 int bottom_js_frame_index = top_frame_index;
1865 bool c_code_found = false;
1866
1867 for (; frame_index < frames.length(); frame_index++) {
1868 StackFrame* frame = frames[frame_index];
1869 if (!IsDropableFrame(frame)) {
1870 c_code_found = true;
1871 break;
1872 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001873 if (target.MatchActivation(
1874 frame, LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001875 target_frame_found = true;
1876 bottom_js_frame_index = frame_index;
1877 }
1878 }
1879
1880 if (c_code_found) {
1881 // There is a C frames on stack. Check that there are no target frames
1882 // below them.
1883 for (; frame_index < frames.length(); frame_index++) {
1884 StackFrame* frame = frames[frame_index];
1885 if (frame->is_java_script()) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001886 if (target.MatchActivation(
1887 frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001888 // Cannot drop frame under C frames.
1889 return NULL;
1890 }
1891 }
1892 }
1893 }
1894
1895 if (!do_drop) {
1896 // We are in check-only mode.
1897 return NULL;
1898 }
1899
1900 if (!target_frame_found) {
1901 // Nothing to drop.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001902 return target.GetNotFoundMessage();
ager@chromium.org357bf652010-04-12 11:30:10 +00001903 }
1904
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001905 Debug::FrameDropMode drop_mode = Debug::FRAMES_UNTOUCHED;
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001906 Object** restarter_frame_function_pointer = NULL;
ager@chromium.org357bf652010-04-12 11:30:10 +00001907 const char* error_message = DropFrames(frames, top_frame_index,
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001908 bottom_js_frame_index, &drop_mode,
1909 &restarter_frame_function_pointer);
ager@chromium.org357bf652010-04-12 11:30:10 +00001910
1911 if (error_message != NULL) {
1912 return error_message;
1913 }
1914
1915 // Adjust break_frame after some frames has been dropped.
1916 StackFrame::Id new_id = StackFrame::NO_ID;
1917 for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) {
1918 if (frames[i]->type() == StackFrame::JAVA_SCRIPT) {
1919 new_id = frames[i]->id();
1920 break;
1921 }
1922 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001923 debug->FramesHaveBeenDropped(new_id, drop_mode,
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001924 restarter_frame_function_pointer);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001925 return NULL;
1926}
1927
1928// Fills result array with statuses of functions. Modifies the stack
1929// removing all listed function if possible and if do_drop is true.
1930static const char* DropActivationsInActiveThread(
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001931 Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001932 MultipleFunctionTarget target(shared_info_array, result);
1933
1934 const char* message =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001935 DropActivationsInActiveThreadImpl(target, do_drop);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001936 if (message) {
1937 return message;
1938 }
1939
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001940 Isolate* isolate = shared_info_array->GetIsolate();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001941 int array_len = GetArrayLength(shared_info_array);
ager@chromium.org357bf652010-04-12 11:30:10 +00001942
1943 // Replace "blocked on active" with "replaced on active" status.
1944 for (int i = 0; i < array_len; i++) {
1945 if (result->GetElement(i) ==
1946 Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001947 Handle<Object> replaced(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001948 Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK), isolate);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001949 SetElementNonStrict(result, i, replaced);
ager@chromium.org357bf652010-04-12 11:30:10 +00001950 }
1951 }
1952 return NULL;
1953}
1954
1955
1956class InactiveThreadActivationsChecker : public ThreadVisitor {
1957 public:
1958 InactiveThreadActivationsChecker(Handle<JSArray> shared_info_array,
1959 Handle<JSArray> result)
1960 : shared_info_array_(shared_info_array), result_(result),
1961 has_blocked_functions_(false) {
1962 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001963 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1964 for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001965 has_blocked_functions_ |= CheckActivation(
1966 shared_info_array_, result_, it.frame(),
1967 LiveEdit::FUNCTION_BLOCKED_ON_OTHER_STACK);
1968 }
1969 }
1970 bool HasBlockedFunctions() {
1971 return has_blocked_functions_;
1972 }
1973
1974 private:
1975 Handle<JSArray> shared_info_array_;
1976 Handle<JSArray> result_;
1977 bool has_blocked_functions_;
1978};
1979
1980
1981Handle<JSArray> LiveEdit::CheckAndDropActivations(
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001982 Handle<JSArray> shared_info_array, bool do_drop) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001983 Isolate* isolate = shared_info_array->GetIsolate();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001984 int len = GetArrayLength(shared_info_array);
ager@chromium.org357bf652010-04-12 11:30:10 +00001985
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001986 Handle<JSArray> result = isolate->factory()->NewJSArray(len);
ager@chromium.org357bf652010-04-12 11:30:10 +00001987
1988 // Fill the default values.
1989 for (int i = 0; i < len; i++) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001990 SetElementNonStrict(
1991 result,
1992 i,
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001993 Handle<Smi>(Smi::FromInt(FUNCTION_AVAILABLE_FOR_PATCH), isolate));
ager@chromium.org357bf652010-04-12 11:30:10 +00001994 }
1995
1996
1997 // First check inactive threads. Fail if some functions are blocked there.
1998 InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array,
1999 result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002000 Isolate::Current()->thread_manager()->IterateArchivedThreads(
2001 &inactive_threads_checker);
ager@chromium.org357bf652010-04-12 11:30:10 +00002002 if (inactive_threads_checker.HasBlockedFunctions()) {
2003 return result;
2004 }
2005
2006 // Try to drop activations from the current stack.
2007 const char* error_message =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002008 DropActivationsInActiveThread(shared_info_array, result, do_drop);
ager@chromium.org357bf652010-04-12 11:30:10 +00002009 if (error_message != NULL) {
2010 // Add error message as an array extra element.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00002011 Vector<const char> vector_message(error_message, StrLength(error_message));
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002012 Handle<String> str = isolate->factory()->NewStringFromAscii(vector_message);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002013 SetElementNonStrict(result, len, str);
ager@chromium.org357bf652010-04-12 11:30:10 +00002014 }
2015 return result;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002016}
2017
2018
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002019// Describes a single callframe a target. Not finding this frame
2020// means an error.
2021class SingleFrameTarget {
2022 public:
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002023 explicit SingleFrameTarget(JavaScriptFrame* frame)
2024 : m_frame(frame),
2025 m_saved_status(LiveEdit::FUNCTION_AVAILABLE_FOR_PATCH) {}
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002026
2027 bool MatchActivation(StackFrame* frame,
2028 LiveEdit::FunctionPatchabilityStatus status) {
2029 if (frame->fp() == m_frame->fp()) {
2030 m_saved_status = status;
2031 return true;
2032 }
2033 return false;
2034 }
2035 const char* GetNotFoundMessage() {
2036 return "Failed to found requested frame";
2037 }
2038 LiveEdit::FunctionPatchabilityStatus saved_status() {
2039 return m_saved_status;
2040 }
2041 private:
2042 JavaScriptFrame* m_frame;
2043 LiveEdit::FunctionPatchabilityStatus m_saved_status;
2044};
2045
2046
2047// Finds a drops required frame and all frames above.
2048// Returns error message or NULL.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002049const char* LiveEdit::RestartFrame(JavaScriptFrame* frame) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002050 SingleFrameTarget target(frame);
2051
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002052 const char* result = DropActivationsInActiveThreadImpl(target, true);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002053 if (result != NULL) {
2054 return result;
2055 }
2056 if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE) {
2057 return "Function is blocked under native code";
2058 }
2059 return NULL;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002060}
2061
2062
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002063LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
2064 FunctionLiteral* fun)
2065 : isolate_(isolate) {
2066 if (isolate_->active_function_info_listener() != NULL) {
2067 isolate_->active_function_info_listener()->FunctionStarted(fun);
ager@chromium.org5c838252010-02-19 08:53:10 +00002068 }
2069}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002070
2071
ager@chromium.org5c838252010-02-19 08:53:10 +00002072LiveEditFunctionTracker::~LiveEditFunctionTracker() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002073 if (isolate_->active_function_info_listener() != NULL) {
2074 isolate_->active_function_info_listener()->FunctionDone();
ager@chromium.org5c838252010-02-19 08:53:10 +00002075 }
2076}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002077
2078
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002079void LiveEditFunctionTracker::RecordFunctionInfo(
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002080 Handle<SharedFunctionInfo> info, FunctionLiteral* lit,
2081 Zone* zone) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002082 if (isolate_->active_function_info_listener() != NULL) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002083 isolate_->active_function_info_listener()->FunctionInfo(info, lit->scope(),
2084 zone);
ager@chromium.org5c838252010-02-19 08:53:10 +00002085 }
2086}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002087
2088
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002089void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002090 isolate_->active_function_info_listener()->FunctionCode(code);
ager@chromium.org5c838252010-02-19 08:53:10 +00002091}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002092
2093
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002094bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
2095 return isolate->active_function_info_listener() != NULL;
ager@chromium.org5c838252010-02-19 08:53:10 +00002096}
2097
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002098
2099#else // ENABLE_DEBUGGER_SUPPORT
2100
2101// This ifdef-else-endif section provides working or stub implementation of
2102// LiveEditFunctionTracker.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002103LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
2104 FunctionLiteral* fun) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002105}
2106
2107
2108LiveEditFunctionTracker::~LiveEditFunctionTracker() {
2109}
2110
2111
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002112void LiveEditFunctionTracker::RecordFunctionInfo(
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002113 Handle<SharedFunctionInfo> info, FunctionLiteral* lit,
2114 Zone* zone) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002115}
2116
2117
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002118void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002119}
2120
2121
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002122bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002123 return false;
2124}
2125
2126#endif // ENABLE_DEBUGGER_SUPPORT
2127
2128
2129
ager@chromium.org5c838252010-02-19 08:53:10 +00002130} } // namespace v8::internal