blob: 80e18bbbff9a9274e04f6fdd628aa671d414516b [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"
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000039#include "parser.h"
40#include "scopeinfo.h"
41#include "scopes.h"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000042#include "v8memory.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000043
44namespace v8 {
45namespace internal {
46
47
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#ifdef ENABLE_DEBUGGER_SUPPORT
49
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000050
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000051void SetElementNonStrict(Handle<JSObject> object,
52 uint32_t index,
53 Handle<Object> value) {
54 // Ignore return value from SetElement. It can only be a failure if there
55 // are element setters causing exceptions and the debugger context has none
56 // of these.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000057 Handle<Object> no_failure =
58 JSObject::SetElement(object, index, value, NONE, kNonStrictMode);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000059 ASSERT(!no_failure.is_null());
60 USE(no_failure);
61}
62
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000063// A simple implementation of dynamic programming algorithm. It solves
64// the problem of finding the difference of 2 arrays. It uses a table of results
65// of subproblems. Each cell contains a number together with 2-bit flag
66// that helps building the chunk list.
67class Differencer {
68 public:
lrn@chromium.orgc34f5802010-04-28 12:53:43 +000069 explicit Differencer(Comparator::Input* input)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000070 : input_(input), len1_(input->GetLength1()), len2_(input->GetLength2()) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000071 buffer_ = NewArray<int>(len1_ * len2_);
72 }
73 ~Differencer() {
74 DeleteArray(buffer_);
75 }
76
77 void Initialize() {
78 int array_size = len1_ * len2_;
79 for (int i = 0; i < array_size; i++) {
80 buffer_[i] = kEmptyCellValue;
81 }
82 }
83
84 // Makes sure that result for the full problem is calculated and stored
85 // in the table together with flags showing a path through subproblems.
86 void FillTable() {
87 CompareUpToTail(0, 0);
88 }
89
lrn@chromium.orgc34f5802010-04-28 12:53:43 +000090 void SaveResult(Comparator::Output* chunk_writer) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000091 ResultWriter writer(chunk_writer);
92
93 int pos1 = 0;
94 int pos2 = 0;
95 while (true) {
96 if (pos1 < len1_) {
97 if (pos2 < len2_) {
98 Direction dir = get_direction(pos1, pos2);
99 switch (dir) {
100 case EQ:
101 writer.eq();
102 pos1++;
103 pos2++;
104 break;
105 case SKIP1:
106 writer.skip1(1);
107 pos1++;
108 break;
109 case SKIP2:
110 case SKIP_ANY:
111 writer.skip2(1);
112 pos2++;
113 break;
114 default:
115 UNREACHABLE();
116 }
117 } else {
118 writer.skip1(len1_ - pos1);
119 break;
120 }
121 } else {
122 if (len2_ != pos2) {
123 writer.skip2(len2_ - pos2);
124 }
125 break;
126 }
127 }
128 writer.close();
129 }
130
131 private:
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000132 Comparator::Input* input_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000133 int* buffer_;
134 int len1_;
135 int len2_;
136
137 enum Direction {
138 EQ = 0,
139 SKIP1,
140 SKIP2,
141 SKIP_ANY,
142
143 MAX_DIRECTION_FLAG_VALUE = SKIP_ANY
144 };
145
146 // Computes result for a subtask and optionally caches it in the buffer table.
147 // All results values are shifted to make space for flags in the lower bits.
148 int CompareUpToTail(int pos1, int pos2) {
149 if (pos1 < len1_) {
150 if (pos2 < len2_) {
151 int cached_res = get_value4(pos1, pos2);
152 if (cached_res == kEmptyCellValue) {
153 Direction dir;
154 int res;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000155 if (input_->Equals(pos1, pos2)) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000156 res = CompareUpToTail(pos1 + 1, pos2 + 1);
157 dir = EQ;
158 } else {
159 int res1 = CompareUpToTail(pos1 + 1, pos2) +
160 (1 << kDirectionSizeBits);
161 int res2 = CompareUpToTail(pos1, pos2 + 1) +
162 (1 << kDirectionSizeBits);
163 if (res1 == res2) {
164 res = res1;
165 dir = SKIP_ANY;
166 } else if (res1 < res2) {
167 res = res1;
168 dir = SKIP1;
169 } else {
170 res = res2;
171 dir = SKIP2;
172 }
173 }
174 set_value4_and_dir(pos1, pos2, res, dir);
175 cached_res = res;
176 }
177 return cached_res;
178 } else {
179 return (len1_ - pos1) << kDirectionSizeBits;
180 }
181 } else {
182 return (len2_ - pos2) << kDirectionSizeBits;
183 }
184 }
185
186 inline int& get_cell(int i1, int i2) {
187 return buffer_[i1 + i2 * len1_];
188 }
189
190 // Each cell keeps a value plus direction. Value is multiplied by 4.
191 void set_value4_and_dir(int i1, int i2, int value4, Direction dir) {
192 ASSERT((value4 & kDirectionMask) == 0);
193 get_cell(i1, i2) = value4 | dir;
194 }
195
196 int get_value4(int i1, int i2) {
197 return get_cell(i1, i2) & (kMaxUInt32 ^ kDirectionMask);
198 }
199 Direction get_direction(int i1, int i2) {
200 return static_cast<Direction>(get_cell(i1, i2) & kDirectionMask);
201 }
202
203 static const int kDirectionSizeBits = 2;
204 static const int kDirectionMask = (1 << kDirectionSizeBits) - 1;
205 static const int kEmptyCellValue = -1 << kDirectionSizeBits;
206
207 // This method only holds static assert statement (unfortunately you cannot
208 // place one in class scope).
209 void StaticAssertHolder() {
210 STATIC_ASSERT(MAX_DIRECTION_FLAG_VALUE < (1 << kDirectionSizeBits));
211 }
212
213 class ResultWriter {
214 public:
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000215 explicit ResultWriter(Comparator::Output* chunk_writer)
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000216 : chunk_writer_(chunk_writer), pos1_(0), pos2_(0),
217 pos1_begin_(-1), pos2_begin_(-1), has_open_chunk_(false) {
218 }
219 void eq() {
220 FlushChunk();
221 pos1_++;
222 pos2_++;
223 }
224 void skip1(int len1) {
225 StartChunk();
226 pos1_ += len1;
227 }
228 void skip2(int len2) {
229 StartChunk();
230 pos2_ += len2;
231 }
232 void close() {
233 FlushChunk();
234 }
235
236 private:
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000237 Comparator::Output* chunk_writer_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000238 int pos1_;
239 int pos2_;
240 int pos1_begin_;
241 int pos2_begin_;
242 bool has_open_chunk_;
243
244 void StartChunk() {
245 if (!has_open_chunk_) {
246 pos1_begin_ = pos1_;
247 pos2_begin_ = pos2_;
248 has_open_chunk_ = true;
249 }
250 }
251
252 void FlushChunk() {
253 if (has_open_chunk_) {
254 chunk_writer_->AddChunk(pos1_begin_, pos2_begin_,
255 pos1_ - pos1_begin_, pos2_ - pos2_begin_);
256 has_open_chunk_ = false;
257 }
258 }
259 };
260};
261
262
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000263void Comparator::CalculateDifference(Comparator::Input* input,
264 Comparator::Output* result_writer) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000265 Differencer differencer(input);
266 differencer.Initialize();
267 differencer.FillTable();
268 differencer.SaveResult(result_writer);
269}
270
271
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000272static bool CompareSubstrings(Handle<String> s1, int pos1,
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000273 Handle<String> s2, int pos2, int len) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000274 for (int i = 0; i < len; i++) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000275 if (s1->Get(i + pos1) != s2->Get(i + pos2)) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000276 return false;
277 }
278 }
279 return true;
280}
281
282
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000283// Additional to Input interface. Lets switch Input range to subrange.
284// More elegant way would be to wrap one Input as another Input object
285// and translate positions there, but that would cost us additional virtual
286// call per comparison.
287class SubrangableInput : public Comparator::Input {
288 public:
289 virtual void SetSubrange1(int offset, int len) = 0;
290 virtual void SetSubrange2(int offset, int len) = 0;
291};
292
293
294class SubrangableOutput : public Comparator::Output {
295 public:
296 virtual void SetSubrange1(int offset, int len) = 0;
297 virtual void SetSubrange2(int offset, int len) = 0;
298};
299
300
301static int min(int a, int b) {
302 return a < b ? a : b;
303}
304
305
306// Finds common prefix and suffix in input. This parts shouldn't take space in
307// linear programming table. Enable subranging in input and output.
308static void NarrowDownInput(SubrangableInput* input,
309 SubrangableOutput* output) {
310 const int len1 = input->GetLength1();
311 const int len2 = input->GetLength2();
312
313 int common_prefix_len;
314 int common_suffix_len;
315
316 {
317 common_prefix_len = 0;
318 int prefix_limit = min(len1, len2);
319 while (common_prefix_len < prefix_limit &&
320 input->Equals(common_prefix_len, common_prefix_len)) {
321 common_prefix_len++;
322 }
323
324 common_suffix_len = 0;
325 int suffix_limit = min(len1 - common_prefix_len, len2 - common_prefix_len);
326
327 while (common_suffix_len < suffix_limit &&
328 input->Equals(len1 - common_suffix_len - 1,
329 len2 - common_suffix_len - 1)) {
330 common_suffix_len++;
331 }
332 }
333
334 if (common_prefix_len > 0 || common_suffix_len > 0) {
335 int new_len1 = len1 - common_suffix_len - common_prefix_len;
336 int new_len2 = len2 - common_suffix_len - common_prefix_len;
337
338 input->SetSubrange1(common_prefix_len, new_len1);
339 input->SetSubrange2(common_prefix_len, new_len2);
340
341 output->SetSubrange1(common_prefix_len, new_len1);
342 output->SetSubrange2(common_prefix_len, new_len2);
343 }
344}
345
346
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000347// A helper class that writes chunk numbers into JSArray.
348// Each chunk is stored as 3 array elements: (pos1_begin, pos1_end, pos2_end).
349class CompareOutputArrayWriter {
350 public:
351 CompareOutputArrayWriter()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000352 : array_(FACTORY->NewJSArray(10)), current_size_(0) {}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000353
354 Handle<JSArray> GetResult() {
355 return array_;
356 }
357
358 void WriteChunk(int char_pos1, int char_pos2, int char_len1, int char_len2) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000359 SetElementNonStrict(array_,
360 current_size_,
361 Handle<Object>(Smi::FromInt(char_pos1)));
362 SetElementNonStrict(array_,
363 current_size_ + 1,
364 Handle<Object>(Smi::FromInt(char_pos1 + char_len1)));
365 SetElementNonStrict(array_,
366 current_size_ + 2,
367 Handle<Object>(Smi::FromInt(char_pos2 + char_len2)));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000368 current_size_ += 3;
369 }
370
371 private:
372 Handle<JSArray> array_;
373 int current_size_;
374};
375
376
377// Represents 2 strings as 2 arrays of tokens.
378// TODO(LiveEdit): Currently it's actually an array of charactres.
379// Make array of tokens instead.
380class TokensCompareInput : public Comparator::Input {
381 public:
382 TokensCompareInput(Handle<String> s1, int offset1, int len1,
383 Handle<String> s2, int offset2, int len2)
384 : s1_(s1), offset1_(offset1), len1_(len1),
385 s2_(s2), offset2_(offset2), len2_(len2) {
386 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000387 virtual int GetLength1() {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000388 return len1_;
389 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000390 virtual int GetLength2() {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000391 return len2_;
392 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000393 bool Equals(int index1, int index2) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000394 return s1_->Get(offset1_ + index1) == s2_->Get(offset2_ + index2);
395 }
396
397 private:
398 Handle<String> s1_;
399 int offset1_;
400 int len1_;
401 Handle<String> s2_;
402 int offset2_;
403 int len2_;
404};
405
406
407// Stores compare result in JSArray. Converts substring positions
408// to absolute positions.
409class TokensCompareOutput : public Comparator::Output {
410 public:
411 TokensCompareOutput(CompareOutputArrayWriter* array_writer,
412 int offset1, int offset2)
413 : array_writer_(array_writer), offset1_(offset1), offset2_(offset2) {
414 }
415
416 void AddChunk(int pos1, int pos2, int len1, int len2) {
417 array_writer_->WriteChunk(pos1 + offset1_, pos2 + offset2_, len1, len2);
418 }
419
420 private:
421 CompareOutputArrayWriter* array_writer_;
422 int offset1_;
423 int offset2_;
424};
425
426
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000427// Wraps raw n-elements line_ends array as a list of n+1 lines. The last line
428// never has terminating new line character.
429class LineEndsWrapper {
430 public:
431 explicit LineEndsWrapper(Handle<String> string)
432 : ends_array_(CalculateLineEnds(string, false)),
433 string_len_(string->length()) {
434 }
435 int length() {
436 return ends_array_->length() + 1;
437 }
438 // Returns start for any line including start of the imaginary line after
439 // the last line.
440 int GetLineStart(int index) {
441 if (index == 0) {
442 return 0;
443 } else {
444 return GetLineEnd(index - 1);
445 }
446 }
447 int GetLineEnd(int index) {
448 if (index == ends_array_->length()) {
449 // End of the last line is always an end of the whole string.
450 // If the string ends with a new line character, the last line is an
451 // empty string after this character.
452 return string_len_;
453 } else {
454 return GetPosAfterNewLine(index);
455 }
456 }
457
458 private:
459 Handle<FixedArray> ends_array_;
460 int string_len_;
461
462 int GetPosAfterNewLine(int index) {
463 return Smi::cast(ends_array_->get(index))->value() + 1;
464 }
465};
466
467
468// Represents 2 strings as 2 arrays of lines.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000469class LineArrayCompareInput : public SubrangableInput {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000470 public:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000471 LineArrayCompareInput(Handle<String> s1, Handle<String> s2,
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000472 LineEndsWrapper line_ends1, LineEndsWrapper line_ends2)
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000473 : s1_(s1), s2_(s2), line_ends1_(line_ends1),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000474 line_ends2_(line_ends2),
475 subrange_offset1_(0), subrange_offset2_(0),
476 subrange_len1_(line_ends1_.length()),
477 subrange_len2_(line_ends2_.length()) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000478 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000479 int GetLength1() {
480 return subrange_len1_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000481 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000482 int GetLength2() {
483 return subrange_len2_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000484 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000485 bool Equals(int index1, int index2) {
486 index1 += subrange_offset1_;
487 index2 += subrange_offset2_;
488
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000489 int line_start1 = line_ends1_.GetLineStart(index1);
490 int line_start2 = line_ends2_.GetLineStart(index2);
491 int line_end1 = line_ends1_.GetLineEnd(index1);
492 int line_end2 = line_ends2_.GetLineEnd(index2);
493 int len1 = line_end1 - line_start1;
494 int len2 = line_end2 - line_start2;
495 if (len1 != len2) {
496 return false;
497 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000498 return CompareSubstrings(s1_, line_start1, s2_, line_start2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000499 len1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000500 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000501 void SetSubrange1(int offset, int len) {
502 subrange_offset1_ = offset;
503 subrange_len1_ = len;
504 }
505 void SetSubrange2(int offset, int len) {
506 subrange_offset2_ = offset;
507 subrange_len2_ = len;
508 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000509
510 private:
511 Handle<String> s1_;
512 Handle<String> s2_;
513 LineEndsWrapper line_ends1_;
514 LineEndsWrapper line_ends2_;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000515 int subrange_offset1_;
516 int subrange_offset2_;
517 int subrange_len1_;
518 int subrange_len2_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000519};
520
521
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000522// Stores compare result in JSArray. For each chunk tries to conduct
523// a fine-grained nested diff token-wise.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000524class TokenizingLineArrayCompareOutput : public SubrangableOutput {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000525 public:
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000526 TokenizingLineArrayCompareOutput(LineEndsWrapper line_ends1,
527 LineEndsWrapper line_ends2,
528 Handle<String> s1, Handle<String> s2)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000529 : line_ends1_(line_ends1), line_ends2_(line_ends2), s1_(s1), s2_(s2),
530 subrange_offset1_(0), subrange_offset2_(0) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000531 }
532
533 void AddChunk(int line_pos1, int line_pos2, int line_len1, int line_len2) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000534 line_pos1 += subrange_offset1_;
535 line_pos2 += subrange_offset2_;
536
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000537 int char_pos1 = line_ends1_.GetLineStart(line_pos1);
538 int char_pos2 = line_ends2_.GetLineStart(line_pos2);
539 int char_len1 = line_ends1_.GetLineStart(line_pos1 + line_len1) - char_pos1;
540 int char_len2 = line_ends2_.GetLineStart(line_pos2 + line_len2) - char_pos2;
541
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000542 if (char_len1 < CHUNK_LEN_LIMIT && char_len2 < CHUNK_LEN_LIMIT) {
543 // Chunk is small enough to conduct a nested token-level diff.
544 HandleScope subTaskScope;
545
546 TokensCompareInput tokens_input(s1_, char_pos1, char_len1,
547 s2_, char_pos2, char_len2);
548 TokensCompareOutput tokens_output(&array_writer_, char_pos1,
549 char_pos2);
550
551 Comparator::CalculateDifference(&tokens_input, &tokens_output);
552 } else {
553 array_writer_.WriteChunk(char_pos1, char_pos2, char_len1, char_len2);
554 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000555 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000556 void SetSubrange1(int offset, int len) {
557 subrange_offset1_ = offset;
558 }
559 void SetSubrange2(int offset, int len) {
560 subrange_offset2_ = offset;
561 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000562
563 Handle<JSArray> GetResult() {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000564 return array_writer_.GetResult();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000565 }
566
567 private:
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000568 static const int CHUNK_LEN_LIMIT = 800;
569
570 CompareOutputArrayWriter array_writer_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000571 LineEndsWrapper line_ends1_;
572 LineEndsWrapper line_ends2_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000573 Handle<String> s1_;
574 Handle<String> s2_;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000575 int subrange_offset1_;
576 int subrange_offset2_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000577};
578
579
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000580Handle<JSArray> LiveEdit::CompareStrings(Handle<String> s1,
581 Handle<String> s2) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000582 s1 = FlattenGetString(s1);
583 s2 = FlattenGetString(s2);
584
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000585 LineEndsWrapper line_ends1(s1);
586 LineEndsWrapper line_ends2(s2);
587
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000588 LineArrayCompareInput input(s1, s2, line_ends1, line_ends2);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000589 TokenizingLineArrayCompareOutput output(line_ends1, line_ends2, s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000590
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000591 NarrowDownInput(&input, &output);
592
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000593 Comparator::CalculateDifference(&input, &output);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000594
595 return output.GetResult();
596}
597
598
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599static void CompileScriptForTracker(Isolate* isolate, Handle<Script> script) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000600 // TODO(635): support extensions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000601 PostponeInterruptsScope postpone(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000602
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000603 // Build AST.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000604 CompilationInfoWithZone info(script);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000605 info.MarkAsGlobal();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000606 // Parse and don't allow skipping lazy functions.
607 if (ParserApi::Parse(&info, kNoParsingFlags)) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000608 // Compile the code.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000609 LiveEditFunctionTracker tracker(info.isolate(), info.function());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000610 if (Compiler::MakeCodeForLiveEdit(&info)) {
611 ASSERT(!info.code().is_null());
612 tracker.RecordRootFunctionInfo(info.code());
613 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 info.isolate()->StackOverflow();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000615 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000616 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000617}
618
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000619
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000620// Unwraps JSValue object, returning its field "value"
621static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) {
622 return Handle<Object>(jsValue->value());
623}
624
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000625
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000626// Wraps any object into a OpaqueReference, that will hide the object
627// from JavaScript.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000628static Handle<JSValue> WrapInJSValue(Handle<Object> object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000629 Handle<JSFunction> constructor =
630 Isolate::Current()->opaque_reference_function();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000631 Handle<JSValue> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000632 Handle<JSValue>::cast(FACTORY->NewJSObject(constructor));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000633 result->set_value(*object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000634 return result;
635}
636
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000637
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000638// Simple helper class that creates more or less typed structures over
639// JSArray object. This is an adhoc method of passing structures from C++
640// to JavaScript.
641template<typename S>
642class JSArrayBasedStruct {
643 public:
644 static S Create() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000645 Handle<JSArray> array = FACTORY->NewJSArray(S::kSize_);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000646 return S(array);
647 }
648 static S cast(Object* object) {
649 JSArray* array = JSArray::cast(object);
650 Handle<JSArray> array_handle(array);
651 return S(array_handle);
652 }
653 explicit JSArrayBasedStruct(Handle<JSArray> array) : array_(array) {
654 }
655 Handle<JSArray> GetJSArray() {
656 return array_;
657 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000658
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000659 protected:
660 void SetField(int field_position, Handle<Object> value) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000661 SetElementNonStrict(array_, field_position, value);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000662 }
663 void SetSmiValueField(int field_position, int value) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000664 SetElementNonStrict(array_,
665 field_position,
666 Handle<Smi>(Smi::FromInt(value)));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000667 }
668 Object* GetField(int field_position) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000669 return array_->GetElementNoExceptionThrown(field_position);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000670 }
671 int GetSmiValueField(int field_position) {
672 Object* res = GetField(field_position);
673 return Smi::cast(res)->value();
674 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000675
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000676 private:
677 Handle<JSArray> array_;
678};
679
680
681// Represents some function compilation details. This structure will be used
682// from JavaScript. It contains Code object, which is kept wrapped
683// into a BlindReference for sanitizing reasons.
684class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
685 public:
686 explicit FunctionInfoWrapper(Handle<JSArray> array)
687 : JSArrayBasedStruct<FunctionInfoWrapper>(array) {
688 }
689 void SetInitialProperties(Handle<String> name, int start_position,
690 int end_position, int param_num, int parent_index) {
691 HandleScope scope;
692 this->SetField(kFunctionNameOffset_, name);
693 this->SetSmiValueField(kStartPositionOffset_, start_position);
694 this->SetSmiValueField(kEndPositionOffset_, end_position);
695 this->SetSmiValueField(kParamNumOffset_, param_num);
696 this->SetSmiValueField(kParentIndexOffset_, parent_index);
697 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000698 void SetFunctionCode(Handle<Code> function_code,
699 Handle<Object> code_scope_info) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000700 Handle<JSValue> code_wrapper = WrapInJSValue(function_code);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000701 this->SetField(kCodeOffset_, code_wrapper);
702
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000703 Handle<JSValue> scope_wrapper = WrapInJSValue(code_scope_info);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000704 this->SetField(kCodeScopeInfoOffset_, scope_wrapper);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000705 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000706 void SetOuterScopeInfo(Handle<Object> scope_info_array) {
707 this->SetField(kOuterScopeInfoOffset_, scope_info_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000708 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000709 void SetSharedFunctionInfo(Handle<SharedFunctionInfo> info) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000710 Handle<JSValue> info_holder = WrapInJSValue(info);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000711 this->SetField(kSharedFunctionInfoOffset_, info_holder);
712 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000713 int GetParentIndex() {
714 return this->GetSmiValueField(kParentIndexOffset_);
715 }
716 Handle<Code> GetFunctionCode() {
717 Handle<Object> raw_result = UnwrapJSValue(Handle<JSValue>(
718 JSValue::cast(this->GetField(kCodeOffset_))));
719 return Handle<Code>::cast(raw_result);
720 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000721 Handle<Object> GetCodeScopeInfo() {
722 Handle<Object> raw_result = UnwrapJSValue(Handle<JSValue>(
723 JSValue::cast(this->GetField(kCodeScopeInfoOffset_))));
724 return raw_result;
725 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000726 int GetStartPosition() {
727 return this->GetSmiValueField(kStartPositionOffset_);
728 }
729 int GetEndPosition() {
730 return this->GetSmiValueField(kEndPositionOffset_);
731 }
732
733 private:
734 static const int kFunctionNameOffset_ = 0;
735 static const int kStartPositionOffset_ = 1;
736 static const int kEndPositionOffset_ = 2;
737 static const int kParamNumOffset_ = 3;
738 static const int kCodeOffset_ = 4;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000739 static const int kCodeScopeInfoOffset_ = 5;
740 static const int kOuterScopeInfoOffset_ = 6;
741 static const int kParentIndexOffset_ = 7;
742 static const int kSharedFunctionInfoOffset_ = 8;
743 static const int kSize_ = 9;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000744
745 friend class JSArrayBasedStruct<FunctionInfoWrapper>;
746};
747
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000748
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000749// Wraps SharedFunctionInfo along with some of its fields for passing it
750// back to JavaScript. SharedFunctionInfo object itself is additionally
751// wrapped into BlindReference for sanitizing reasons.
752class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> {
753 public:
ager@chromium.orgac091b72010-05-05 07:34:42 +0000754 static bool IsInstance(Handle<JSArray> array) {
755 return array->length() == Smi::FromInt(kSize_) &&
lrn@chromium.org303ada72010-10-27 09:33:13 +0000756 array->GetElementNoExceptionThrown(kSharedInfoOffset_)->IsJSValue();
ager@chromium.orgac091b72010-05-05 07:34:42 +0000757 }
758
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000759 explicit SharedInfoWrapper(Handle<JSArray> array)
760 : JSArrayBasedStruct<SharedInfoWrapper>(array) {
761 }
762
763 void SetProperties(Handle<String> name, int start_position, int end_position,
764 Handle<SharedFunctionInfo> info) {
765 HandleScope scope;
766 this->SetField(kFunctionNameOffset_, name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000767 Handle<JSValue> info_holder = WrapInJSValue(info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000768 this->SetField(kSharedInfoOffset_, info_holder);
769 this->SetSmiValueField(kStartPositionOffset_, start_position);
770 this->SetSmiValueField(kEndPositionOffset_, end_position);
771 }
772 Handle<SharedFunctionInfo> GetInfo() {
773 Object* element = this->GetField(kSharedInfoOffset_);
774 Handle<JSValue> value_wrapper(JSValue::cast(element));
775 Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
776 return Handle<SharedFunctionInfo>::cast(raw_result);
777 }
778
779 private:
780 static const int kFunctionNameOffset_ = 0;
781 static const int kStartPositionOffset_ = 1;
782 static const int kEndPositionOffset_ = 2;
783 static const int kSharedInfoOffset_ = 3;
784 static const int kSize_ = 4;
785
786 friend class JSArrayBasedStruct<SharedInfoWrapper>;
787};
788
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000789
ager@chromium.org5c838252010-02-19 08:53:10 +0000790class FunctionInfoListener {
791 public:
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000792 FunctionInfoListener() {
793 current_parent_index_ = -1;
794 len_ = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000795 result_ = FACTORY->NewJSArray(10);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000796 }
797
ager@chromium.org5c838252010-02-19 08:53:10 +0000798 void FunctionStarted(FunctionLiteral* fun) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000799 HandleScope scope;
800 FunctionInfoWrapper info = FunctionInfoWrapper::Create();
801 info.SetInitialProperties(fun->name(), fun->start_position(),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000802 fun->end_position(), fun->parameter_count(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000803 current_parent_index_);
804 current_parent_index_ = len_;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000805 SetElementNonStrict(result_, len_, info.GetJSArray());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000806 len_++;
ager@chromium.org5c838252010-02-19 08:53:10 +0000807 }
808
809 void FunctionDone() {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000810 HandleScope scope;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000811 FunctionInfoWrapper info =
812 FunctionInfoWrapper::cast(
813 result_->GetElementNoExceptionThrown(current_parent_index_));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000814 current_parent_index_ = info.GetParentIndex();
ager@chromium.org5c838252010-02-19 08:53:10 +0000815 }
816
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000817 // Saves only function code, because for a script function we
818 // may never create a SharedFunctionInfo object.
819 void FunctionCode(Handle<Code> function_code) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000820 FunctionInfoWrapper info =
821 FunctionInfoWrapper::cast(
822 result_->GetElementNoExceptionThrown(current_parent_index_));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000823 info.SetFunctionCode(function_code, Handle<Object>(HEAP->null_value()));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000824 }
825
826 // Saves full information about a function: its code, its scope info
827 // and a SharedFunctionInfo object.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000828 void FunctionInfo(Handle<SharedFunctionInfo> shared, Scope* scope,
829 Zone* zone) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000830 if (!shared->IsSharedFunctionInfo()) {
831 return;
832 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000833 FunctionInfoWrapper info =
834 FunctionInfoWrapper::cast(
835 result_->GetElementNoExceptionThrown(current_parent_index_));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000836 info.SetFunctionCode(Handle<Code>(shared->code()),
837 Handle<Object>(shared->scope_info()));
838 info.SetSharedFunctionInfo(shared);
839
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000840 Handle<Object> scope_info_list(SerializeFunctionScope(scope, zone));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000841 info.SetOuterScopeInfo(scope_info_list);
842 }
843
844 Handle<JSArray> GetResult() { return result_; }
845
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000846 private:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000847 Object* SerializeFunctionScope(Scope* scope, Zone* zone) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000848 HandleScope handle_scope;
849
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000850 Handle<JSArray> scope_info_list = FACTORY->NewJSArray(10);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000851 int scope_info_length = 0;
852
853 // Saves some description of scope. It stores name and indexes of
854 // variables in the whole scope chain. Null-named slots delimit
855 // scopes of this chain.
856 Scope* outer_scope = scope->outer_scope();
857 if (outer_scope == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000858 return HEAP->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000859 }
860 do {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000861 ZoneList<Variable*> stack_list(outer_scope->StackLocalCount(), zone);
862 ZoneList<Variable*> context_list(outer_scope->ContextLocalCount(), zone);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000863 outer_scope->CollectStackAndContextLocals(&stack_list, &context_list);
864 context_list.Sort(&Variable::CompareIndex);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000865
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000866 for (int i = 0; i < context_list.length(); i++) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000867 SetElementNonStrict(scope_info_list,
868 scope_info_length,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000869 context_list[i]->name());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000870 scope_info_length++;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000871 SetElementNonStrict(
872 scope_info_list,
873 scope_info_length,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000874 Handle<Smi>(Smi::FromInt(context_list[i]->index())));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000875 scope_info_length++;
876 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000877 SetElementNonStrict(scope_info_list,
878 scope_info_length,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000879 Handle<Object>(HEAP->null_value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000880 scope_info_length++;
881
882 outer_scope = outer_scope->outer_scope();
883 } while (outer_scope != NULL);
884
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000885 return *scope_info_list;
ager@chromium.org5c838252010-02-19 08:53:10 +0000886 }
887
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000888 Handle<JSArray> result_;
889 int len_;
890 int current_parent_index_;
ager@chromium.org5c838252010-02-19 08:53:10 +0000891};
892
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000893
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000894JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script,
895 Handle<String> source) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000896 Isolate* isolate = Isolate::Current();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000897
898 FunctionInfoListener listener;
899 Handle<Object> original_source = Handle<Object>(script->source());
900 script->set_source(*source);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000901 isolate->set_active_function_info_listener(&listener);
902 CompileScriptForTracker(isolate, script);
903 isolate->set_active_function_info_listener(NULL);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000904 script->set_source(*original_source);
905
906 return *(listener.GetResult());
907}
908
909
910void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> array) {
911 HandleScope scope;
912 int len = Smi::cast(array->length())->value();
913 for (int i = 0; i < len; i++) {
914 Handle<SharedFunctionInfo> info(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000915 SharedFunctionInfo::cast(array->GetElementNoExceptionThrown(i)));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000916 SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create();
917 Handle<String> name_handle(String::cast(info->name()));
918 info_wrapper.SetProperties(name_handle, info->start_position(),
919 info->end_position(), info);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000920 SetElementNonStrict(array, i, info_wrapper.GetJSArray());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000921 }
922}
923
924
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000925// Visitor that finds all references to a particular code object,
926// including "CODE_TARGET" references in other code objects and replaces
927// them on the fly.
928class ReplacingVisitor : public ObjectVisitor {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000929 public:
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000930 explicit ReplacingVisitor(Code* original, Code* substitution)
931 : original_(original), substitution_(substitution) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000932 }
933
934 virtual void VisitPointers(Object** start, Object** end) {
935 for (Object** p = start; p < end; p++) {
936 if (*p == original_) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000937 *p = substitution_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000938 }
939 }
940 }
941
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000942 virtual void VisitCodeEntry(Address entry) {
943 if (Code::GetObjectFromEntryAddress(entry) == original_) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000944 Address substitution_entry = substitution_->instruction_start();
945 Memory::Address_at(entry) = substitution_entry;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000946 }
947 }
948
949 virtual void VisitCodeTarget(RelocInfo* rinfo) {
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000950 if (RelocInfo::IsCodeTarget(rinfo->rmode()) &&
951 Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000952 Address substitution_entry = substitution_->instruction_start();
953 rinfo->set_target_address(substitution_entry);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000954 }
955 }
956
957 virtual void VisitDebugTarget(RelocInfo* rinfo) {
958 VisitCodeTarget(rinfo);
959 }
960
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000961 private:
962 Code* original_;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000963 Code* substitution_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000964};
965
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000966
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000967// Finds all references to original and replaces them with substitution.
968static void ReplaceCodeObject(Code* original, Code* substitution) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 ASSERT(!HEAP->InNewSpace(substitution));
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000970
971 AssertNoAllocation no_allocations_please;
972
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000973 ReplacingVisitor visitor(original, substitution);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000974
975 // Iterate over all roots. Stack frames may have pointer into original code,
976 // so temporary replace the pointers with offset numbers
977 // in prologue/epilogue.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000978 HEAP->IterateRoots(&visitor, VISIT_ALL);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000979
980 // Now iterate over all pointers of all objects, including code_target
981 // implicit pointers.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000982 HeapIterator iterator;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000983 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
984 obj->Iterate(&visitor);
985 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000986}
987
988
ager@chromium.org357bf652010-04-12 11:30:10 +0000989// Check whether the code is natural function code (not a lazy-compile stub
990// code).
991static bool IsJSFunctionCode(Code* code) {
992 return code->kind() == Code::FUNCTION;
993}
994
995
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000996// Returns true if an instance of candidate were inlined into function's code.
997static bool IsInlined(JSFunction* function, SharedFunctionInfo* candidate) {
998 AssertNoAllocation no_gc;
999
1000 if (function->code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
1001
1002 DeoptimizationInputData* data =
1003 DeoptimizationInputData::cast(function->code()->deoptimization_data());
1004
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001005 if (data == HEAP->empty_fixed_array()) return false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001006
1007 FixedArray* literals = data->LiteralArray();
1008
1009 int inlined_count = data->InlinedFunctionCount()->value();
1010 for (int i = 0; i < inlined_count; ++i) {
1011 JSFunction* inlined = JSFunction::cast(literals->get(i));
1012 if (inlined->shared() == candidate) return true;
1013 }
1014
1015 return false;
1016}
1017
1018
1019class DependentFunctionsDeoptimizingVisitor : public OptimizedFunctionVisitor {
1020 public:
1021 explicit DependentFunctionsDeoptimizingVisitor(
1022 SharedFunctionInfo* function_info)
1023 : function_info_(function_info) {}
1024
1025 virtual void EnterContext(Context* context) {
1026 }
1027
1028 virtual void VisitFunction(JSFunction* function) {
1029 if (function->shared() == function_info_ ||
1030 IsInlined(function, function_info_)) {
1031 Deoptimizer::DeoptimizeFunction(function);
1032 }
1033 }
1034
1035 virtual void LeaveContext(Context* context) {
1036 }
1037
1038 private:
1039 SharedFunctionInfo* function_info_;
1040};
1041
1042
1043static void DeoptimizeDependentFunctions(SharedFunctionInfo* function_info) {
1044 AssertNoAllocation no_allocation;
1045
1046 DependentFunctionsDeoptimizingVisitor visitor(function_info);
1047 Deoptimizer::VisitAllOptimizedFunctions(&visitor);
1048}
1049
1050
lrn@chromium.org303ada72010-10-27 09:33:13 +00001051MaybeObject* LiveEdit::ReplaceFunctionCode(
1052 Handle<JSArray> new_compile_info_array,
1053 Handle<JSArray> shared_info_array) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001054 HandleScope scope;
1055
ager@chromium.orgac091b72010-05-05 07:34:42 +00001056 if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001057 return Isolate::Current()->ThrowIllegalOperation();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001058 }
1059
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001060 FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
1061 SharedInfoWrapper shared_info_wrapper(shared_info_array);
1062
1063 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
1064
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001065 HEAP->EnsureHeapIsIterable();
1066
ager@chromium.org357bf652010-04-12 11:30:10 +00001067 if (IsJSFunctionCode(shared_info->code())) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001068 Handle<Code> code = compile_info_wrapper.GetFunctionCode();
1069 ReplaceCodeObject(shared_info->code(), *code);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001070 Handle<Object> code_scope_info = compile_info_wrapper.GetCodeScopeInfo();
1071 if (code_scope_info->IsFixedArray()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001072 shared_info->set_scope_info(ScopeInfo::cast(*code_scope_info));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001073 }
ager@chromium.org357bf652010-04-12 11:30:10 +00001074 }
1075
1076 if (shared_info->debug_info()->IsDebugInfo()) {
1077 Handle<DebugInfo> debug_info(DebugInfo::cast(shared_info->debug_info()));
1078 Handle<Code> new_original_code =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001079 FACTORY->CopyCode(compile_info_wrapper.GetFunctionCode());
ager@chromium.org357bf652010-04-12 11:30:10 +00001080 debug_info->set_original_code(*new_original_code);
1081 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001083 int start_position = compile_info_wrapper.GetStartPosition();
1084 int end_position = compile_info_wrapper.GetEndPosition();
1085 shared_info->set_start_position(start_position);
1086 shared_info->set_end_position(end_position);
ager@chromium.org357bf652010-04-12 11:30:10 +00001087
1088 shared_info->set_construct_stub(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 Isolate::Current()->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001090 Builtins::kJSConstructStubGeneric));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001091
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001092 DeoptimizeDependentFunctions(*shared_info);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001093 Isolate::Current()->compilation_cache()->Remove(shared_info);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001094
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001095 return HEAP->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001096}
1097
1098
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001099MaybeObject* LiveEdit::FunctionSourceUpdated(
1100 Handle<JSArray> shared_info_array) {
1101 HandleScope scope;
1102
1103 if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001104 return Isolate::Current()->ThrowIllegalOperation();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001105 }
1106
1107 SharedInfoWrapper shared_info_wrapper(shared_info_array);
1108 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
1109
1110 DeoptimizeDependentFunctions(*shared_info);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001111 Isolate::Current()->compilation_cache()->Remove(shared_info);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001112
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001113 return HEAP->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001114}
1115
1116
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001117void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
1118 Handle<Object> script_handle) {
1119 Handle<SharedFunctionInfo> shared_info =
1120 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(function_wrapper));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001121 shared_info->set_script(*script_handle);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001122
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001123 Isolate::Current()->compilation_cache()->Remove(shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001124}
1125
1126
1127// For a script text change (defined as position_change_array), translates
1128// position in unchanged text to position in changed text.
1129// Text change is a set of non-overlapping regions in text, that have changed
1130// their contents and length. It is specified as array of groups of 3 numbers:
1131// (change_begin, change_end, change_end_new_position).
1132// Each group describes a change in text; groups are sorted by change_begin.
1133// Only position in text beyond any changes may be successfully translated.
1134// If a positions is inside some region that changed, result is currently
1135// undefined.
1136static int TranslatePosition(int original_position,
1137 Handle<JSArray> position_change_array) {
1138 int position_diff = 0;
1139 int array_len = Smi::cast(position_change_array->length())->value();
1140 // TODO(635): binary search may be used here
1141 for (int i = 0; i < array_len; i += 3) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001142 Object* element = position_change_array->GetElementNoExceptionThrown(i);
1143 int chunk_start = Smi::cast(element)->value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001144 if (original_position < chunk_start) {
1145 break;
1146 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001147 element = position_change_array->GetElementNoExceptionThrown(i + 1);
1148 int chunk_end = Smi::cast(element)->value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001149 // Position mustn't be inside a chunk.
1150 ASSERT(original_position >= chunk_end);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001151 element = position_change_array->GetElementNoExceptionThrown(i + 2);
1152 int chunk_changed_end = Smi::cast(element)->value();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001153 position_diff = chunk_changed_end - chunk_end;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001154 }
1155
1156 return original_position + position_diff;
1157}
1158
1159
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001160// Auto-growing buffer for writing relocation info code section. This buffer
1161// is a simplified version of buffer from Assembler. Unlike Assembler, this
1162// class is platform-independent and it works without dealing with instructions.
1163// As specified by RelocInfo format, the buffer is filled in reversed order:
1164// from upper to lower addresses.
1165// It uses NewArray/DeleteArray for memory management.
1166class RelocInfoBuffer {
1167 public:
1168 RelocInfoBuffer(int buffer_initial_capicity, byte* pc) {
1169 buffer_size_ = buffer_initial_capicity + kBufferGap;
1170 buffer_ = NewArray<byte>(buffer_size_);
1171
1172 reloc_info_writer_.Reposition(buffer_ + buffer_size_, pc);
1173 }
1174 ~RelocInfoBuffer() {
1175 DeleteArray(buffer_);
1176 }
1177
1178 // As specified by RelocInfo format, the buffer is filled in reversed order:
1179 // from upper to lower addresses.
1180 void Write(const RelocInfo* rinfo) {
1181 if (buffer_ + kBufferGap >= reloc_info_writer_.pos()) {
1182 Grow();
1183 }
1184 reloc_info_writer_.Write(rinfo);
1185 }
1186
1187 Vector<byte> GetResult() {
1188 // Return the bytes from pos up to end of buffer.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001189 int result_size =
1190 static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer_.pos());
1191 return Vector<byte>(reloc_info_writer_.pos(), result_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001192 }
1193
1194 private:
1195 void Grow() {
1196 // Compute new buffer size.
1197 int new_buffer_size;
1198 if (buffer_size_ < 2 * KB) {
1199 new_buffer_size = 4 * KB;
1200 } else {
1201 new_buffer_size = 2 * buffer_size_;
1202 }
1203 // Some internal data structures overflow for very large buffers,
1204 // they must ensure that kMaximalBufferSize is not too large.
1205 if (new_buffer_size > kMaximalBufferSize) {
1206 V8::FatalProcessOutOfMemory("RelocInfoBuffer::GrowBuffer");
1207 }
1208
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001209 // Set up new buffer.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001210 byte* new_buffer = NewArray<byte>(new_buffer_size);
1211
1212 // Copy the data.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001213 int curently_used_size =
1214 static_cast<int>(buffer_ + buffer_size_ - reloc_info_writer_.pos());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001215 memmove(new_buffer + new_buffer_size - curently_used_size,
1216 reloc_info_writer_.pos(), curently_used_size);
1217
1218 reloc_info_writer_.Reposition(
1219 new_buffer + new_buffer_size - curently_used_size,
1220 reloc_info_writer_.last_pc());
1221
1222 DeleteArray(buffer_);
1223 buffer_ = new_buffer;
1224 buffer_size_ = new_buffer_size;
1225 }
1226
1227 RelocInfoWriter reloc_info_writer_;
1228 byte* buffer_;
1229 int buffer_size_;
1230
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001231 static const int kBufferGap = RelocInfoWriter::kMaxSize;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001232 static const int kMaximalBufferSize = 512*MB;
1233};
1234
1235// Patch positions in code (changes relocation info section) and possibly
1236// returns new instance of code.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001237static Handle<Code> PatchPositionsInCode(
1238 Handle<Code> code,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001239 Handle<JSArray> position_change_array) {
1240
1241 RelocInfoBuffer buffer_writer(code->relocation_size(),
1242 code->instruction_start());
1243
1244 {
1245 AssertNoAllocation no_allocations_please;
1246 for (RelocIterator it(*code); !it.done(); it.next()) {
1247 RelocInfo* rinfo = it.rinfo();
1248 if (RelocInfo::IsPosition(rinfo->rmode())) {
1249 int position = static_cast<int>(rinfo->data());
1250 int new_position = TranslatePosition(position,
1251 position_change_array);
1252 if (position != new_position) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001253 RelocInfo info_copy(rinfo->pc(), rinfo->rmode(), new_position, NULL);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001254 buffer_writer.Write(&info_copy);
1255 continue;
1256 }
1257 }
1258 buffer_writer.Write(it.rinfo());
1259 }
1260 }
1261
1262 Vector<byte> buffer = buffer_writer.GetResult();
1263
1264 if (buffer.length() == code->relocation_size()) {
1265 // Simply patch relocation area of code.
1266 memcpy(code->relocation_start(), buffer.start(), buffer.length());
1267 return code;
1268 } else {
1269 // Relocation info section now has different size. We cannot simply
1270 // rewrite it inside code object. Instead we have to create a new
1271 // code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001272 Handle<Code> result(FACTORY->CopyCode(code, buffer));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001273 return result;
1274 }
1275}
1276
1277
lrn@chromium.org303ada72010-10-27 09:33:13 +00001278MaybeObject* LiveEdit::PatchFunctionPositions(
ager@chromium.org357bf652010-04-12 11:30:10 +00001279 Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001280
1281 if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001282 return Isolate::Current()->ThrowIllegalOperation();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001283 }
1284
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001285 SharedInfoWrapper shared_info_wrapper(shared_info_array);
1286 Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo();
1287
ager@chromium.org357bf652010-04-12 11:30:10 +00001288 int old_function_start = info->start_position();
1289 int new_function_start = TranslatePosition(old_function_start,
1290 position_change_array);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001291 int new_function_end = TranslatePosition(info->end_position(),
1292 position_change_array);
1293 int new_function_token_pos =
1294 TranslatePosition(info->function_token_position(), position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001295
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001296 info->set_start_position(new_function_start);
1297 info->set_end_position(new_function_end);
1298 info->set_function_token_position(new_function_token_pos);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001299
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 HEAP->EnsureHeapIsIterable();
1301
ager@chromium.org357bf652010-04-12 11:30:10 +00001302 if (IsJSFunctionCode(info->code())) {
1303 // Patch relocation info section of the code.
1304 Handle<Code> patched_code = PatchPositionsInCode(Handle<Code>(info->code()),
1305 position_change_array);
1306 if (*patched_code != info->code()) {
1307 // Replace all references to the code across the heap. In particular,
1308 // some stubs may refer to this code and this code may be being executed
1309 // on stack (it is safe to substitute the code object on stack, because
1310 // we only change the structure of rinfo and leave instructions
1311 // untouched).
1312 ReplaceCodeObject(info->code(), *patched_code);
1313 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001314 }
ager@chromium.orgac091b72010-05-05 07:34:42 +00001315
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001316 return HEAP->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001317}
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001318
ager@chromium.org357bf652010-04-12 11:30:10 +00001319
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001320static Handle<Script> CreateScriptCopy(Handle<Script> original) {
1321 Handle<String> original_source(String::cast(original->source()));
ager@chromium.org357bf652010-04-12 11:30:10 +00001322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001323 Handle<Script> copy = FACTORY->NewScript(original_source);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001324
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001325 copy->set_name(original->name());
1326 copy->set_line_offset(original->line_offset());
1327 copy->set_column_offset(original->column_offset());
1328 copy->set_data(original->data());
1329 copy->set_type(original->type());
1330 copy->set_context_data(original->context_data());
1331 copy->set_compilation_type(original->compilation_type());
1332 copy->set_eval_from_shared(original->eval_from_shared());
1333 copy->set_eval_from_instructions_offset(
1334 original->eval_from_instructions_offset());
1335
1336 return copy;
1337}
1338
1339
1340Object* LiveEdit::ChangeScriptSource(Handle<Script> original_script,
1341 Handle<String> new_source,
1342 Handle<Object> old_script_name) {
1343 Handle<Object> old_script_object;
1344 if (old_script_name->IsString()) {
1345 Handle<Script> old_script = CreateScriptCopy(original_script);
1346 old_script->set_name(String::cast(*old_script_name));
1347 old_script_object = old_script;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001348 Isolate::Current()->debugger()->OnAfterCompile(
1349 old_script, Debugger::SEND_WHEN_DEBUGGING);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001350 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001351 old_script_object = Handle<Object>(HEAP->null_value());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001352 }
1353
1354 original_script->set_source(*new_source);
1355
1356 // Drop line ends so that they will be recalculated.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001357 original_script->set_line_ends(HEAP->undefined_value());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001358
1359 return *old_script_object;
1360}
1361
1362
1363
1364void LiveEdit::ReplaceRefToNestedFunction(
1365 Handle<JSValue> parent_function_wrapper,
1366 Handle<JSValue> orig_function_wrapper,
1367 Handle<JSValue> subst_function_wrapper) {
1368
1369 Handle<SharedFunctionInfo> parent_shared =
1370 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(parent_function_wrapper));
1371 Handle<SharedFunctionInfo> orig_shared =
1372 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(orig_function_wrapper));
1373 Handle<SharedFunctionInfo> subst_shared =
1374 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(subst_function_wrapper));
1375
1376 for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) {
1377 if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) {
1378 if (it.rinfo()->target_object() == *orig_shared) {
1379 it.rinfo()->set_target_object(*subst_shared);
ager@chromium.org357bf652010-04-12 11:30:10 +00001380 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001381 }
1382 }
ager@chromium.org357bf652010-04-12 11:30:10 +00001383}
1384
1385
1386// Check an activation against list of functions. If there is a function
1387// that matches, its status in result array is changed to status argument value.
1388static bool CheckActivation(Handle<JSArray> shared_info_array,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001389 Handle<JSArray> result,
1390 StackFrame* frame,
ager@chromium.org357bf652010-04-12 11:30:10 +00001391 LiveEdit::FunctionPatchabilityStatus status) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001392 if (!frame->is_java_script()) return false;
1393
1394 Handle<JSFunction> function(
1395 JSFunction::cast(JavaScriptFrame::cast(frame)->function()));
1396
ager@chromium.org357bf652010-04-12 11:30:10 +00001397 int len = Smi::cast(shared_info_array->length())->value();
1398 for (int i = 0; i < len; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001399 JSValue* wrapper =
1400 JSValue::cast(shared_info_array->GetElementNoExceptionThrown(i));
ager@chromium.org357bf652010-04-12 11:30:10 +00001401 Handle<SharedFunctionInfo> shared(
1402 SharedFunctionInfo::cast(wrapper->value()));
1403
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001404 if (function->shared() == *shared || IsInlined(*function, *shared)) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001405 SetElementNonStrict(result, i, Handle<Smi>(Smi::FromInt(status)));
ager@chromium.org357bf652010-04-12 11:30:10 +00001406 return true;
1407 }
1408 }
1409 return false;
1410}
1411
1412
1413// Iterates over handler chain and removes all elements that are inside
1414// frames being dropped.
1415static bool FixTryCatchHandler(StackFrame* top_frame,
1416 StackFrame* bottom_frame) {
1417 Address* pointer_address =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418 &Memory::Address_at(Isolate::Current()->get_address_from_id(
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001419 Isolate::kHandlerAddress));
ager@chromium.org357bf652010-04-12 11:30:10 +00001420
1421 while (*pointer_address < top_frame->sp()) {
1422 pointer_address = &Memory::Address_at(*pointer_address);
1423 }
1424 Address* above_frame_address = pointer_address;
1425 while (*pointer_address < bottom_frame->fp()) {
1426 pointer_address = &Memory::Address_at(*pointer_address);
1427 }
1428 bool change = *above_frame_address != *pointer_address;
1429 *above_frame_address = *pointer_address;
1430 return change;
1431}
1432
1433
1434// Removes specified range of frames from stack. There may be 1 or more
1435// frames in range. Anyway the bottom frame is restarted rather than dropped,
1436// and therefore has to be a JavaScript frame.
1437// Returns error message or NULL.
1438static const char* DropFrames(Vector<StackFrame*> frames,
1439 int top_frame_index,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001440 int bottom_js_frame_index,
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001441 Debug::FrameDropMode* mode,
1442 Object*** restarter_frame_function_pointer) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001443 if (!Debug::kFrameDropperSupported) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001444 return "Stack manipulations are not supported in this architecture.";
1445 }
1446
ager@chromium.org357bf652010-04-12 11:30:10 +00001447 StackFrame* pre_top_frame = frames[top_frame_index - 1];
1448 StackFrame* top_frame = frames[top_frame_index];
1449 StackFrame* bottom_js_frame = frames[bottom_js_frame_index];
1450
1451 ASSERT(bottom_js_frame->is_java_script());
1452
1453 // Check the nature of the top frame.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001454 Isolate* isolate = Isolate::Current();
1455 Code* pre_top_frame_code = pre_top_frame->LookupCode();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001456 bool frame_has_padding;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 if (pre_top_frame_code->is_inline_cache_stub() &&
1458 pre_top_frame_code->ic_state() == DEBUG_BREAK) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001459 // OK, we can drop inline cache calls.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001460 *mode = Debug::FRAME_DROPPED_IN_IC_CALL;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001461 frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001462 } else if (pre_top_frame_code ==
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001463 isolate->debug()->debug_break_slot()) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001464 // OK, we can drop debug break slot.
1465 *mode = Debug::FRAME_DROPPED_IN_DEBUG_SLOT_CALL;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001466 frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001467 } else if (pre_top_frame_code ==
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001468 isolate->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001469 Builtins::kFrameDropper_LiveEdit)) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001470 // OK, we can drop our own code.
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00001471 pre_top_frame = frames[top_frame_index - 2];
1472 top_frame = frames[top_frame_index - 1];
1473 *mode = Debug::CURRENTLY_SET_MODE;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001474 frame_has_padding = false;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001475 } else if (pre_top_frame_code ==
1476 isolate->builtins()->builtin(Builtins::kReturn_DebugBreak)) {
1477 *mode = Debug::FRAME_DROPPED_IN_RETURN_CALL;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001478 frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001479 } else if (pre_top_frame_code->kind() == Code::STUB &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001480 pre_top_frame_code->major_key() == CodeStub::CEntry) {
1481 // Entry from our unit tests on 'debugger' statement.
1482 // It's fine, we support this case.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001483 *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001484 // We don't have a padding from 'debugger' statement call.
1485 // Here the stub is CEntry, it's not debug-only and can't be padded.
1486 // If anyone would complain, a proxy padded stub could be added.
1487 frame_has_padding = false;
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00001488 } else if (pre_top_frame->type() == StackFrame::ARGUMENTS_ADAPTOR) {
1489 // This must be adaptor that remain from the frame dropping that
1490 // is still on stack. A frame dropper frame must be above it.
1491 ASSERT(frames[top_frame_index - 2]->LookupCode() ==
1492 isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit));
1493 pre_top_frame = frames[top_frame_index - 3];
1494 top_frame = frames[top_frame_index - 2];
1495 *mode = Debug::CURRENTLY_SET_MODE;
1496 frame_has_padding = false;
ager@chromium.org357bf652010-04-12 11:30:10 +00001497 } else {
1498 return "Unknown structure of stack above changing function";
1499 }
1500
1501 Address unused_stack_top = top_frame->sp();
1502 Address unused_stack_bottom = bottom_js_frame->fp()
1503 - Debug::kFrameDropperFrameSize * kPointerSize // Size of the new frame.
1504 + kPointerSize; // Bigger address end is exclusive.
1505
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001506 Address* top_frame_pc_address = top_frame->pc_address();
1507
1508 // top_frame may be damaged below this point. Do not used it.
1509 ASSERT(!(top_frame = NULL));
1510
ager@chromium.org357bf652010-04-12 11:30:10 +00001511 if (unused_stack_top > unused_stack_bottom) {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001512 if (frame_has_padding) {
1513 int shortage_bytes =
1514 static_cast<int>(unused_stack_top - unused_stack_bottom);
1515
1516 Address padding_start = pre_top_frame->fp() -
1517 Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize;
1518
1519 Address padding_pointer = padding_start;
1520 Smi* padding_object =
1521 Smi::FromInt(Debug::FramePaddingLayout::kPaddingValue);
1522 while (Memory::Object_at(padding_pointer) == padding_object) {
1523 padding_pointer -= kPointerSize;
1524 }
1525 int padding_counter =
1526 Smi::cast(Memory::Object_at(padding_pointer))->value();
1527 if (padding_counter * kPointerSize < shortage_bytes) {
1528 return "Not enough space for frame dropper frame "
1529 "(even with padding frame)";
1530 }
1531 Memory::Object_at(padding_pointer) =
1532 Smi::FromInt(padding_counter - shortage_bytes / kPointerSize);
1533
1534 StackFrame* pre_pre_frame = frames[top_frame_index - 2];
1535
1536 memmove(padding_start + kPointerSize - shortage_bytes,
1537 padding_start + kPointerSize,
1538 Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize);
1539
1540 pre_top_frame->UpdateFp(pre_top_frame->fp() - shortage_bytes);
1541 pre_pre_frame->SetCallerFp(pre_top_frame->fp());
1542 unused_stack_top -= shortage_bytes;
1543
1544 STATIC_ASSERT(sizeof(Address) == kPointerSize);
1545 top_frame_pc_address -= shortage_bytes / kPointerSize;
1546 } else {
1547 return "Not enough space for frame dropper frame";
1548 }
ager@chromium.org357bf652010-04-12 11:30:10 +00001549 }
1550
1551 // Committing now. After this point we should return only NULL value.
1552
1553 FixTryCatchHandler(pre_top_frame, bottom_js_frame);
1554 // Make sure FixTryCatchHandler is idempotent.
1555 ASSERT(!FixTryCatchHandler(pre_top_frame, bottom_js_frame));
1556
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001557 Handle<Code> code = Isolate::Current()->builtins()->FrameDropper_LiveEdit();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001558 *top_frame_pc_address = code->entry();
ager@chromium.org357bf652010-04-12 11:30:10 +00001559 pre_top_frame->SetCallerFp(bottom_js_frame->fp());
1560
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001561 *restarter_frame_function_pointer =
1562 Debug::SetUpFrameDropperFrame(bottom_js_frame, code);
1563
1564 ASSERT((**restarter_frame_function_pointer)->IsJSFunction());
ager@chromium.org357bf652010-04-12 11:30:10 +00001565
1566 for (Address a = unused_stack_top;
1567 a < unused_stack_bottom;
1568 a += kPointerSize) {
1569 Memory::Object_at(a) = Smi::FromInt(0);
1570 }
1571
1572 return NULL;
1573}
1574
1575
1576static bool IsDropableFrame(StackFrame* frame) {
1577 return !frame->is_exit();
1578}
1579
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001580
1581// Describes a set of call frames that execute any of listed functions.
1582// Finding no such frames does not mean error.
1583class MultipleFunctionTarget {
1584 public:
1585 MultipleFunctionTarget(Handle<JSArray> shared_info_array,
1586 Handle<JSArray> result)
1587 : m_shared_info_array(shared_info_array),
1588 m_result(result) {}
1589 bool MatchActivation(StackFrame* frame,
1590 LiveEdit::FunctionPatchabilityStatus status) {
1591 return CheckActivation(m_shared_info_array, m_result, frame, status);
1592 }
1593 const char* GetNotFoundMessage() {
1594 return NULL;
1595 }
1596 private:
1597 Handle<JSArray> m_shared_info_array;
1598 Handle<JSArray> m_result;
1599};
1600
1601// Drops all call frame matched by target and all frames above them.
1602template<typename TARGET>
1603static const char* DropActivationsInActiveThreadImpl(
1604 TARGET& target, bool do_drop, Zone* zone) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001605 Isolate* isolate = Isolate::Current();
1606 Debug* debug = isolate->debug();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001607 ZoneScope scope(zone, DELETE_ON_EXIT);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001608 Vector<StackFrame*> frames = CreateStackMap(zone);
ager@chromium.org357bf652010-04-12 11:30:10 +00001609
ager@chromium.org357bf652010-04-12 11:30:10 +00001610
1611 int top_frame_index = -1;
1612 int frame_index = 0;
1613 for (; frame_index < frames.length(); frame_index++) {
1614 StackFrame* frame = frames[frame_index];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001615 if (frame->id() == debug->break_frame_id()) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001616 top_frame_index = frame_index;
1617 break;
1618 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001619 if (target.MatchActivation(
1620 frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001621 // We are still above break_frame. It is not a target frame,
1622 // it is a problem.
1623 return "Debugger mark-up on stack is not found";
1624 }
1625 }
1626
1627 if (top_frame_index == -1) {
1628 // We haven't found break frame, but no function is blocking us anyway.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001629 return target.GetNotFoundMessage();
ager@chromium.org357bf652010-04-12 11:30:10 +00001630 }
1631
1632 bool target_frame_found = false;
1633 int bottom_js_frame_index = top_frame_index;
1634 bool c_code_found = false;
1635
1636 for (; frame_index < frames.length(); frame_index++) {
1637 StackFrame* frame = frames[frame_index];
1638 if (!IsDropableFrame(frame)) {
1639 c_code_found = true;
1640 break;
1641 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001642 if (target.MatchActivation(
1643 frame, LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001644 target_frame_found = true;
1645 bottom_js_frame_index = frame_index;
1646 }
1647 }
1648
1649 if (c_code_found) {
1650 // There is a C frames on stack. Check that there are no target frames
1651 // below them.
1652 for (; frame_index < frames.length(); frame_index++) {
1653 StackFrame* frame = frames[frame_index];
1654 if (frame->is_java_script()) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001655 if (target.MatchActivation(
1656 frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001657 // Cannot drop frame under C frames.
1658 return NULL;
1659 }
1660 }
1661 }
1662 }
1663
1664 if (!do_drop) {
1665 // We are in check-only mode.
1666 return NULL;
1667 }
1668
1669 if (!target_frame_found) {
1670 // Nothing to drop.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001671 return target.GetNotFoundMessage();
ager@chromium.org357bf652010-04-12 11:30:10 +00001672 }
1673
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001674 Debug::FrameDropMode drop_mode = Debug::FRAMES_UNTOUCHED;
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001675 Object** restarter_frame_function_pointer = NULL;
ager@chromium.org357bf652010-04-12 11:30:10 +00001676 const char* error_message = DropFrames(frames, top_frame_index,
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001677 bottom_js_frame_index, &drop_mode,
1678 &restarter_frame_function_pointer);
ager@chromium.org357bf652010-04-12 11:30:10 +00001679
1680 if (error_message != NULL) {
1681 return error_message;
1682 }
1683
1684 // Adjust break_frame after some frames has been dropped.
1685 StackFrame::Id new_id = StackFrame::NO_ID;
1686 for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) {
1687 if (frames[i]->type() == StackFrame::JAVA_SCRIPT) {
1688 new_id = frames[i]->id();
1689 break;
1690 }
1691 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001692 debug->FramesHaveBeenDropped(new_id, drop_mode,
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001693 restarter_frame_function_pointer);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001694 return NULL;
1695}
1696
1697// Fills result array with statuses of functions. Modifies the stack
1698// removing all listed function if possible and if do_drop is true.
1699static const char* DropActivationsInActiveThread(
1700 Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop,
1701 Zone* zone) {
1702 MultipleFunctionTarget target(shared_info_array, result);
1703
1704 const char* message =
1705 DropActivationsInActiveThreadImpl(target, do_drop, zone);
1706 if (message) {
1707 return message;
1708 }
1709
1710 int array_len = Smi::cast(shared_info_array->length())->value();
ager@chromium.org357bf652010-04-12 11:30:10 +00001711
1712 // Replace "blocked on active" with "replaced on active" status.
1713 for (int i = 0; i < array_len; i++) {
1714 if (result->GetElement(i) ==
1715 Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001716 Handle<Object> replaced(
1717 Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001718 SetElementNonStrict(result, i, replaced);
ager@chromium.org357bf652010-04-12 11:30:10 +00001719 }
1720 }
1721 return NULL;
1722}
1723
1724
1725class InactiveThreadActivationsChecker : public ThreadVisitor {
1726 public:
1727 InactiveThreadActivationsChecker(Handle<JSArray> shared_info_array,
1728 Handle<JSArray> result)
1729 : shared_info_array_(shared_info_array), result_(result),
1730 has_blocked_functions_(false) {
1731 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001732 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1733 for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001734 has_blocked_functions_ |= CheckActivation(
1735 shared_info_array_, result_, it.frame(),
1736 LiveEdit::FUNCTION_BLOCKED_ON_OTHER_STACK);
1737 }
1738 }
1739 bool HasBlockedFunctions() {
1740 return has_blocked_functions_;
1741 }
1742
1743 private:
1744 Handle<JSArray> shared_info_array_;
1745 Handle<JSArray> result_;
1746 bool has_blocked_functions_;
1747};
1748
1749
1750Handle<JSArray> LiveEdit::CheckAndDropActivations(
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001751 Handle<JSArray> shared_info_array, bool do_drop, Zone* zone) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001752 int len = Smi::cast(shared_info_array->length())->value();
1753
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001754 Handle<JSArray> result = FACTORY->NewJSArray(len);
ager@chromium.org357bf652010-04-12 11:30:10 +00001755
1756 // Fill the default values.
1757 for (int i = 0; i < len; i++) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001758 SetElementNonStrict(
1759 result,
1760 i,
1761 Handle<Smi>(Smi::FromInt(FUNCTION_AVAILABLE_FOR_PATCH)));
ager@chromium.org357bf652010-04-12 11:30:10 +00001762 }
1763
1764
1765 // First check inactive threads. Fail if some functions are blocked there.
1766 InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array,
1767 result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001768 Isolate::Current()->thread_manager()->IterateArchivedThreads(
1769 &inactive_threads_checker);
ager@chromium.org357bf652010-04-12 11:30:10 +00001770 if (inactive_threads_checker.HasBlockedFunctions()) {
1771 return result;
1772 }
1773
1774 // Try to drop activations from the current stack.
1775 const char* error_message =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001776 DropActivationsInActiveThread(shared_info_array, result, do_drop, zone);
ager@chromium.org357bf652010-04-12 11:30:10 +00001777 if (error_message != NULL) {
1778 // Add error message as an array extra element.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001779 Vector<const char> vector_message(error_message, StrLength(error_message));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001780 Handle<String> str = FACTORY->NewStringFromAscii(vector_message);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001781 SetElementNonStrict(result, len, str);
ager@chromium.org357bf652010-04-12 11:30:10 +00001782 }
1783 return result;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001784}
1785
1786
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001787// Describes a single callframe a target. Not finding this frame
1788// means an error.
1789class SingleFrameTarget {
1790 public:
1791 explicit SingleFrameTarget(JavaScriptFrame* frame) : m_frame(frame) {}
1792
1793 bool MatchActivation(StackFrame* frame,
1794 LiveEdit::FunctionPatchabilityStatus status) {
1795 if (frame->fp() == m_frame->fp()) {
1796 m_saved_status = status;
1797 return true;
1798 }
1799 return false;
1800 }
1801 const char* GetNotFoundMessage() {
1802 return "Failed to found requested frame";
1803 }
1804 LiveEdit::FunctionPatchabilityStatus saved_status() {
1805 return m_saved_status;
1806 }
1807 private:
1808 JavaScriptFrame* m_frame;
1809 LiveEdit::FunctionPatchabilityStatus m_saved_status;
1810};
1811
1812
1813// Finds a drops required frame and all frames above.
1814// Returns error message or NULL.
1815const char* LiveEdit::RestartFrame(JavaScriptFrame* frame, Zone* zone) {
1816 SingleFrameTarget target(frame);
1817
1818 return DropActivationsInActiveThreadImpl(target, true, zone);
1819}
1820
1821
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001822LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
1823 FunctionLiteral* fun)
1824 : isolate_(isolate) {
1825 if (isolate_->active_function_info_listener() != NULL) {
1826 isolate_->active_function_info_listener()->FunctionStarted(fun);
ager@chromium.org5c838252010-02-19 08:53:10 +00001827 }
1828}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001829
1830
ager@chromium.org5c838252010-02-19 08:53:10 +00001831LiveEditFunctionTracker::~LiveEditFunctionTracker() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001832 if (isolate_->active_function_info_listener() != NULL) {
1833 isolate_->active_function_info_listener()->FunctionDone();
ager@chromium.org5c838252010-02-19 08:53:10 +00001834 }
1835}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001836
1837
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001838void LiveEditFunctionTracker::RecordFunctionInfo(
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001839 Handle<SharedFunctionInfo> info, FunctionLiteral* lit,
1840 Zone* zone) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001841 if (isolate_->active_function_info_listener() != NULL) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001842 isolate_->active_function_info_listener()->FunctionInfo(info, lit->scope(),
1843 zone);
ager@chromium.org5c838252010-02-19 08:53:10 +00001844 }
1845}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001846
1847
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001848void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001849 isolate_->active_function_info_listener()->FunctionCode(code);
ager@chromium.org5c838252010-02-19 08:53:10 +00001850}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001851
1852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001853bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
1854 return isolate->active_function_info_listener() != NULL;
ager@chromium.org5c838252010-02-19 08:53:10 +00001855}
1856
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001857
1858#else // ENABLE_DEBUGGER_SUPPORT
1859
1860// This ifdef-else-endif section provides working or stub implementation of
1861// LiveEditFunctionTracker.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
1863 FunctionLiteral* fun) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001864}
1865
1866
1867LiveEditFunctionTracker::~LiveEditFunctionTracker() {
1868}
1869
1870
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001871void LiveEditFunctionTracker::RecordFunctionInfo(
1872 Handle<SharedFunctionInfo> info, FunctionLiteral* lit) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001873}
1874
1875
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001876void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001877}
1878
1879
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001880bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001881 return false;
1882}
1883
1884#endif // ENABLE_DEBUGGER_SUPPORT
1885
1886
1887
ager@chromium.org5c838252010-02-19 08:53:10 +00001888} } // namespace v8::internal