blob: 5dc86f91d6b5490b8ac550f22be20cab0f85bb17 [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.
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +0000968static void ReplaceCodeObject(Handle<Code> original,
969 Handle<Code> substitution) {
970 // Perform a full GC in order to ensure that we are not in the middle of an
971 // incremental marking phase when we are replacing the code object.
972 // Since we are not in an incremental marking phase we can write pointers
973 // to code objects (that are never in new space) without worrying about
974 // write barriers.
975 HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask,
976 "liveedit.cc ReplaceCodeObject");
977
978 ASSERT(!HEAP->InNewSpace(*substitution));
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000979
980 AssertNoAllocation no_allocations_please;
981
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +0000982 ReplacingVisitor visitor(*original, *substitution);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000983
984 // Iterate over all roots. Stack frames may have pointer into original code,
985 // so temporary replace the pointers with offset numbers
986 // in prologue/epilogue.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000987 HEAP->IterateRoots(&visitor, VISIT_ALL);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000988
989 // Now iterate over all pointers of all objects, including code_target
990 // implicit pointers.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000991 HeapIterator iterator;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000992 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
993 obj->Iterate(&visitor);
994 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000995}
996
997
ager@chromium.org357bf652010-04-12 11:30:10 +0000998// Check whether the code is natural function code (not a lazy-compile stub
999// code).
1000static bool IsJSFunctionCode(Code* code) {
1001 return code->kind() == Code::FUNCTION;
1002}
1003
1004
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001005// Returns true if an instance of candidate were inlined into function's code.
1006static bool IsInlined(JSFunction* function, SharedFunctionInfo* candidate) {
1007 AssertNoAllocation no_gc;
1008
1009 if (function->code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
1010
1011 DeoptimizationInputData* data =
1012 DeoptimizationInputData::cast(function->code()->deoptimization_data());
1013
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001014 if (data == HEAP->empty_fixed_array()) return false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001015
1016 FixedArray* literals = data->LiteralArray();
1017
1018 int inlined_count = data->InlinedFunctionCount()->value();
1019 for (int i = 0; i < inlined_count; ++i) {
1020 JSFunction* inlined = JSFunction::cast(literals->get(i));
1021 if (inlined->shared() == candidate) return true;
1022 }
1023
1024 return false;
1025}
1026
1027
1028class DependentFunctionsDeoptimizingVisitor : public OptimizedFunctionVisitor {
1029 public:
1030 explicit DependentFunctionsDeoptimizingVisitor(
1031 SharedFunctionInfo* function_info)
1032 : function_info_(function_info) {}
1033
1034 virtual void EnterContext(Context* context) {
1035 }
1036
1037 virtual void VisitFunction(JSFunction* function) {
1038 if (function->shared() == function_info_ ||
1039 IsInlined(function, function_info_)) {
1040 Deoptimizer::DeoptimizeFunction(function);
1041 }
1042 }
1043
1044 virtual void LeaveContext(Context* context) {
1045 }
1046
1047 private:
1048 SharedFunctionInfo* function_info_;
1049};
1050
1051
1052static void DeoptimizeDependentFunctions(SharedFunctionInfo* function_info) {
1053 AssertNoAllocation no_allocation;
1054
1055 DependentFunctionsDeoptimizingVisitor visitor(function_info);
1056 Deoptimizer::VisitAllOptimizedFunctions(&visitor);
1057}
1058
1059
lrn@chromium.org303ada72010-10-27 09:33:13 +00001060MaybeObject* LiveEdit::ReplaceFunctionCode(
1061 Handle<JSArray> new_compile_info_array,
1062 Handle<JSArray> shared_info_array) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001063 HandleScope scope;
1064
ager@chromium.orgac091b72010-05-05 07:34:42 +00001065 if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001066 return Isolate::Current()->ThrowIllegalOperation();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001067 }
1068
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001069 FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
1070 SharedInfoWrapper shared_info_wrapper(shared_info_array);
1071
1072 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
1073
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001074 HEAP->EnsureHeapIsIterable();
1075
ager@chromium.org357bf652010-04-12 11:30:10 +00001076 if (IsJSFunctionCode(shared_info->code())) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001077 Handle<Code> code = compile_info_wrapper.GetFunctionCode();
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +00001078 ReplaceCodeObject(Handle<Code>(shared_info->code()), code);
1079 Handle<Object> code_scope_info = compile_info_wrapper.GetCodeScopeInfo();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001080 if (code_scope_info->IsFixedArray()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001081 shared_info->set_scope_info(ScopeInfo::cast(*code_scope_info));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001082 }
ager@chromium.org357bf652010-04-12 11:30:10 +00001083 }
1084
1085 if (shared_info->debug_info()->IsDebugInfo()) {
1086 Handle<DebugInfo> debug_info(DebugInfo::cast(shared_info->debug_info()));
1087 Handle<Code> new_original_code =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001088 FACTORY->CopyCode(compile_info_wrapper.GetFunctionCode());
ager@chromium.org357bf652010-04-12 11:30:10 +00001089 debug_info->set_original_code(*new_original_code);
1090 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001092 int start_position = compile_info_wrapper.GetStartPosition();
1093 int end_position = compile_info_wrapper.GetEndPosition();
1094 shared_info->set_start_position(start_position);
1095 shared_info->set_end_position(end_position);
ager@chromium.org357bf652010-04-12 11:30:10 +00001096
1097 shared_info->set_construct_stub(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001098 Isolate::Current()->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001099 Builtins::kJSConstructStubGeneric));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001100
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001101 DeoptimizeDependentFunctions(*shared_info);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001102 Isolate::Current()->compilation_cache()->Remove(shared_info);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001103
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001104 return HEAP->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001105}
1106
1107
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001108MaybeObject* LiveEdit::FunctionSourceUpdated(
1109 Handle<JSArray> shared_info_array) {
1110 HandleScope scope;
1111
1112 if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001113 return Isolate::Current()->ThrowIllegalOperation();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001114 }
1115
1116 SharedInfoWrapper shared_info_wrapper(shared_info_array);
1117 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
1118
1119 DeoptimizeDependentFunctions(*shared_info);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001120 Isolate::Current()->compilation_cache()->Remove(shared_info);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001121
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001122 return HEAP->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001123}
1124
1125
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001126void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
1127 Handle<Object> script_handle) {
1128 Handle<SharedFunctionInfo> shared_info =
1129 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(function_wrapper));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001130 shared_info->set_script(*script_handle);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001131
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001132 Isolate::Current()->compilation_cache()->Remove(shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001133}
1134
1135
1136// For a script text change (defined as position_change_array), translates
1137// position in unchanged text to position in changed text.
1138// Text change is a set of non-overlapping regions in text, that have changed
1139// their contents and length. It is specified as array of groups of 3 numbers:
1140// (change_begin, change_end, change_end_new_position).
1141// Each group describes a change in text; groups are sorted by change_begin.
1142// Only position in text beyond any changes may be successfully translated.
1143// If a positions is inside some region that changed, result is currently
1144// undefined.
1145static int TranslatePosition(int original_position,
1146 Handle<JSArray> position_change_array) {
1147 int position_diff = 0;
1148 int array_len = Smi::cast(position_change_array->length())->value();
1149 // TODO(635): binary search may be used here
1150 for (int i = 0; i < array_len; i += 3) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001151 Object* element = position_change_array->GetElementNoExceptionThrown(i);
1152 int chunk_start = Smi::cast(element)->value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001153 if (original_position < chunk_start) {
1154 break;
1155 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001156 element = position_change_array->GetElementNoExceptionThrown(i + 1);
1157 int chunk_end = Smi::cast(element)->value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001158 // Position mustn't be inside a chunk.
1159 ASSERT(original_position >= chunk_end);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001160 element = position_change_array->GetElementNoExceptionThrown(i + 2);
1161 int chunk_changed_end = Smi::cast(element)->value();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001162 position_diff = chunk_changed_end - chunk_end;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001163 }
1164
1165 return original_position + position_diff;
1166}
1167
1168
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001169// Auto-growing buffer for writing relocation info code section. This buffer
1170// is a simplified version of buffer from Assembler. Unlike Assembler, this
1171// class is platform-independent and it works without dealing with instructions.
1172// As specified by RelocInfo format, the buffer is filled in reversed order:
1173// from upper to lower addresses.
1174// It uses NewArray/DeleteArray for memory management.
1175class RelocInfoBuffer {
1176 public:
1177 RelocInfoBuffer(int buffer_initial_capicity, byte* pc) {
1178 buffer_size_ = buffer_initial_capicity + kBufferGap;
1179 buffer_ = NewArray<byte>(buffer_size_);
1180
1181 reloc_info_writer_.Reposition(buffer_ + buffer_size_, pc);
1182 }
1183 ~RelocInfoBuffer() {
1184 DeleteArray(buffer_);
1185 }
1186
1187 // As specified by RelocInfo format, the buffer is filled in reversed order:
1188 // from upper to lower addresses.
1189 void Write(const RelocInfo* rinfo) {
1190 if (buffer_ + kBufferGap >= reloc_info_writer_.pos()) {
1191 Grow();
1192 }
1193 reloc_info_writer_.Write(rinfo);
1194 }
1195
1196 Vector<byte> GetResult() {
1197 // Return the bytes from pos up to end of buffer.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001198 int result_size =
1199 static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer_.pos());
1200 return Vector<byte>(reloc_info_writer_.pos(), result_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001201 }
1202
1203 private:
1204 void Grow() {
1205 // Compute new buffer size.
1206 int new_buffer_size;
1207 if (buffer_size_ < 2 * KB) {
1208 new_buffer_size = 4 * KB;
1209 } else {
1210 new_buffer_size = 2 * buffer_size_;
1211 }
1212 // Some internal data structures overflow for very large buffers,
1213 // they must ensure that kMaximalBufferSize is not too large.
1214 if (new_buffer_size > kMaximalBufferSize) {
1215 V8::FatalProcessOutOfMemory("RelocInfoBuffer::GrowBuffer");
1216 }
1217
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001218 // Set up new buffer.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001219 byte* new_buffer = NewArray<byte>(new_buffer_size);
1220
1221 // Copy the data.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001222 int curently_used_size =
1223 static_cast<int>(buffer_ + buffer_size_ - reloc_info_writer_.pos());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001224 memmove(new_buffer + new_buffer_size - curently_used_size,
1225 reloc_info_writer_.pos(), curently_used_size);
1226
1227 reloc_info_writer_.Reposition(
1228 new_buffer + new_buffer_size - curently_used_size,
1229 reloc_info_writer_.last_pc());
1230
1231 DeleteArray(buffer_);
1232 buffer_ = new_buffer;
1233 buffer_size_ = new_buffer_size;
1234 }
1235
1236 RelocInfoWriter reloc_info_writer_;
1237 byte* buffer_;
1238 int buffer_size_;
1239
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001240 static const int kBufferGap = RelocInfoWriter::kMaxSize;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001241 static const int kMaximalBufferSize = 512*MB;
1242};
1243
1244// Patch positions in code (changes relocation info section) and possibly
1245// returns new instance of code.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001246static Handle<Code> PatchPositionsInCode(
1247 Handle<Code> code,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001248 Handle<JSArray> position_change_array) {
1249
1250 RelocInfoBuffer buffer_writer(code->relocation_size(),
1251 code->instruction_start());
1252
1253 {
1254 AssertNoAllocation no_allocations_please;
1255 for (RelocIterator it(*code); !it.done(); it.next()) {
1256 RelocInfo* rinfo = it.rinfo();
1257 if (RelocInfo::IsPosition(rinfo->rmode())) {
1258 int position = static_cast<int>(rinfo->data());
1259 int new_position = TranslatePosition(position,
1260 position_change_array);
1261 if (position != new_position) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001262 RelocInfo info_copy(rinfo->pc(), rinfo->rmode(), new_position, NULL);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001263 buffer_writer.Write(&info_copy);
1264 continue;
1265 }
1266 }
1267 buffer_writer.Write(it.rinfo());
1268 }
1269 }
1270
1271 Vector<byte> buffer = buffer_writer.GetResult();
1272
1273 if (buffer.length() == code->relocation_size()) {
1274 // Simply patch relocation area of code.
1275 memcpy(code->relocation_start(), buffer.start(), buffer.length());
1276 return code;
1277 } else {
1278 // Relocation info section now has different size. We cannot simply
1279 // rewrite it inside code object. Instead we have to create a new
1280 // code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001281 Handle<Code> result(FACTORY->CopyCode(code, buffer));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001282 return result;
1283 }
1284}
1285
1286
lrn@chromium.org303ada72010-10-27 09:33:13 +00001287MaybeObject* LiveEdit::PatchFunctionPositions(
ager@chromium.org357bf652010-04-12 11:30:10 +00001288 Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001289
1290 if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001291 return Isolate::Current()->ThrowIllegalOperation();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001292 }
1293
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001294 SharedInfoWrapper shared_info_wrapper(shared_info_array);
1295 Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo();
1296
ager@chromium.org357bf652010-04-12 11:30:10 +00001297 int old_function_start = info->start_position();
1298 int new_function_start = TranslatePosition(old_function_start,
1299 position_change_array);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001300 int new_function_end = TranslatePosition(info->end_position(),
1301 position_change_array);
1302 int new_function_token_pos =
1303 TranslatePosition(info->function_token_position(), position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001304
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001305 info->set_start_position(new_function_start);
1306 info->set_end_position(new_function_end);
1307 info->set_function_token_position(new_function_token_pos);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001308
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001309 HEAP->EnsureHeapIsIterable();
1310
ager@chromium.org357bf652010-04-12 11:30:10 +00001311 if (IsJSFunctionCode(info->code())) {
1312 // Patch relocation info section of the code.
1313 Handle<Code> patched_code = PatchPositionsInCode(Handle<Code>(info->code()),
1314 position_change_array);
1315 if (*patched_code != info->code()) {
1316 // Replace all references to the code across the heap. In particular,
1317 // some stubs may refer to this code and this code may be being executed
1318 // on stack (it is safe to substitute the code object on stack, because
1319 // we only change the structure of rinfo and leave instructions
1320 // untouched).
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +00001321 ReplaceCodeObject(Handle<Code>(info->code()), patched_code);
ager@chromium.org357bf652010-04-12 11:30:10 +00001322 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001323 }
ager@chromium.orgac091b72010-05-05 07:34:42 +00001324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001325 return HEAP->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001326}
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001327
ager@chromium.org357bf652010-04-12 11:30:10 +00001328
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001329static Handle<Script> CreateScriptCopy(Handle<Script> original) {
1330 Handle<String> original_source(String::cast(original->source()));
ager@chromium.org357bf652010-04-12 11:30:10 +00001331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001332 Handle<Script> copy = FACTORY->NewScript(original_source);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001333
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001334 copy->set_name(original->name());
1335 copy->set_line_offset(original->line_offset());
1336 copy->set_column_offset(original->column_offset());
1337 copy->set_data(original->data());
1338 copy->set_type(original->type());
1339 copy->set_context_data(original->context_data());
1340 copy->set_compilation_type(original->compilation_type());
1341 copy->set_eval_from_shared(original->eval_from_shared());
1342 copy->set_eval_from_instructions_offset(
1343 original->eval_from_instructions_offset());
1344
1345 return copy;
1346}
1347
1348
1349Object* LiveEdit::ChangeScriptSource(Handle<Script> original_script,
1350 Handle<String> new_source,
1351 Handle<Object> old_script_name) {
1352 Handle<Object> old_script_object;
1353 if (old_script_name->IsString()) {
1354 Handle<Script> old_script = CreateScriptCopy(original_script);
1355 old_script->set_name(String::cast(*old_script_name));
1356 old_script_object = old_script;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001357 Isolate::Current()->debugger()->OnAfterCompile(
1358 old_script, Debugger::SEND_WHEN_DEBUGGING);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001359 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001360 old_script_object = Handle<Object>(HEAP->null_value());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001361 }
1362
1363 original_script->set_source(*new_source);
1364
1365 // Drop line ends so that they will be recalculated.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001366 original_script->set_line_ends(HEAP->undefined_value());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001367
1368 return *old_script_object;
1369}
1370
1371
1372
1373void LiveEdit::ReplaceRefToNestedFunction(
1374 Handle<JSValue> parent_function_wrapper,
1375 Handle<JSValue> orig_function_wrapper,
1376 Handle<JSValue> subst_function_wrapper) {
1377
1378 Handle<SharedFunctionInfo> parent_shared =
1379 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(parent_function_wrapper));
1380 Handle<SharedFunctionInfo> orig_shared =
1381 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(orig_function_wrapper));
1382 Handle<SharedFunctionInfo> subst_shared =
1383 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(subst_function_wrapper));
1384
1385 for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) {
1386 if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) {
1387 if (it.rinfo()->target_object() == *orig_shared) {
1388 it.rinfo()->set_target_object(*subst_shared);
ager@chromium.org357bf652010-04-12 11:30:10 +00001389 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001390 }
1391 }
ager@chromium.org357bf652010-04-12 11:30:10 +00001392}
1393
1394
1395// Check an activation against list of functions. If there is a function
1396// that matches, its status in result array is changed to status argument value.
1397static bool CheckActivation(Handle<JSArray> shared_info_array,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001398 Handle<JSArray> result,
1399 StackFrame* frame,
ager@chromium.org357bf652010-04-12 11:30:10 +00001400 LiveEdit::FunctionPatchabilityStatus status) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001401 if (!frame->is_java_script()) return false;
1402
1403 Handle<JSFunction> function(
1404 JSFunction::cast(JavaScriptFrame::cast(frame)->function()));
1405
ager@chromium.org357bf652010-04-12 11:30:10 +00001406 int len = Smi::cast(shared_info_array->length())->value();
1407 for (int i = 0; i < len; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001408 JSValue* wrapper =
1409 JSValue::cast(shared_info_array->GetElementNoExceptionThrown(i));
ager@chromium.org357bf652010-04-12 11:30:10 +00001410 Handle<SharedFunctionInfo> shared(
1411 SharedFunctionInfo::cast(wrapper->value()));
1412
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001413 if (function->shared() == *shared || IsInlined(*function, *shared)) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001414 SetElementNonStrict(result, i, Handle<Smi>(Smi::FromInt(status)));
ager@chromium.org357bf652010-04-12 11:30:10 +00001415 return true;
1416 }
1417 }
1418 return false;
1419}
1420
1421
1422// Iterates over handler chain and removes all elements that are inside
1423// frames being dropped.
1424static bool FixTryCatchHandler(StackFrame* top_frame,
1425 StackFrame* bottom_frame) {
1426 Address* pointer_address =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001427 &Memory::Address_at(Isolate::Current()->get_address_from_id(
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001428 Isolate::kHandlerAddress));
ager@chromium.org357bf652010-04-12 11:30:10 +00001429
1430 while (*pointer_address < top_frame->sp()) {
1431 pointer_address = &Memory::Address_at(*pointer_address);
1432 }
1433 Address* above_frame_address = pointer_address;
1434 while (*pointer_address < bottom_frame->fp()) {
1435 pointer_address = &Memory::Address_at(*pointer_address);
1436 }
1437 bool change = *above_frame_address != *pointer_address;
1438 *above_frame_address = *pointer_address;
1439 return change;
1440}
1441
1442
1443// Removes specified range of frames from stack. There may be 1 or more
1444// frames in range. Anyway the bottom frame is restarted rather than dropped,
1445// and therefore has to be a JavaScript frame.
1446// Returns error message or NULL.
1447static const char* DropFrames(Vector<StackFrame*> frames,
1448 int top_frame_index,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001449 int bottom_js_frame_index,
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001450 Debug::FrameDropMode* mode,
1451 Object*** restarter_frame_function_pointer) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001452 if (!Debug::kFrameDropperSupported) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001453 return "Stack manipulations are not supported in this architecture.";
1454 }
1455
ager@chromium.org357bf652010-04-12 11:30:10 +00001456 StackFrame* pre_top_frame = frames[top_frame_index - 1];
1457 StackFrame* top_frame = frames[top_frame_index];
1458 StackFrame* bottom_js_frame = frames[bottom_js_frame_index];
1459
1460 ASSERT(bottom_js_frame->is_java_script());
1461
1462 // Check the nature of the top frame.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001463 Isolate* isolate = Isolate::Current();
1464 Code* pre_top_frame_code = pre_top_frame->LookupCode();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001465 bool frame_has_padding;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001466 if (pre_top_frame_code->is_inline_cache_stub() &&
1467 pre_top_frame_code->ic_state() == DEBUG_BREAK) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001468 // OK, we can drop inline cache calls.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001469 *mode = Debug::FRAME_DROPPED_IN_IC_CALL;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001470 frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001471 } else if (pre_top_frame_code ==
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001472 isolate->debug()->debug_break_slot()) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001473 // OK, we can drop debug break slot.
1474 *mode = Debug::FRAME_DROPPED_IN_DEBUG_SLOT_CALL;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001475 frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001476 } else if (pre_top_frame_code ==
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001477 isolate->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001478 Builtins::kFrameDropper_LiveEdit)) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001479 // OK, we can drop our own code.
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00001480 pre_top_frame = frames[top_frame_index - 2];
1481 top_frame = frames[top_frame_index - 1];
1482 *mode = Debug::CURRENTLY_SET_MODE;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001483 frame_has_padding = false;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001484 } else if (pre_top_frame_code ==
1485 isolate->builtins()->builtin(Builtins::kReturn_DebugBreak)) {
1486 *mode = Debug::FRAME_DROPPED_IN_RETURN_CALL;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001487 frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001488 } else if (pre_top_frame_code->kind() == Code::STUB &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001489 pre_top_frame_code->major_key() == CodeStub::CEntry) {
1490 // Entry from our unit tests on 'debugger' statement.
1491 // It's fine, we support this case.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001492 *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001493 // We don't have a padding from 'debugger' statement call.
1494 // Here the stub is CEntry, it's not debug-only and can't be padded.
1495 // If anyone would complain, a proxy padded stub could be added.
1496 frame_has_padding = false;
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00001497 } else if (pre_top_frame->type() == StackFrame::ARGUMENTS_ADAPTOR) {
1498 // This must be adaptor that remain from the frame dropping that
1499 // is still on stack. A frame dropper frame must be above it.
1500 ASSERT(frames[top_frame_index - 2]->LookupCode() ==
1501 isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit));
1502 pre_top_frame = frames[top_frame_index - 3];
1503 top_frame = frames[top_frame_index - 2];
1504 *mode = Debug::CURRENTLY_SET_MODE;
1505 frame_has_padding = false;
ager@chromium.org357bf652010-04-12 11:30:10 +00001506 } else {
1507 return "Unknown structure of stack above changing function";
1508 }
1509
1510 Address unused_stack_top = top_frame->sp();
1511 Address unused_stack_bottom = bottom_js_frame->fp()
1512 - Debug::kFrameDropperFrameSize * kPointerSize // Size of the new frame.
1513 + kPointerSize; // Bigger address end is exclusive.
1514
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001515 Address* top_frame_pc_address = top_frame->pc_address();
1516
1517 // top_frame may be damaged below this point. Do not used it.
1518 ASSERT(!(top_frame = NULL));
1519
ager@chromium.org357bf652010-04-12 11:30:10 +00001520 if (unused_stack_top > unused_stack_bottom) {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001521 if (frame_has_padding) {
1522 int shortage_bytes =
1523 static_cast<int>(unused_stack_top - unused_stack_bottom);
1524
1525 Address padding_start = pre_top_frame->fp() -
1526 Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize;
1527
1528 Address padding_pointer = padding_start;
1529 Smi* padding_object =
1530 Smi::FromInt(Debug::FramePaddingLayout::kPaddingValue);
1531 while (Memory::Object_at(padding_pointer) == padding_object) {
1532 padding_pointer -= kPointerSize;
1533 }
1534 int padding_counter =
1535 Smi::cast(Memory::Object_at(padding_pointer))->value();
1536 if (padding_counter * kPointerSize < shortage_bytes) {
1537 return "Not enough space for frame dropper frame "
1538 "(even with padding frame)";
1539 }
1540 Memory::Object_at(padding_pointer) =
1541 Smi::FromInt(padding_counter - shortage_bytes / kPointerSize);
1542
1543 StackFrame* pre_pre_frame = frames[top_frame_index - 2];
1544
1545 memmove(padding_start + kPointerSize - shortage_bytes,
1546 padding_start + kPointerSize,
1547 Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize);
1548
1549 pre_top_frame->UpdateFp(pre_top_frame->fp() - shortage_bytes);
1550 pre_pre_frame->SetCallerFp(pre_top_frame->fp());
1551 unused_stack_top -= shortage_bytes;
1552
1553 STATIC_ASSERT(sizeof(Address) == kPointerSize);
1554 top_frame_pc_address -= shortage_bytes / kPointerSize;
1555 } else {
1556 return "Not enough space for frame dropper frame";
1557 }
ager@chromium.org357bf652010-04-12 11:30:10 +00001558 }
1559
1560 // Committing now. After this point we should return only NULL value.
1561
1562 FixTryCatchHandler(pre_top_frame, bottom_js_frame);
1563 // Make sure FixTryCatchHandler is idempotent.
1564 ASSERT(!FixTryCatchHandler(pre_top_frame, bottom_js_frame));
1565
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001566 Handle<Code> code = Isolate::Current()->builtins()->FrameDropper_LiveEdit();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001567 *top_frame_pc_address = code->entry();
ager@chromium.org357bf652010-04-12 11:30:10 +00001568 pre_top_frame->SetCallerFp(bottom_js_frame->fp());
1569
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001570 *restarter_frame_function_pointer =
1571 Debug::SetUpFrameDropperFrame(bottom_js_frame, code);
1572
1573 ASSERT((**restarter_frame_function_pointer)->IsJSFunction());
ager@chromium.org357bf652010-04-12 11:30:10 +00001574
1575 for (Address a = unused_stack_top;
1576 a < unused_stack_bottom;
1577 a += kPointerSize) {
1578 Memory::Object_at(a) = Smi::FromInt(0);
1579 }
1580
1581 return NULL;
1582}
1583
1584
1585static bool IsDropableFrame(StackFrame* frame) {
1586 return !frame->is_exit();
1587}
1588
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001589
1590// Describes a set of call frames that execute any of listed functions.
1591// Finding no such frames does not mean error.
1592class MultipleFunctionTarget {
1593 public:
1594 MultipleFunctionTarget(Handle<JSArray> shared_info_array,
1595 Handle<JSArray> result)
1596 : m_shared_info_array(shared_info_array),
1597 m_result(result) {}
1598 bool MatchActivation(StackFrame* frame,
1599 LiveEdit::FunctionPatchabilityStatus status) {
1600 return CheckActivation(m_shared_info_array, m_result, frame, status);
1601 }
1602 const char* GetNotFoundMessage() {
1603 return NULL;
1604 }
1605 private:
1606 Handle<JSArray> m_shared_info_array;
1607 Handle<JSArray> m_result;
1608};
1609
1610// Drops all call frame matched by target and all frames above them.
1611template<typename TARGET>
1612static const char* DropActivationsInActiveThreadImpl(
1613 TARGET& target, bool do_drop, Zone* zone) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001614 Isolate* isolate = Isolate::Current();
1615 Debug* debug = isolate->debug();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001616 ZoneScope scope(zone, DELETE_ON_EXIT);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001617 Vector<StackFrame*> frames = CreateStackMap(zone);
ager@chromium.org357bf652010-04-12 11:30:10 +00001618
ager@chromium.org357bf652010-04-12 11:30:10 +00001619
1620 int top_frame_index = -1;
1621 int frame_index = 0;
1622 for (; frame_index < frames.length(); frame_index++) {
1623 StackFrame* frame = frames[frame_index];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001624 if (frame->id() == debug->break_frame_id()) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001625 top_frame_index = frame_index;
1626 break;
1627 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001628 if (target.MatchActivation(
1629 frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001630 // We are still above break_frame. It is not a target frame,
1631 // it is a problem.
1632 return "Debugger mark-up on stack is not found";
1633 }
1634 }
1635
1636 if (top_frame_index == -1) {
1637 // We haven't found break frame, but no function is blocking us anyway.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001638 return target.GetNotFoundMessage();
ager@chromium.org357bf652010-04-12 11:30:10 +00001639 }
1640
1641 bool target_frame_found = false;
1642 int bottom_js_frame_index = top_frame_index;
1643 bool c_code_found = false;
1644
1645 for (; frame_index < frames.length(); frame_index++) {
1646 StackFrame* frame = frames[frame_index];
1647 if (!IsDropableFrame(frame)) {
1648 c_code_found = true;
1649 break;
1650 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001651 if (target.MatchActivation(
1652 frame, LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001653 target_frame_found = true;
1654 bottom_js_frame_index = frame_index;
1655 }
1656 }
1657
1658 if (c_code_found) {
1659 // There is a C frames on stack. Check that there are no target frames
1660 // below them.
1661 for (; frame_index < frames.length(); frame_index++) {
1662 StackFrame* frame = frames[frame_index];
1663 if (frame->is_java_script()) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001664 if (target.MatchActivation(
1665 frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001666 // Cannot drop frame under C frames.
1667 return NULL;
1668 }
1669 }
1670 }
1671 }
1672
1673 if (!do_drop) {
1674 // We are in check-only mode.
1675 return NULL;
1676 }
1677
1678 if (!target_frame_found) {
1679 // Nothing to drop.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001680 return target.GetNotFoundMessage();
ager@chromium.org357bf652010-04-12 11:30:10 +00001681 }
1682
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001683 Debug::FrameDropMode drop_mode = Debug::FRAMES_UNTOUCHED;
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001684 Object** restarter_frame_function_pointer = NULL;
ager@chromium.org357bf652010-04-12 11:30:10 +00001685 const char* error_message = DropFrames(frames, top_frame_index,
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001686 bottom_js_frame_index, &drop_mode,
1687 &restarter_frame_function_pointer);
ager@chromium.org357bf652010-04-12 11:30:10 +00001688
1689 if (error_message != NULL) {
1690 return error_message;
1691 }
1692
1693 // Adjust break_frame after some frames has been dropped.
1694 StackFrame::Id new_id = StackFrame::NO_ID;
1695 for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) {
1696 if (frames[i]->type() == StackFrame::JAVA_SCRIPT) {
1697 new_id = frames[i]->id();
1698 break;
1699 }
1700 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001701 debug->FramesHaveBeenDropped(new_id, drop_mode,
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001702 restarter_frame_function_pointer);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001703 return NULL;
1704}
1705
1706// Fills result array with statuses of functions. Modifies the stack
1707// removing all listed function if possible and if do_drop is true.
1708static const char* DropActivationsInActiveThread(
1709 Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop,
1710 Zone* zone) {
1711 MultipleFunctionTarget target(shared_info_array, result);
1712
1713 const char* message =
1714 DropActivationsInActiveThreadImpl(target, do_drop, zone);
1715 if (message) {
1716 return message;
1717 }
1718
1719 int array_len = Smi::cast(shared_info_array->length())->value();
ager@chromium.org357bf652010-04-12 11:30:10 +00001720
1721 // Replace "blocked on active" with "replaced on active" status.
1722 for (int i = 0; i < array_len; i++) {
1723 if (result->GetElement(i) ==
1724 Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001725 Handle<Object> replaced(
1726 Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001727 SetElementNonStrict(result, i, replaced);
ager@chromium.org357bf652010-04-12 11:30:10 +00001728 }
1729 }
1730 return NULL;
1731}
1732
1733
1734class InactiveThreadActivationsChecker : public ThreadVisitor {
1735 public:
1736 InactiveThreadActivationsChecker(Handle<JSArray> shared_info_array,
1737 Handle<JSArray> result)
1738 : shared_info_array_(shared_info_array), result_(result),
1739 has_blocked_functions_(false) {
1740 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001741 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1742 for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001743 has_blocked_functions_ |= CheckActivation(
1744 shared_info_array_, result_, it.frame(),
1745 LiveEdit::FUNCTION_BLOCKED_ON_OTHER_STACK);
1746 }
1747 }
1748 bool HasBlockedFunctions() {
1749 return has_blocked_functions_;
1750 }
1751
1752 private:
1753 Handle<JSArray> shared_info_array_;
1754 Handle<JSArray> result_;
1755 bool has_blocked_functions_;
1756};
1757
1758
1759Handle<JSArray> LiveEdit::CheckAndDropActivations(
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001760 Handle<JSArray> shared_info_array, bool do_drop, Zone* zone) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001761 int len = Smi::cast(shared_info_array->length())->value();
1762
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 Handle<JSArray> result = FACTORY->NewJSArray(len);
ager@chromium.org357bf652010-04-12 11:30:10 +00001764
1765 // Fill the default values.
1766 for (int i = 0; i < len; i++) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001767 SetElementNonStrict(
1768 result,
1769 i,
1770 Handle<Smi>(Smi::FromInt(FUNCTION_AVAILABLE_FOR_PATCH)));
ager@chromium.org357bf652010-04-12 11:30:10 +00001771 }
1772
1773
1774 // First check inactive threads. Fail if some functions are blocked there.
1775 InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array,
1776 result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001777 Isolate::Current()->thread_manager()->IterateArchivedThreads(
1778 &inactive_threads_checker);
ager@chromium.org357bf652010-04-12 11:30:10 +00001779 if (inactive_threads_checker.HasBlockedFunctions()) {
1780 return result;
1781 }
1782
1783 // Try to drop activations from the current stack.
1784 const char* error_message =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001785 DropActivationsInActiveThread(shared_info_array, result, do_drop, zone);
ager@chromium.org357bf652010-04-12 11:30:10 +00001786 if (error_message != NULL) {
1787 // Add error message as an array extra element.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001788 Vector<const char> vector_message(error_message, StrLength(error_message));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001789 Handle<String> str = FACTORY->NewStringFromAscii(vector_message);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001790 SetElementNonStrict(result, len, str);
ager@chromium.org357bf652010-04-12 11:30:10 +00001791 }
1792 return result;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001793}
1794
1795
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001796// Describes a single callframe a target. Not finding this frame
1797// means an error.
1798class SingleFrameTarget {
1799 public:
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001800 explicit SingleFrameTarget(JavaScriptFrame* frame)
1801 : m_frame(frame),
1802 m_saved_status(LiveEdit::FUNCTION_AVAILABLE_FOR_PATCH) {}
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001803
1804 bool MatchActivation(StackFrame* frame,
1805 LiveEdit::FunctionPatchabilityStatus status) {
1806 if (frame->fp() == m_frame->fp()) {
1807 m_saved_status = status;
1808 return true;
1809 }
1810 return false;
1811 }
1812 const char* GetNotFoundMessage() {
1813 return "Failed to found requested frame";
1814 }
1815 LiveEdit::FunctionPatchabilityStatus saved_status() {
1816 return m_saved_status;
1817 }
1818 private:
1819 JavaScriptFrame* m_frame;
1820 LiveEdit::FunctionPatchabilityStatus m_saved_status;
1821};
1822
1823
1824// Finds a drops required frame and all frames above.
1825// Returns error message or NULL.
1826const char* LiveEdit::RestartFrame(JavaScriptFrame* frame, Zone* zone) {
1827 SingleFrameTarget target(frame);
1828
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001829 const char* result = DropActivationsInActiveThreadImpl(target, true, zone);
1830 if (result != NULL) {
1831 return result;
1832 }
1833 if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE) {
1834 return "Function is blocked under native code";
1835 }
1836 return NULL;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001837}
1838
1839
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
1841 FunctionLiteral* fun)
1842 : isolate_(isolate) {
1843 if (isolate_->active_function_info_listener() != NULL) {
1844 isolate_->active_function_info_listener()->FunctionStarted(fun);
ager@chromium.org5c838252010-02-19 08:53:10 +00001845 }
1846}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001847
1848
ager@chromium.org5c838252010-02-19 08:53:10 +00001849LiveEditFunctionTracker::~LiveEditFunctionTracker() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001850 if (isolate_->active_function_info_listener() != NULL) {
1851 isolate_->active_function_info_listener()->FunctionDone();
ager@chromium.org5c838252010-02-19 08:53:10 +00001852 }
1853}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001854
1855
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001856void LiveEditFunctionTracker::RecordFunctionInfo(
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001857 Handle<SharedFunctionInfo> info, FunctionLiteral* lit,
1858 Zone* zone) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001859 if (isolate_->active_function_info_listener() != NULL) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001860 isolate_->active_function_info_listener()->FunctionInfo(info, lit->scope(),
1861 zone);
ager@chromium.org5c838252010-02-19 08:53:10 +00001862 }
1863}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001864
1865
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001866void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001867 isolate_->active_function_info_listener()->FunctionCode(code);
ager@chromium.org5c838252010-02-19 08:53:10 +00001868}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001869
1870
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001871bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
1872 return isolate->active_function_info_listener() != NULL;
ager@chromium.org5c838252010-02-19 08:53:10 +00001873}
1874
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001875
1876#else // ENABLE_DEBUGGER_SUPPORT
1877
1878// This ifdef-else-endif section provides working or stub implementation of
1879// LiveEditFunctionTracker.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001880LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
1881 FunctionLiteral* fun) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001882}
1883
1884
1885LiveEditFunctionTracker::~LiveEditFunctionTracker() {
1886}
1887
1888
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001889void LiveEditFunctionTracker::RecordFunctionInfo(
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001890 Handle<SharedFunctionInfo> info, FunctionLiteral* lit,
1891 Zone* zone) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001892}
1893
1894
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001895void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001896}
1897
1898
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001899bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001900 return false;
1901}
1902
1903#endif // ENABLE_DEBUGGER_SUPPORT
1904
1905
1906
ager@chromium.org5c838252010-02-19 08:53:10 +00001907} } // namespace v8::internal