blob: 9c5294a26d5031bdc559572b942388609136d681 [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Andrei Popescu402d9372010-02-26 13:31:12 +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"
Ben Murdochf87a2032010-10-22 12:50:53 +010032
Ben Murdochb0fe1622011-05-05 13:52:32 +010033#include "compilation-cache.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000034#include "compiler.h"
Andrei Popescu402d9372010-02-26 13:31:12 +000035#include "debug.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010036#include "deoptimizer.h"
Ben Murdochf87a2032010-10-22 12:50:53 +010037#include "global-handles.h"
Ben Murdochf87a2032010-10-22 12:50:53 +010038#include "parser.h"
39#include "scopeinfo.h"
40#include "scopes.h"
Steve Block44f0eee2011-05-26 01:26:41 +010041#include "v8memory.h"
Andrei Popescu402d9372010-02-26 13:31:12 +000042
43namespace v8 {
44namespace internal {
45
46
Steve Block6ded16b2010-05-10 14:33:55 +010047#ifdef ENABLE_DEBUGGER_SUPPORT
48
49
Steve Block44f0eee2011-05-26 01:26:41 +010050void SetElementNonStrict(Handle<JSObject> object,
51 uint32_t index,
52 Handle<Object> value) {
53 // Ignore return value from SetElement. It can only be a failure if there
54 // are element setters causing exceptions and the debugger context has none
55 // of these.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010056 Handle<Object> no_failure =
57 JSObject::SetElement(object, index, value, NONE, kNonStrictMode);
Steve Block44f0eee2011-05-26 01:26:41 +010058 ASSERT(!no_failure.is_null());
59 USE(no_failure);
60}
61
Steve Block6ded16b2010-05-10 14:33:55 +010062// A simple implementation of dynamic programming algorithm. It solves
63// the problem of finding the difference of 2 arrays. It uses a table of results
64// of subproblems. Each cell contains a number together with 2-bit flag
65// that helps building the chunk list.
66class Differencer {
Andrei Popescu402d9372010-02-26 13:31:12 +000067 public:
Steve Block6ded16b2010-05-10 14:33:55 +010068 explicit Differencer(Comparator::Input* input)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000069 : input_(input), len1_(input->GetLength1()), len2_(input->GetLength2()) {
Steve Block6ded16b2010-05-10 14:33:55 +010070 buffer_ = NewArray<int>(len1_ * len2_);
71 }
72 ~Differencer() {
73 DeleteArray(buffer_);
Andrei Popescu402d9372010-02-26 13:31:12 +000074 }
75
Steve Block6ded16b2010-05-10 14:33:55 +010076 void Initialize() {
77 int array_size = len1_ * len2_;
78 for (int i = 0; i < array_size; i++) {
79 buffer_[i] = kEmptyCellValue;
80 }
Andrei Popescu402d9372010-02-26 13:31:12 +000081 }
82
Steve Block6ded16b2010-05-10 14:33:55 +010083 // Makes sure that result for the full problem is calculated and stored
84 // in the table together with flags showing a path through subproblems.
85 void FillTable() {
86 CompareUpToTail(0, 0);
Andrei Popescu402d9372010-02-26 13:31:12 +000087 }
88
Steve Block6ded16b2010-05-10 14:33:55 +010089 void SaveResult(Comparator::Output* chunk_writer) {
90 ResultWriter writer(chunk_writer);
91
92 int pos1 = 0;
93 int pos2 = 0;
94 while (true) {
95 if (pos1 < len1_) {
96 if (pos2 < len2_) {
97 Direction dir = get_direction(pos1, pos2);
98 switch (dir) {
99 case EQ:
100 writer.eq();
101 pos1++;
102 pos2++;
103 break;
104 case SKIP1:
105 writer.skip1(1);
106 pos1++;
107 break;
108 case SKIP2:
109 case SKIP_ANY:
110 writer.skip2(1);
111 pos2++;
112 break;
113 default:
114 UNREACHABLE();
115 }
116 } else {
117 writer.skip1(len1_ - pos1);
118 break;
119 }
120 } else {
121 if (len2_ != pos2) {
122 writer.skip2(len2_ - pos2);
123 }
124 break;
125 }
126 }
127 writer.close();
128 }
129
130 private:
131 Comparator::Input* input_;
132 int* buffer_;
133 int len1_;
134 int len2_;
135
136 enum Direction {
137 EQ = 0,
138 SKIP1,
139 SKIP2,
140 SKIP_ANY,
141
142 MAX_DIRECTION_FLAG_VALUE = SKIP_ANY
143 };
144
145 // Computes result for a subtask and optionally caches it in the buffer table.
146 // All results values are shifted to make space for flags in the lower bits.
147 int CompareUpToTail(int pos1, int pos2) {
148 if (pos1 < len1_) {
149 if (pos2 < len2_) {
150 int cached_res = get_value4(pos1, pos2);
151 if (cached_res == kEmptyCellValue) {
152 Direction dir;
153 int res;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000154 if (input_->Equals(pos1, pos2)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100155 res = CompareUpToTail(pos1 + 1, pos2 + 1);
156 dir = EQ;
157 } else {
158 int res1 = CompareUpToTail(pos1 + 1, pos2) +
159 (1 << kDirectionSizeBits);
160 int res2 = CompareUpToTail(pos1, pos2 + 1) +
161 (1 << kDirectionSizeBits);
162 if (res1 == res2) {
163 res = res1;
164 dir = SKIP_ANY;
165 } else if (res1 < res2) {
166 res = res1;
167 dir = SKIP1;
168 } else {
169 res = res2;
170 dir = SKIP2;
171 }
172 }
173 set_value4_and_dir(pos1, pos2, res, dir);
174 cached_res = res;
175 }
176 return cached_res;
177 } else {
178 return (len1_ - pos1) << kDirectionSizeBits;
179 }
180 } else {
181 return (len2_ - pos2) << kDirectionSizeBits;
182 }
183 }
184
185 inline int& get_cell(int i1, int i2) {
186 return buffer_[i1 + i2 * len1_];
187 }
188
189 // Each cell keeps a value plus direction. Value is multiplied by 4.
190 void set_value4_and_dir(int i1, int i2, int value4, Direction dir) {
191 ASSERT((value4 & kDirectionMask) == 0);
192 get_cell(i1, i2) = value4 | dir;
193 }
194
195 int get_value4(int i1, int i2) {
196 return get_cell(i1, i2) & (kMaxUInt32 ^ kDirectionMask);
197 }
198 Direction get_direction(int i1, int i2) {
199 return static_cast<Direction>(get_cell(i1, i2) & kDirectionMask);
200 }
201
202 static const int kDirectionSizeBits = 2;
203 static const int kDirectionMask = (1 << kDirectionSizeBits) - 1;
204 static const int kEmptyCellValue = -1 << kDirectionSizeBits;
205
206 // This method only holds static assert statement (unfortunately you cannot
207 // place one in class scope).
208 void StaticAssertHolder() {
209 STATIC_ASSERT(MAX_DIRECTION_FLAG_VALUE < (1 << kDirectionSizeBits));
210 }
211
212 class ResultWriter {
213 public:
214 explicit ResultWriter(Comparator::Output* chunk_writer)
215 : chunk_writer_(chunk_writer), pos1_(0), pos2_(0),
216 pos1_begin_(-1), pos2_begin_(-1), has_open_chunk_(false) {
217 }
218 void eq() {
219 FlushChunk();
220 pos1_++;
221 pos2_++;
222 }
223 void skip1(int len1) {
224 StartChunk();
225 pos1_ += len1;
226 }
227 void skip2(int len2) {
228 StartChunk();
229 pos2_ += len2;
230 }
231 void close() {
232 FlushChunk();
233 }
234
235 private:
236 Comparator::Output* chunk_writer_;
237 int pos1_;
238 int pos2_;
239 int pos1_begin_;
240 int pos2_begin_;
241 bool has_open_chunk_;
242
243 void StartChunk() {
244 if (!has_open_chunk_) {
245 pos1_begin_ = pos1_;
246 pos2_begin_ = pos2_;
247 has_open_chunk_ = true;
248 }
249 }
250
251 void FlushChunk() {
252 if (has_open_chunk_) {
253 chunk_writer_->AddChunk(pos1_begin_, pos2_begin_,
254 pos1_ - pos1_begin_, pos2_ - pos2_begin_);
255 has_open_chunk_ = false;
256 }
257 }
258 };
259};
260
261
262void Comparator::CalculateDifference(Comparator::Input* input,
263 Comparator::Output* result_writer) {
264 Differencer differencer(input);
265 differencer.Initialize();
266 differencer.FillTable();
267 differencer.SaveResult(result_writer);
268}
269
270
Ben Murdoch257744e2011-11-30 15:57:28 +0000271static bool CompareSubstrings(Handle<String> s1, int pos1,
Steve Block6ded16b2010-05-10 14:33:55 +0100272 Handle<String> s2, int pos2, int len) {
Steve Block6ded16b2010-05-10 14:33:55 +0100273 for (int i = 0; i < len; i++) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000274 if (s1->Get(i + pos1) != s2->Get(i + pos2)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100275 return false;
276 }
277 }
278 return true;
279}
280
281
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000282// Additional to Input interface. Lets switch Input range to subrange.
283// More elegant way would be to wrap one Input as another Input object
284// and translate positions there, but that would cost us additional virtual
285// call per comparison.
286class SubrangableInput : public Comparator::Input {
287 public:
288 virtual void SetSubrange1(int offset, int len) = 0;
289 virtual void SetSubrange2(int offset, int len) = 0;
290};
291
292
293class SubrangableOutput : public Comparator::Output {
294 public:
295 virtual void SetSubrange1(int offset, int len) = 0;
296 virtual void SetSubrange2(int offset, int len) = 0;
297};
298
299
300static int min(int a, int b) {
301 return a < b ? a : b;
302}
303
304
305// Finds common prefix and suffix in input. This parts shouldn't take space in
306// linear programming table. Enable subranging in input and output.
307static void NarrowDownInput(SubrangableInput* input,
308 SubrangableOutput* output) {
309 const int len1 = input->GetLength1();
310 const int len2 = input->GetLength2();
311
312 int common_prefix_len;
313 int common_suffix_len;
314
315 {
316 common_prefix_len = 0;
317 int prefix_limit = min(len1, len2);
318 while (common_prefix_len < prefix_limit &&
319 input->Equals(common_prefix_len, common_prefix_len)) {
320 common_prefix_len++;
321 }
322
323 common_suffix_len = 0;
324 int suffix_limit = min(len1 - common_prefix_len, len2 - common_prefix_len);
325
326 while (common_suffix_len < suffix_limit &&
327 input->Equals(len1 - common_suffix_len - 1,
328 len2 - common_suffix_len - 1)) {
329 common_suffix_len++;
330 }
331 }
332
333 if (common_prefix_len > 0 || common_suffix_len > 0) {
334 int new_len1 = len1 - common_suffix_len - common_prefix_len;
335 int new_len2 = len2 - common_suffix_len - common_prefix_len;
336
337 input->SetSubrange1(common_prefix_len, new_len1);
338 input->SetSubrange2(common_prefix_len, new_len2);
339
340 output->SetSubrange1(common_prefix_len, new_len1);
341 output->SetSubrange2(common_prefix_len, new_len2);
342 }
343}
344
345
Ben Murdochb8e0da22011-05-16 14:20:40 +0100346// A helper class that writes chunk numbers into JSArray.
347// Each chunk is stored as 3 array elements: (pos1_begin, pos1_end, pos2_end).
348class CompareOutputArrayWriter {
349 public:
350 CompareOutputArrayWriter()
Steve Block44f0eee2011-05-26 01:26:41 +0100351 : array_(FACTORY->NewJSArray(10)), current_size_(0) {}
Ben Murdochb8e0da22011-05-16 14:20:40 +0100352
353 Handle<JSArray> GetResult() {
354 return array_;
355 }
356
357 void WriteChunk(int char_pos1, int char_pos2, int char_len1, int char_len2) {
Steve Block44f0eee2011-05-26 01:26:41 +0100358 SetElementNonStrict(array_,
359 current_size_,
360 Handle<Object>(Smi::FromInt(char_pos1)));
361 SetElementNonStrict(array_,
362 current_size_ + 1,
363 Handle<Object>(Smi::FromInt(char_pos1 + char_len1)));
364 SetElementNonStrict(array_,
365 current_size_ + 2,
366 Handle<Object>(Smi::FromInt(char_pos2 + char_len2)));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100367 current_size_ += 3;
368 }
369
370 private:
371 Handle<JSArray> array_;
372 int current_size_;
373};
374
375
376// Represents 2 strings as 2 arrays of tokens.
377// TODO(LiveEdit): Currently it's actually an array of charactres.
378// Make array of tokens instead.
379class TokensCompareInput : public Comparator::Input {
380 public:
381 TokensCompareInput(Handle<String> s1, int offset1, int len1,
382 Handle<String> s2, int offset2, int len2)
383 : s1_(s1), offset1_(offset1), len1_(len1),
384 s2_(s2), offset2_(offset2), len2_(len2) {
385 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000386 virtual int GetLength1() {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100387 return len1_;
388 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000389 virtual int GetLength2() {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100390 return len2_;
391 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000392 bool Equals(int index1, int index2) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100393 return s1_->Get(offset1_ + index1) == s2_->Get(offset2_ + index2);
394 }
395
396 private:
397 Handle<String> s1_;
398 int offset1_;
399 int len1_;
400 Handle<String> s2_;
401 int offset2_;
402 int len2_;
403};
404
405
406// Stores compare result in JSArray. Converts substring positions
407// to absolute positions.
408class TokensCompareOutput : public Comparator::Output {
409 public:
410 TokensCompareOutput(CompareOutputArrayWriter* array_writer,
411 int offset1, int offset2)
412 : array_writer_(array_writer), offset1_(offset1), offset2_(offset2) {
413 }
414
415 void AddChunk(int pos1, int pos2, int len1, int len2) {
416 array_writer_->WriteChunk(pos1 + offset1_, pos2 + offset2_, len1, len2);
417 }
418
419 private:
420 CompareOutputArrayWriter* array_writer_;
421 int offset1_;
422 int offset2_;
423};
424
425
Steve Block6ded16b2010-05-10 14:33:55 +0100426// Wraps raw n-elements line_ends array as a list of n+1 lines. The last line
427// never has terminating new line character.
428class LineEndsWrapper {
429 public:
430 explicit LineEndsWrapper(Handle<String> string)
431 : ends_array_(CalculateLineEnds(string, false)),
432 string_len_(string->length()) {
433 }
434 int length() {
435 return ends_array_->length() + 1;
436 }
437 // Returns start for any line including start of the imaginary line after
438 // the last line.
439 int GetLineStart(int index) {
440 if (index == 0) {
441 return 0;
442 } else {
443 return GetLineEnd(index - 1);
444 }
445 }
446 int GetLineEnd(int index) {
447 if (index == ends_array_->length()) {
448 // End of the last line is always an end of the whole string.
449 // If the string ends with a new line character, the last line is an
450 // empty string after this character.
451 return string_len_;
452 } else {
453 return GetPosAfterNewLine(index);
454 }
455 }
456
457 private:
458 Handle<FixedArray> ends_array_;
459 int string_len_;
460
461 int GetPosAfterNewLine(int index) {
462 return Smi::cast(ends_array_->get(index))->value() + 1;
Andrei Popescu402d9372010-02-26 13:31:12 +0000463 }
464};
465
Steve Block6ded16b2010-05-10 14:33:55 +0100466
467// Represents 2 strings as 2 arrays of lines.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000468class LineArrayCompareInput : public SubrangableInput {
Steve Block6ded16b2010-05-10 14:33:55 +0100469 public:
Ben Murdoch257744e2011-11-30 15:57:28 +0000470 LineArrayCompareInput(Handle<String> s1, Handle<String> s2,
Steve Block6ded16b2010-05-10 14:33:55 +0100471 LineEndsWrapper line_ends1, LineEndsWrapper line_ends2)
Ben Murdoch257744e2011-11-30 15:57:28 +0000472 : s1_(s1), s2_(s2), line_ends1_(line_ends1),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000473 line_ends2_(line_ends2),
474 subrange_offset1_(0), subrange_offset2_(0),
475 subrange_len1_(line_ends1_.length()),
476 subrange_len2_(line_ends2_.length()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100477 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000478 int GetLength1() {
479 return subrange_len1_;
Steve Block6ded16b2010-05-10 14:33:55 +0100480 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000481 int GetLength2() {
482 return subrange_len2_;
Steve Block6ded16b2010-05-10 14:33:55 +0100483 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000484 bool Equals(int index1, int index2) {
485 index1 += subrange_offset1_;
486 index2 += subrange_offset2_;
487
Steve Block6ded16b2010-05-10 14:33:55 +0100488 int line_start1 = line_ends1_.GetLineStart(index1);
489 int line_start2 = line_ends2_.GetLineStart(index2);
490 int line_end1 = line_ends1_.GetLineEnd(index1);
491 int line_end2 = line_ends2_.GetLineEnd(index2);
492 int len1 = line_end1 - line_start1;
493 int len2 = line_end2 - line_start2;
494 if (len1 != len2) {
495 return false;
496 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000497 return CompareSubstrings(s1_, line_start1, s2_, line_start2,
Steve Block44f0eee2011-05-26 01:26:41 +0100498 len1);
Steve Block6ded16b2010-05-10 14:33:55 +0100499 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000500 void SetSubrange1(int offset, int len) {
501 subrange_offset1_ = offset;
502 subrange_len1_ = len;
503 }
504 void SetSubrange2(int offset, int len) {
505 subrange_offset2_ = offset;
506 subrange_len2_ = len;
507 }
Steve Block6ded16b2010-05-10 14:33:55 +0100508
509 private:
510 Handle<String> s1_;
511 Handle<String> s2_;
512 LineEndsWrapper line_ends1_;
513 LineEndsWrapper line_ends2_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000514 int subrange_offset1_;
515 int subrange_offset2_;
516 int subrange_len1_;
517 int subrange_len2_;
Steve Block6ded16b2010-05-10 14:33:55 +0100518};
519
520
Ben Murdochb8e0da22011-05-16 14:20:40 +0100521// Stores compare result in JSArray. For each chunk tries to conduct
522// a fine-grained nested diff token-wise.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000523class TokenizingLineArrayCompareOutput : public SubrangableOutput {
Steve Block6ded16b2010-05-10 14:33:55 +0100524 public:
Ben Murdochb8e0da22011-05-16 14:20:40 +0100525 TokenizingLineArrayCompareOutput(LineEndsWrapper line_ends1,
526 LineEndsWrapper line_ends2,
527 Handle<String> s1, Handle<String> s2)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000528 : line_ends1_(line_ends1), line_ends2_(line_ends2), s1_(s1), s2_(s2),
529 subrange_offset1_(0), subrange_offset2_(0) {
Steve Block6ded16b2010-05-10 14:33:55 +0100530 }
531
532 void AddChunk(int line_pos1, int line_pos2, int line_len1, int line_len2) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000533 line_pos1 += subrange_offset1_;
534 line_pos2 += subrange_offset2_;
535
Steve Block6ded16b2010-05-10 14:33:55 +0100536 int char_pos1 = line_ends1_.GetLineStart(line_pos1);
537 int char_pos2 = line_ends2_.GetLineStart(line_pos2);
538 int char_len1 = line_ends1_.GetLineStart(line_pos1 + line_len1) - char_pos1;
539 int char_len2 = line_ends2_.GetLineStart(line_pos2 + line_len2) - char_pos2;
540
Ben Murdochb8e0da22011-05-16 14:20:40 +0100541 if (char_len1 < CHUNK_LEN_LIMIT && char_len2 < CHUNK_LEN_LIMIT) {
542 // Chunk is small enough to conduct a nested token-level diff.
543 HandleScope subTaskScope;
544
545 TokensCompareInput tokens_input(s1_, char_pos1, char_len1,
546 s2_, char_pos2, char_len2);
547 TokensCompareOutput tokens_output(&array_writer_, char_pos1,
548 char_pos2);
549
550 Comparator::CalculateDifference(&tokens_input, &tokens_output);
551 } else {
552 array_writer_.WriteChunk(char_pos1, char_pos2, char_len1, char_len2);
553 }
Steve Block6ded16b2010-05-10 14:33:55 +0100554 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000555 void SetSubrange1(int offset, int len) {
556 subrange_offset1_ = offset;
557 }
558 void SetSubrange2(int offset, int len) {
559 subrange_offset2_ = offset;
560 }
Steve Block6ded16b2010-05-10 14:33:55 +0100561
562 Handle<JSArray> GetResult() {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100563 return array_writer_.GetResult();
Steve Block6ded16b2010-05-10 14:33:55 +0100564 }
565
566 private:
Ben Murdochb8e0da22011-05-16 14:20:40 +0100567 static const int CHUNK_LEN_LIMIT = 800;
568
569 CompareOutputArrayWriter array_writer_;
Steve Block6ded16b2010-05-10 14:33:55 +0100570 LineEndsWrapper line_ends1_;
571 LineEndsWrapper line_ends2_;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100572 Handle<String> s1_;
573 Handle<String> s2_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000574 int subrange_offset1_;
575 int subrange_offset2_;
Steve Block6ded16b2010-05-10 14:33:55 +0100576};
577
578
Ben Murdochb8e0da22011-05-16 14:20:40 +0100579Handle<JSArray> LiveEdit::CompareStrings(Handle<String> s1,
580 Handle<String> s2) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000581 s1 = FlattenGetString(s1);
582 s2 = FlattenGetString(s2);
583
Steve Block6ded16b2010-05-10 14:33:55 +0100584 LineEndsWrapper line_ends1(s1);
585 LineEndsWrapper line_ends2(s2);
586
Ben Murdoch257744e2011-11-30 15:57:28 +0000587 LineArrayCompareInput input(s1, s2, line_ends1, line_ends2);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100588 TokenizingLineArrayCompareOutput output(line_ends1, line_ends2, s1, s2);
Steve Block6ded16b2010-05-10 14:33:55 +0100589
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000590 NarrowDownInput(&input, &output);
591
Steve Block6ded16b2010-05-10 14:33:55 +0100592 Comparator::CalculateDifference(&input, &output);
593
594 return output.GetResult();
595}
596
597
Steve Block44f0eee2011-05-26 01:26:41 +0100598static void CompileScriptForTracker(Isolate* isolate, Handle<Script> script) {
Steve Block6ded16b2010-05-10 14:33:55 +0100599 // TODO(635): support extensions.
Steve Block44f0eee2011-05-26 01:26:41 +0100600 PostponeInterruptsScope postpone(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +0100601
Steve Block6ded16b2010-05-10 14:33:55 +0100602 // Build AST.
Ben Murdochf87a2032010-10-22 12:50:53 +0100603 CompilationInfo info(script);
604 info.MarkAsGlobal();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100605 // Parse and don't allow skipping lazy functions.
606 if (ParserApi::Parse(&info, kNoParsingFlags)) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100607 // Compile the code.
Steve Block44f0eee2011-05-26 01:26:41 +0100608 LiveEditFunctionTracker tracker(info.isolate(), info.function());
Ben Murdochf87a2032010-10-22 12:50:53 +0100609 if (Compiler::MakeCodeForLiveEdit(&info)) {
610 ASSERT(!info.code().is_null());
611 tracker.RecordRootFunctionInfo(info.code());
612 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100613 info.isolate()->StackOverflow();
Ben Murdochf87a2032010-10-22 12:50:53 +0100614 }
Steve Block6ded16b2010-05-10 14:33:55 +0100615 }
Steve Block6ded16b2010-05-10 14:33:55 +0100616}
617
Ben Murdochf87a2032010-10-22 12:50:53 +0100618
Steve Block6ded16b2010-05-10 14:33:55 +0100619// Unwraps JSValue object, returning its field "value"
620static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) {
621 return Handle<Object>(jsValue->value());
622}
623
Ben Murdochf87a2032010-10-22 12:50:53 +0100624
Steve Block6ded16b2010-05-10 14:33:55 +0100625// Wraps any object into a OpaqueReference, that will hide the object
626// from JavaScript.
Ben Murdoch257744e2011-11-30 15:57:28 +0000627static Handle<JSValue> WrapInJSValue(Handle<Object> object) {
Steve Block44f0eee2011-05-26 01:26:41 +0100628 Handle<JSFunction> constructor =
629 Isolate::Current()->opaque_reference_function();
Steve Block6ded16b2010-05-10 14:33:55 +0100630 Handle<JSValue> result =
Steve Block44f0eee2011-05-26 01:26:41 +0100631 Handle<JSValue>::cast(FACTORY->NewJSObject(constructor));
Ben Murdoch257744e2011-11-30 15:57:28 +0000632 result->set_value(*object);
Steve Block6ded16b2010-05-10 14:33:55 +0100633 return result;
634}
635
Ben Murdochf87a2032010-10-22 12:50:53 +0100636
Steve Block6ded16b2010-05-10 14:33:55 +0100637// Simple helper class that creates more or less typed structures over
638// JSArray object. This is an adhoc method of passing structures from C++
639// to JavaScript.
640template<typename S>
641class JSArrayBasedStruct {
642 public:
643 static S Create() {
Steve Block44f0eee2011-05-26 01:26:41 +0100644 Handle<JSArray> array = FACTORY->NewJSArray(S::kSize_);
Steve Block6ded16b2010-05-10 14:33:55 +0100645 return S(array);
646 }
647 static S cast(Object* object) {
648 JSArray* array = JSArray::cast(object);
649 Handle<JSArray> array_handle(array);
650 return S(array_handle);
651 }
652 explicit JSArrayBasedStruct(Handle<JSArray> array) : array_(array) {
653 }
654 Handle<JSArray> GetJSArray() {
655 return array_;
656 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100657
Steve Block6ded16b2010-05-10 14:33:55 +0100658 protected:
659 void SetField(int field_position, Handle<Object> value) {
Steve Block44f0eee2011-05-26 01:26:41 +0100660 SetElementNonStrict(array_, field_position, value);
Steve Block6ded16b2010-05-10 14:33:55 +0100661 }
662 void SetSmiValueField(int field_position, int value) {
Steve Block44f0eee2011-05-26 01:26:41 +0100663 SetElementNonStrict(array_,
664 field_position,
665 Handle<Smi>(Smi::FromInt(value)));
Steve Block6ded16b2010-05-10 14:33:55 +0100666 }
667 Object* GetField(int field_position) {
John Reck59135872010-11-02 12:39:01 -0700668 return array_->GetElementNoExceptionThrown(field_position);
Steve Block6ded16b2010-05-10 14:33:55 +0100669 }
670 int GetSmiValueField(int field_position) {
671 Object* res = GetField(field_position);
672 return Smi::cast(res)->value();
673 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100674
Steve Block6ded16b2010-05-10 14:33:55 +0100675 private:
676 Handle<JSArray> array_;
677};
678
679
680// Represents some function compilation details. This structure will be used
681// from JavaScript. It contains Code object, which is kept wrapped
682// into a BlindReference for sanitizing reasons.
683class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
684 public:
685 explicit FunctionInfoWrapper(Handle<JSArray> array)
686 : JSArrayBasedStruct<FunctionInfoWrapper>(array) {
687 }
688 void SetInitialProperties(Handle<String> name, int start_position,
689 int end_position, int param_num, int parent_index) {
690 HandleScope scope;
691 this->SetField(kFunctionNameOffset_, name);
692 this->SetSmiValueField(kStartPositionOffset_, start_position);
693 this->SetSmiValueField(kEndPositionOffset_, end_position);
694 this->SetSmiValueField(kParamNumOffset_, param_num);
695 this->SetSmiValueField(kParentIndexOffset_, parent_index);
696 }
Iain Merrick75681382010-08-19 15:07:18 +0100697 void SetFunctionCode(Handle<Code> function_code,
698 Handle<Object> code_scope_info) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000699 Handle<JSValue> code_wrapper = WrapInJSValue(function_code);
Iain Merrick75681382010-08-19 15:07:18 +0100700 this->SetField(kCodeOffset_, code_wrapper);
701
Ben Murdoch257744e2011-11-30 15:57:28 +0000702 Handle<JSValue> scope_wrapper = WrapInJSValue(code_scope_info);
Iain Merrick75681382010-08-19 15:07:18 +0100703 this->SetField(kCodeScopeInfoOffset_, scope_wrapper);
Steve Block6ded16b2010-05-10 14:33:55 +0100704 }
Iain Merrick75681382010-08-19 15:07:18 +0100705 void SetOuterScopeInfo(Handle<Object> scope_info_array) {
706 this->SetField(kOuterScopeInfoOffset_, scope_info_array);
Steve Block6ded16b2010-05-10 14:33:55 +0100707 }
708 void SetSharedFunctionInfo(Handle<SharedFunctionInfo> info) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000709 Handle<JSValue> info_holder = WrapInJSValue(info);
Steve Block6ded16b2010-05-10 14:33:55 +0100710 this->SetField(kSharedFunctionInfoOffset_, info_holder);
711 }
712 int GetParentIndex() {
713 return this->GetSmiValueField(kParentIndexOffset_);
714 }
715 Handle<Code> GetFunctionCode() {
716 Handle<Object> raw_result = UnwrapJSValue(Handle<JSValue>(
717 JSValue::cast(this->GetField(kCodeOffset_))));
718 return Handle<Code>::cast(raw_result);
719 }
Iain Merrick75681382010-08-19 15:07:18 +0100720 Handle<Object> GetCodeScopeInfo() {
721 Handle<Object> raw_result = UnwrapJSValue(Handle<JSValue>(
722 JSValue::cast(this->GetField(kCodeScopeInfoOffset_))));
723 return raw_result;
724 }
Steve Block6ded16b2010-05-10 14:33:55 +0100725 int GetStartPosition() {
726 return this->GetSmiValueField(kStartPositionOffset_);
727 }
728 int GetEndPosition() {
729 return this->GetSmiValueField(kEndPositionOffset_);
730 }
731
732 private:
733 static const int kFunctionNameOffset_ = 0;
734 static const int kStartPositionOffset_ = 1;
735 static const int kEndPositionOffset_ = 2;
736 static const int kParamNumOffset_ = 3;
737 static const int kCodeOffset_ = 4;
Iain Merrick75681382010-08-19 15:07:18 +0100738 static const int kCodeScopeInfoOffset_ = 5;
739 static const int kOuterScopeInfoOffset_ = 6;
740 static const int kParentIndexOffset_ = 7;
741 static const int kSharedFunctionInfoOffset_ = 8;
742 static const int kSize_ = 9;
Steve Block6ded16b2010-05-10 14:33:55 +0100743
744 friend class JSArrayBasedStruct<FunctionInfoWrapper>;
745};
746
Ben Murdochf87a2032010-10-22 12:50:53 +0100747
Steve Block6ded16b2010-05-10 14:33:55 +0100748// Wraps SharedFunctionInfo along with some of its fields for passing it
749// back to JavaScript. SharedFunctionInfo object itself is additionally
750// wrapped into BlindReference for sanitizing reasons.
751class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> {
752 public:
753 static bool IsInstance(Handle<JSArray> array) {
754 return array->length() == Smi::FromInt(kSize_) &&
John Reck59135872010-11-02 12:39:01 -0700755 array->GetElementNoExceptionThrown(kSharedInfoOffset_)->IsJSValue();
Steve Block6ded16b2010-05-10 14:33:55 +0100756 }
757
758 explicit SharedInfoWrapper(Handle<JSArray> array)
759 : JSArrayBasedStruct<SharedInfoWrapper>(array) {
760 }
761
762 void SetProperties(Handle<String> name, int start_position, int end_position,
763 Handle<SharedFunctionInfo> info) {
764 HandleScope scope;
765 this->SetField(kFunctionNameOffset_, name);
Ben Murdoch257744e2011-11-30 15:57:28 +0000766 Handle<JSValue> info_holder = WrapInJSValue(info);
Steve Block6ded16b2010-05-10 14:33:55 +0100767 this->SetField(kSharedInfoOffset_, info_holder);
768 this->SetSmiValueField(kStartPositionOffset_, start_position);
769 this->SetSmiValueField(kEndPositionOffset_, end_position);
770 }
771 Handle<SharedFunctionInfo> GetInfo() {
772 Object* element = this->GetField(kSharedInfoOffset_);
773 Handle<JSValue> value_wrapper(JSValue::cast(element));
774 Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
775 return Handle<SharedFunctionInfo>::cast(raw_result);
776 }
777
778 private:
779 static const int kFunctionNameOffset_ = 0;
780 static const int kStartPositionOffset_ = 1;
781 static const int kEndPositionOffset_ = 2;
782 static const int kSharedInfoOffset_ = 3;
783 static const int kSize_ = 4;
784
785 friend class JSArrayBasedStruct<SharedInfoWrapper>;
786};
787
Ben Murdochf87a2032010-10-22 12:50:53 +0100788
Steve Block6ded16b2010-05-10 14:33:55 +0100789class FunctionInfoListener {
790 public:
791 FunctionInfoListener() {
792 current_parent_index_ = -1;
793 len_ = 0;
Steve Block44f0eee2011-05-26 01:26:41 +0100794 result_ = FACTORY->NewJSArray(10);
Steve Block6ded16b2010-05-10 14:33:55 +0100795 }
796
797 void FunctionStarted(FunctionLiteral* fun) {
798 HandleScope scope;
799 FunctionInfoWrapper info = FunctionInfoWrapper::Create();
800 info.SetInitialProperties(fun->name(), fun->start_position(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100801 fun->end_position(), fun->parameter_count(),
Steve Block6ded16b2010-05-10 14:33:55 +0100802 current_parent_index_);
803 current_parent_index_ = len_;
Steve Block44f0eee2011-05-26 01:26:41 +0100804 SetElementNonStrict(result_, len_, info.GetJSArray());
Steve Block6ded16b2010-05-10 14:33:55 +0100805 len_++;
806 }
807
808 void FunctionDone() {
809 HandleScope scope;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100810 FunctionInfoWrapper info =
811 FunctionInfoWrapper::cast(
812 result_->GetElementNoExceptionThrown(current_parent_index_));
Steve Block6ded16b2010-05-10 14:33:55 +0100813 current_parent_index_ = info.GetParentIndex();
814 }
815
Steve Block59151502010-09-22 15:07:15 +0100816 // Saves only function code, because for a script function we
817 // may never create a SharedFunctionInfo object.
818 void FunctionCode(Handle<Code> function_code) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100819 FunctionInfoWrapper info =
820 FunctionInfoWrapper::cast(
821 result_->GetElementNoExceptionThrown(current_parent_index_));
Steve Block44f0eee2011-05-26 01:26:41 +0100822 info.SetFunctionCode(function_code, Handle<Object>(HEAP->null_value()));
Steve Block59151502010-09-22 15:07:15 +0100823 }
824
825 // Saves full information about a function: its code, its scope info
826 // and a SharedFunctionInfo object.
827 void FunctionInfo(Handle<SharedFunctionInfo> shared, Scope* scope) {
828 if (!shared->IsSharedFunctionInfo()) {
829 return;
830 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100831 FunctionInfoWrapper info =
832 FunctionInfoWrapper::cast(
833 result_->GetElementNoExceptionThrown(current_parent_index_));
Steve Block59151502010-09-22 15:07:15 +0100834 info.SetFunctionCode(Handle<Code>(shared->code()),
835 Handle<Object>(shared->scope_info()));
836 info.SetSharedFunctionInfo(shared);
837
838 Handle<Object> scope_info_list(SerializeFunctionScope(scope));
839 info.SetOuterScopeInfo(scope_info_list);
840 }
841
842 Handle<JSArray> GetResult() { return result_; }
843
Steve Block6ded16b2010-05-10 14:33:55 +0100844 private:
845 Object* SerializeFunctionScope(Scope* scope) {
846 HandleScope handle_scope;
847
Steve Block44f0eee2011-05-26 01:26:41 +0100848 Handle<JSArray> scope_info_list = FACTORY->NewJSArray(10);
Steve Block6ded16b2010-05-10 14:33:55 +0100849 int scope_info_length = 0;
850
851 // Saves some description of scope. It stores name and indexes of
852 // variables in the whole scope chain. Null-named slots delimit
853 // scopes of this chain.
854 Scope* outer_scope = scope->outer_scope();
855 if (outer_scope == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100856 return HEAP->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +0100857 }
858 do {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100859 ZoneList<Variable*> stack_list(outer_scope->StackLocalCount());
860 ZoneList<Variable*> context_list(outer_scope->ContextLocalCount());
861 outer_scope->CollectStackAndContextLocals(&stack_list, &context_list);
862 context_list.Sort(&Variable::CompareIndex);
Steve Block6ded16b2010-05-10 14:33:55 +0100863
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100864 for (int i = 0; i < context_list.length(); i++) {
Steve Block44f0eee2011-05-26 01:26:41 +0100865 SetElementNonStrict(scope_info_list,
866 scope_info_length,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100867 context_list[i]->name());
Steve Block6ded16b2010-05-10 14:33:55 +0100868 scope_info_length++;
Steve Block44f0eee2011-05-26 01:26:41 +0100869 SetElementNonStrict(
870 scope_info_list,
871 scope_info_length,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100872 Handle<Smi>(Smi::FromInt(context_list[i]->index())));
Steve Block6ded16b2010-05-10 14:33:55 +0100873 scope_info_length++;
874 }
Steve Block44f0eee2011-05-26 01:26:41 +0100875 SetElementNonStrict(scope_info_list,
876 scope_info_length,
877 Handle<Object>(HEAP->null_value()));
Steve Block6ded16b2010-05-10 14:33:55 +0100878 scope_info_length++;
879
880 outer_scope = outer_scope->outer_scope();
881 } while (outer_scope != NULL);
882
883 return *scope_info_list;
884 }
885
Steve Block6ded16b2010-05-10 14:33:55 +0100886 Handle<JSArray> result_;
887 int len_;
888 int current_parent_index_;
889};
890
Ben Murdochf87a2032010-10-22 12:50:53 +0100891
Steve Block6ded16b2010-05-10 14:33:55 +0100892JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script,
893 Handle<String> source) {
Steve Block44f0eee2011-05-26 01:26:41 +0100894 Isolate* isolate = Isolate::Current();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000895 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
Steve Block6ded16b2010-05-10 14:33:55 +0100896
897 FunctionInfoListener listener;
898 Handle<Object> original_source = Handle<Object>(script->source());
899 script->set_source(*source);
Steve Block44f0eee2011-05-26 01:26:41 +0100900 isolate->set_active_function_info_listener(&listener);
901 CompileScriptForTracker(isolate, script);
902 isolate->set_active_function_info_listener(NULL);
Steve Block6ded16b2010-05-10 14:33:55 +0100903 script->set_source(*original_source);
904
905 return *(listener.GetResult());
906}
907
908
909void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> array) {
910 HandleScope scope;
911 int len = Smi::cast(array->length())->value();
912 for (int i = 0; i < len; i++) {
913 Handle<SharedFunctionInfo> info(
John Reck59135872010-11-02 12:39:01 -0700914 SharedFunctionInfo::cast(array->GetElementNoExceptionThrown(i)));
Steve Block6ded16b2010-05-10 14:33:55 +0100915 SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create();
916 Handle<String> name_handle(String::cast(info->name()));
917 info_wrapper.SetProperties(name_handle, info->start_position(),
918 info->end_position(), info);
Steve Block44f0eee2011-05-26 01:26:41 +0100919 SetElementNonStrict(array, i, info_wrapper.GetJSArray());
Steve Block6ded16b2010-05-10 14:33:55 +0100920 }
921}
922
923
924// Visitor that collects all references to a particular code object,
925// including "CODE_TARGET" references in other code objects.
926// It works in context of ZoneScope.
927class ReferenceCollectorVisitor : public ObjectVisitor {
928 public:
929 explicit ReferenceCollectorVisitor(Code* original)
Steve Block791712a2010-08-27 10:21:07 +0100930 : original_(original), rvalues_(10), reloc_infos_(10), code_entries_(10) {
Steve Block6ded16b2010-05-10 14:33:55 +0100931 }
932
933 virtual void VisitPointers(Object** start, Object** end) {
934 for (Object** p = start; p < end; p++) {
935 if (*p == original_) {
936 rvalues_.Add(p);
937 }
938 }
939 }
940
Steve Block791712a2010-08-27 10:21:07 +0100941 virtual void VisitCodeEntry(Address entry) {
942 if (Code::GetObjectFromEntryAddress(entry) == original_) {
943 code_entries_.Add(entry);
944 }
945 }
946
947 virtual void VisitCodeTarget(RelocInfo* rinfo) {
Steve Block6ded16b2010-05-10 14:33:55 +0100948 if (RelocInfo::IsCodeTarget(rinfo->rmode()) &&
949 Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) {
950 reloc_infos_.Add(*rinfo);
951 }
952 }
953
954 virtual void VisitDebugTarget(RelocInfo* rinfo) {
955 VisitCodeTarget(rinfo);
956 }
957
958 // Post-visiting method that iterates over all collected references and
959 // modifies them.
960 void Replace(Code* substitution) {
961 for (int i = 0; i < rvalues_.length(); i++) {
962 *(rvalues_[i]) = substitution;
963 }
Steve Block791712a2010-08-27 10:21:07 +0100964 Address substitution_entry = substitution->instruction_start();
Steve Block6ded16b2010-05-10 14:33:55 +0100965 for (int i = 0; i < reloc_infos_.length(); i++) {
Steve Block791712a2010-08-27 10:21:07 +0100966 reloc_infos_[i].set_target_address(substitution_entry);
967 }
968 for (int i = 0; i < code_entries_.length(); i++) {
969 Address entry = code_entries_[i];
970 Memory::Address_at(entry) = substitution_entry;
Steve Block6ded16b2010-05-10 14:33:55 +0100971 }
972 }
973
974 private:
975 Code* original_;
976 ZoneList<Object**> rvalues_;
977 ZoneList<RelocInfo> reloc_infos_;
Steve Block791712a2010-08-27 10:21:07 +0100978 ZoneList<Address> code_entries_;
Steve Block6ded16b2010-05-10 14:33:55 +0100979};
980
981
Steve Block6ded16b2010-05-10 14:33:55 +0100982// Finds all references to original and replaces them with substitution.
983static void ReplaceCodeObject(Code* original, Code* substitution) {
Steve Block44f0eee2011-05-26 01:26:41 +0100984 ASSERT(!HEAP->InNewSpace(substitution));
Steve Block6ded16b2010-05-10 14:33:55 +0100985
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100986 HeapIterator iterator;
Steve Block6ded16b2010-05-10 14:33:55 +0100987 AssertNoAllocation no_allocations_please;
988
989 // A zone scope for ReferenceCollectorVisitor.
Ben Murdoch257744e2011-11-30 15:57:28 +0000990 ZoneScope scope(Isolate::Current(), DELETE_ON_EXIT);
Steve Block6ded16b2010-05-10 14:33:55 +0100991
992 ReferenceCollectorVisitor visitor(original);
993
994 // Iterate over all roots. Stack frames may have pointer into original code,
995 // so temporary replace the pointers with offset numbers
996 // in prologue/epilogue.
997 {
Steve Block44f0eee2011-05-26 01:26:41 +0100998 HEAP->IterateStrongRoots(&visitor, VISIT_ALL);
Steve Block6ded16b2010-05-10 14:33:55 +0100999 }
1000
1001 // Now iterate over all pointers of all objects, including code_target
1002 // implicit pointers.
Steve Block6ded16b2010-05-10 14:33:55 +01001003 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1004 obj->Iterate(&visitor);
1005 }
1006
1007 visitor.Replace(substitution);
1008}
1009
1010
1011// Check whether the code is natural function code (not a lazy-compile stub
1012// code).
1013static bool IsJSFunctionCode(Code* code) {
1014 return code->kind() == Code::FUNCTION;
1015}
1016
1017
Ben Murdochb0fe1622011-05-05 13:52:32 +01001018// Returns true if an instance of candidate were inlined into function's code.
1019static bool IsInlined(JSFunction* function, SharedFunctionInfo* candidate) {
1020 AssertNoAllocation no_gc;
1021
1022 if (function->code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
1023
1024 DeoptimizationInputData* data =
1025 DeoptimizationInputData::cast(function->code()->deoptimization_data());
1026
Steve Block44f0eee2011-05-26 01:26:41 +01001027 if (data == HEAP->empty_fixed_array()) return false;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001028
1029 FixedArray* literals = data->LiteralArray();
1030
1031 int inlined_count = data->InlinedFunctionCount()->value();
1032 for (int i = 0; i < inlined_count; ++i) {
1033 JSFunction* inlined = JSFunction::cast(literals->get(i));
1034 if (inlined->shared() == candidate) return true;
1035 }
1036
1037 return false;
1038}
1039
1040
1041class DependentFunctionsDeoptimizingVisitor : public OptimizedFunctionVisitor {
1042 public:
1043 explicit DependentFunctionsDeoptimizingVisitor(
1044 SharedFunctionInfo* function_info)
1045 : function_info_(function_info) {}
1046
1047 virtual void EnterContext(Context* context) {
1048 }
1049
1050 virtual void VisitFunction(JSFunction* function) {
1051 if (function->shared() == function_info_ ||
1052 IsInlined(function, function_info_)) {
1053 Deoptimizer::DeoptimizeFunction(function);
1054 }
1055 }
1056
1057 virtual void LeaveContext(Context* context) {
1058 }
1059
1060 private:
1061 SharedFunctionInfo* function_info_;
1062};
1063
1064
1065static void DeoptimizeDependentFunctions(SharedFunctionInfo* function_info) {
1066 AssertNoAllocation no_allocation;
1067
1068 DependentFunctionsDeoptimizingVisitor visitor(function_info);
1069 Deoptimizer::VisitAllOptimizedFunctions(&visitor);
1070}
1071
1072
John Reck59135872010-11-02 12:39:01 -07001073MaybeObject* LiveEdit::ReplaceFunctionCode(
1074 Handle<JSArray> new_compile_info_array,
1075 Handle<JSArray> shared_info_array) {
Steve Block6ded16b2010-05-10 14:33:55 +01001076 HandleScope scope;
1077
1078 if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
Steve Block44f0eee2011-05-26 01:26:41 +01001079 return Isolate::Current()->ThrowIllegalOperation();
Steve Block6ded16b2010-05-10 14:33:55 +01001080 }
1081
1082 FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
1083 SharedInfoWrapper shared_info_wrapper(shared_info_array);
1084
1085 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
1086
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001087 HEAP->EnsureHeapIsIterable();
1088
Steve Block6ded16b2010-05-10 14:33:55 +01001089 if (IsJSFunctionCode(shared_info->code())) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001090 Handle<Code> code = compile_info_wrapper.GetFunctionCode();
1091 ReplaceCodeObject(shared_info->code(), *code);
Iain Merrick75681382010-08-19 15:07:18 +01001092 Handle<Object> code_scope_info = compile_info_wrapper.GetCodeScopeInfo();
1093 if (code_scope_info->IsFixedArray()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001094 shared_info->set_scope_info(ScopeInfo::cast(*code_scope_info));
Iain Merrick75681382010-08-19 15:07:18 +01001095 }
Steve Block6ded16b2010-05-10 14:33:55 +01001096 }
1097
1098 if (shared_info->debug_info()->IsDebugInfo()) {
1099 Handle<DebugInfo> debug_info(DebugInfo::cast(shared_info->debug_info()));
1100 Handle<Code> new_original_code =
Steve Block44f0eee2011-05-26 01:26:41 +01001101 FACTORY->CopyCode(compile_info_wrapper.GetFunctionCode());
Steve Block6ded16b2010-05-10 14:33:55 +01001102 debug_info->set_original_code(*new_original_code);
1103 }
1104
Ben Murdoch8b112d22011-06-08 16:22:53 +01001105 int start_position = compile_info_wrapper.GetStartPosition();
1106 int end_position = compile_info_wrapper.GetEndPosition();
1107 shared_info->set_start_position(start_position);
1108 shared_info->set_end_position(end_position);
Steve Block6ded16b2010-05-10 14:33:55 +01001109
1110 shared_info->set_construct_stub(
Steve Block44f0eee2011-05-26 01:26:41 +01001111 Isolate::Current()->builtins()->builtin(
1112 Builtins::kJSConstructStubGeneric));
Steve Block6ded16b2010-05-10 14:33:55 +01001113
Ben Murdochb0fe1622011-05-05 13:52:32 +01001114 DeoptimizeDependentFunctions(*shared_info);
Steve Block44f0eee2011-05-26 01:26:41 +01001115 Isolate::Current()->compilation_cache()->Remove(shared_info);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001116
Steve Block44f0eee2011-05-26 01:26:41 +01001117 return HEAP->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001118}
1119
1120
Ben Murdochb0fe1622011-05-05 13:52:32 +01001121MaybeObject* LiveEdit::FunctionSourceUpdated(
1122 Handle<JSArray> shared_info_array) {
1123 HandleScope scope;
1124
1125 if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
Steve Block44f0eee2011-05-26 01:26:41 +01001126 return Isolate::Current()->ThrowIllegalOperation();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001127 }
1128
1129 SharedInfoWrapper shared_info_wrapper(shared_info_array);
1130 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
1131
1132 DeoptimizeDependentFunctions(*shared_info);
Steve Block44f0eee2011-05-26 01:26:41 +01001133 Isolate::Current()->compilation_cache()->Remove(shared_info);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001134
Steve Block44f0eee2011-05-26 01:26:41 +01001135 return HEAP->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001136}
1137
1138
Steve Block6ded16b2010-05-10 14:33:55 +01001139void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
1140 Handle<Object> script_handle) {
1141 Handle<SharedFunctionInfo> shared_info =
1142 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(function_wrapper));
1143 shared_info->set_script(*script_handle);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001144
Steve Block44f0eee2011-05-26 01:26:41 +01001145 Isolate::Current()->compilation_cache()->Remove(shared_info);
Steve Block6ded16b2010-05-10 14:33:55 +01001146}
1147
1148
1149// For a script text change (defined as position_change_array), translates
1150// position in unchanged text to position in changed text.
1151// Text change is a set of non-overlapping regions in text, that have changed
1152// their contents and length. It is specified as array of groups of 3 numbers:
1153// (change_begin, change_end, change_end_new_position).
1154// Each group describes a change in text; groups are sorted by change_begin.
1155// Only position in text beyond any changes may be successfully translated.
1156// If a positions is inside some region that changed, result is currently
1157// undefined.
1158static int TranslatePosition(int original_position,
1159 Handle<JSArray> position_change_array) {
1160 int position_diff = 0;
1161 int array_len = Smi::cast(position_change_array->length())->value();
1162 // TODO(635): binary search may be used here
1163 for (int i = 0; i < array_len; i += 3) {
John Reck59135872010-11-02 12:39:01 -07001164 Object* element = position_change_array->GetElementNoExceptionThrown(i);
1165 int chunk_start = Smi::cast(element)->value();
Steve Block6ded16b2010-05-10 14:33:55 +01001166 if (original_position < chunk_start) {
1167 break;
1168 }
John Reck59135872010-11-02 12:39:01 -07001169 element = position_change_array->GetElementNoExceptionThrown(i + 1);
1170 int chunk_end = Smi::cast(element)->value();
Steve Block6ded16b2010-05-10 14:33:55 +01001171 // Position mustn't be inside a chunk.
1172 ASSERT(original_position >= chunk_end);
John Reck59135872010-11-02 12:39:01 -07001173 element = position_change_array->GetElementNoExceptionThrown(i + 2);
1174 int chunk_changed_end = Smi::cast(element)->value();
Steve Block6ded16b2010-05-10 14:33:55 +01001175 position_diff = chunk_changed_end - chunk_end;
1176 }
1177
1178 return original_position + position_diff;
1179}
1180
1181
1182// Auto-growing buffer for writing relocation info code section. This buffer
1183// is a simplified version of buffer from Assembler. Unlike Assembler, this
1184// class is platform-independent and it works without dealing with instructions.
1185// As specified by RelocInfo format, the buffer is filled in reversed order:
1186// from upper to lower addresses.
1187// It uses NewArray/DeleteArray for memory management.
1188class RelocInfoBuffer {
1189 public:
1190 RelocInfoBuffer(int buffer_initial_capicity, byte* pc) {
1191 buffer_size_ = buffer_initial_capicity + kBufferGap;
1192 buffer_ = NewArray<byte>(buffer_size_);
1193
1194 reloc_info_writer_.Reposition(buffer_ + buffer_size_, pc);
1195 }
1196 ~RelocInfoBuffer() {
1197 DeleteArray(buffer_);
1198 }
1199
1200 // As specified by RelocInfo format, the buffer is filled in reversed order:
1201 // from upper to lower addresses.
1202 void Write(const RelocInfo* rinfo) {
1203 if (buffer_ + kBufferGap >= reloc_info_writer_.pos()) {
1204 Grow();
1205 }
1206 reloc_info_writer_.Write(rinfo);
1207 }
1208
1209 Vector<byte> GetResult() {
1210 // Return the bytes from pos up to end of buffer.
1211 int result_size =
1212 static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer_.pos());
1213 return Vector<byte>(reloc_info_writer_.pos(), result_size);
1214 }
1215
1216 private:
1217 void Grow() {
1218 // Compute new buffer size.
1219 int new_buffer_size;
1220 if (buffer_size_ < 2 * KB) {
1221 new_buffer_size = 4 * KB;
1222 } else {
1223 new_buffer_size = 2 * buffer_size_;
1224 }
1225 // Some internal data structures overflow for very large buffers,
1226 // they must ensure that kMaximalBufferSize is not too large.
1227 if (new_buffer_size > kMaximalBufferSize) {
1228 V8::FatalProcessOutOfMemory("RelocInfoBuffer::GrowBuffer");
1229 }
1230
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001231 // Set up new buffer.
Steve Block6ded16b2010-05-10 14:33:55 +01001232 byte* new_buffer = NewArray<byte>(new_buffer_size);
1233
1234 // Copy the data.
1235 int curently_used_size =
1236 static_cast<int>(buffer_ + buffer_size_ - reloc_info_writer_.pos());
1237 memmove(new_buffer + new_buffer_size - curently_used_size,
1238 reloc_info_writer_.pos(), curently_used_size);
1239
1240 reloc_info_writer_.Reposition(
1241 new_buffer + new_buffer_size - curently_used_size,
1242 reloc_info_writer_.last_pc());
1243
1244 DeleteArray(buffer_);
1245 buffer_ = new_buffer;
1246 buffer_size_ = new_buffer_size;
1247 }
1248
1249 RelocInfoWriter reloc_info_writer_;
1250 byte* buffer_;
1251 int buffer_size_;
1252
Leon Clarkef7060e22010-06-03 12:02:55 +01001253 static const int kBufferGap = RelocInfoWriter::kMaxSize;
Steve Block6ded16b2010-05-10 14:33:55 +01001254 static const int kMaximalBufferSize = 512*MB;
1255};
1256
1257// Patch positions in code (changes relocation info section) and possibly
1258// returns new instance of code.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001259static Handle<Code> PatchPositionsInCode(
1260 Handle<Code> code,
Steve Block6ded16b2010-05-10 14:33:55 +01001261 Handle<JSArray> position_change_array) {
1262
1263 RelocInfoBuffer buffer_writer(code->relocation_size(),
1264 code->instruction_start());
1265
1266 {
1267 AssertNoAllocation no_allocations_please;
1268 for (RelocIterator it(*code); !it.done(); it.next()) {
1269 RelocInfo* rinfo = it.rinfo();
1270 if (RelocInfo::IsPosition(rinfo->rmode())) {
1271 int position = static_cast<int>(rinfo->data());
1272 int new_position = TranslatePosition(position,
1273 position_change_array);
1274 if (position != new_position) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001275 RelocInfo info_copy(rinfo->pc(), rinfo->rmode(), new_position, NULL);
Steve Block6ded16b2010-05-10 14:33:55 +01001276 buffer_writer.Write(&info_copy);
1277 continue;
1278 }
1279 }
1280 buffer_writer.Write(it.rinfo());
1281 }
1282 }
1283
1284 Vector<byte> buffer = buffer_writer.GetResult();
1285
1286 if (buffer.length() == code->relocation_size()) {
1287 // Simply patch relocation area of code.
1288 memcpy(code->relocation_start(), buffer.start(), buffer.length());
1289 return code;
1290 } else {
1291 // Relocation info section now has different size. We cannot simply
1292 // rewrite it inside code object. Instead we have to create a new
1293 // code object.
Steve Block44f0eee2011-05-26 01:26:41 +01001294 Handle<Code> result(FACTORY->CopyCode(code, buffer));
Steve Block6ded16b2010-05-10 14:33:55 +01001295 return result;
1296 }
1297}
1298
1299
John Reck59135872010-11-02 12:39:01 -07001300MaybeObject* LiveEdit::PatchFunctionPositions(
Steve Block6ded16b2010-05-10 14:33:55 +01001301 Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array) {
1302
1303 if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
Steve Block44f0eee2011-05-26 01:26:41 +01001304 return Isolate::Current()->ThrowIllegalOperation();
Steve Block6ded16b2010-05-10 14:33:55 +01001305 }
1306
1307 SharedInfoWrapper shared_info_wrapper(shared_info_array);
1308 Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo();
1309
1310 int old_function_start = info->start_position();
1311 int new_function_start = TranslatePosition(old_function_start,
1312 position_change_array);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001313 int new_function_end = TranslatePosition(info->end_position(),
1314 position_change_array);
1315 int new_function_token_pos =
1316 TranslatePosition(info->function_token_position(), position_change_array);
Steve Block6ded16b2010-05-10 14:33:55 +01001317
Ben Murdoch8b112d22011-06-08 16:22:53 +01001318 info->set_start_position(new_function_start);
1319 info->set_end_position(new_function_end);
1320 info->set_function_token_position(new_function_token_pos);
Steve Block6ded16b2010-05-10 14:33:55 +01001321
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001322 HEAP->EnsureHeapIsIterable();
1323
Steve Block6ded16b2010-05-10 14:33:55 +01001324 if (IsJSFunctionCode(info->code())) {
1325 // Patch relocation info section of the code.
1326 Handle<Code> patched_code = PatchPositionsInCode(Handle<Code>(info->code()),
1327 position_change_array);
1328 if (*patched_code != info->code()) {
1329 // Replace all references to the code across the heap. In particular,
1330 // some stubs may refer to this code and this code may be being executed
1331 // on stack (it is safe to substitute the code object on stack, because
1332 // we only change the structure of rinfo and leave instructions
1333 // untouched).
1334 ReplaceCodeObject(info->code(), *patched_code);
1335 }
1336 }
1337
Steve Block44f0eee2011-05-26 01:26:41 +01001338 return HEAP->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001339}
1340
1341
1342static Handle<Script> CreateScriptCopy(Handle<Script> original) {
1343 Handle<String> original_source(String::cast(original->source()));
1344
Steve Block44f0eee2011-05-26 01:26:41 +01001345 Handle<Script> copy = FACTORY->NewScript(original_source);
Steve Block6ded16b2010-05-10 14:33:55 +01001346
1347 copy->set_name(original->name());
1348 copy->set_line_offset(original->line_offset());
1349 copy->set_column_offset(original->column_offset());
1350 copy->set_data(original->data());
1351 copy->set_type(original->type());
1352 copy->set_context_data(original->context_data());
1353 copy->set_compilation_type(original->compilation_type());
1354 copy->set_eval_from_shared(original->eval_from_shared());
1355 copy->set_eval_from_instructions_offset(
1356 original->eval_from_instructions_offset());
1357
1358 return copy;
1359}
1360
1361
1362Object* LiveEdit::ChangeScriptSource(Handle<Script> original_script,
1363 Handle<String> new_source,
1364 Handle<Object> old_script_name) {
1365 Handle<Object> old_script_object;
1366 if (old_script_name->IsString()) {
1367 Handle<Script> old_script = CreateScriptCopy(original_script);
1368 old_script->set_name(String::cast(*old_script_name));
1369 old_script_object = old_script;
Steve Block44f0eee2011-05-26 01:26:41 +01001370 Isolate::Current()->debugger()->OnAfterCompile(
1371 old_script, Debugger::SEND_WHEN_DEBUGGING);
Steve Block6ded16b2010-05-10 14:33:55 +01001372 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001373 old_script_object = Handle<Object>(HEAP->null_value());
Steve Block6ded16b2010-05-10 14:33:55 +01001374 }
1375
1376 original_script->set_source(*new_source);
1377
1378 // Drop line ends so that they will be recalculated.
Steve Block44f0eee2011-05-26 01:26:41 +01001379 original_script->set_line_ends(HEAP->undefined_value());
Steve Block6ded16b2010-05-10 14:33:55 +01001380
1381 return *old_script_object;
1382}
1383
1384
1385
1386void LiveEdit::ReplaceRefToNestedFunction(
1387 Handle<JSValue> parent_function_wrapper,
1388 Handle<JSValue> orig_function_wrapper,
1389 Handle<JSValue> subst_function_wrapper) {
1390
1391 Handle<SharedFunctionInfo> parent_shared =
1392 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(parent_function_wrapper));
1393 Handle<SharedFunctionInfo> orig_shared =
1394 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(orig_function_wrapper));
1395 Handle<SharedFunctionInfo> subst_shared =
1396 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(subst_function_wrapper));
1397
1398 for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) {
1399 if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) {
1400 if (it.rinfo()->target_object() == *orig_shared) {
1401 it.rinfo()->set_target_object(*subst_shared);
1402 }
1403 }
1404 }
1405}
1406
1407
1408// Check an activation against list of functions. If there is a function
1409// that matches, its status in result array is changed to status argument value.
1410static bool CheckActivation(Handle<JSArray> shared_info_array,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001411 Handle<JSArray> result,
1412 StackFrame* frame,
Steve Block6ded16b2010-05-10 14:33:55 +01001413 LiveEdit::FunctionPatchabilityStatus status) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001414 if (!frame->is_java_script()) return false;
1415
1416 Handle<JSFunction> function(
1417 JSFunction::cast(JavaScriptFrame::cast(frame)->function()));
1418
Steve Block6ded16b2010-05-10 14:33:55 +01001419 int len = Smi::cast(shared_info_array->length())->value();
1420 for (int i = 0; i < len; i++) {
John Reck59135872010-11-02 12:39:01 -07001421 JSValue* wrapper =
1422 JSValue::cast(shared_info_array->GetElementNoExceptionThrown(i));
Steve Block6ded16b2010-05-10 14:33:55 +01001423 Handle<SharedFunctionInfo> shared(
1424 SharedFunctionInfo::cast(wrapper->value()));
1425
Ben Murdochb0fe1622011-05-05 13:52:32 +01001426 if (function->shared() == *shared || IsInlined(*function, *shared)) {
Steve Block44f0eee2011-05-26 01:26:41 +01001427 SetElementNonStrict(result, i, Handle<Smi>(Smi::FromInt(status)));
Steve Block6ded16b2010-05-10 14:33:55 +01001428 return true;
1429 }
1430 }
1431 return false;
1432}
1433
1434
1435// Iterates over handler chain and removes all elements that are inside
1436// frames being dropped.
1437static bool FixTryCatchHandler(StackFrame* top_frame,
1438 StackFrame* bottom_frame) {
1439 Address* pointer_address =
Steve Block44f0eee2011-05-26 01:26:41 +01001440 &Memory::Address_at(Isolate::Current()->get_address_from_id(
Ben Murdoch589d6972011-11-30 16:04:58 +00001441 Isolate::kHandlerAddress));
Steve Block6ded16b2010-05-10 14:33:55 +01001442
1443 while (*pointer_address < top_frame->sp()) {
1444 pointer_address = &Memory::Address_at(*pointer_address);
1445 }
1446 Address* above_frame_address = pointer_address;
1447 while (*pointer_address < bottom_frame->fp()) {
1448 pointer_address = &Memory::Address_at(*pointer_address);
1449 }
1450 bool change = *above_frame_address != *pointer_address;
1451 *above_frame_address = *pointer_address;
1452 return change;
1453}
1454
1455
1456// Removes specified range of frames from stack. There may be 1 or more
1457// frames in range. Anyway the bottom frame is restarted rather than dropped,
1458// and therefore has to be a JavaScript frame.
1459// Returns error message or NULL.
1460static const char* DropFrames(Vector<StackFrame*> frames,
1461 int top_frame_index,
Steve Block8defd9f2010-07-08 12:39:36 +01001462 int bottom_js_frame_index,
Ben Murdochbb769b22010-08-11 14:56:33 +01001463 Debug::FrameDropMode* mode,
1464 Object*** restarter_frame_function_pointer) {
Iain Merrick75681382010-08-19 15:07:18 +01001465 if (!Debug::kFrameDropperSupported) {
Steve Block8defd9f2010-07-08 12:39:36 +01001466 return "Stack manipulations are not supported in this architecture.";
1467 }
1468
Steve Block6ded16b2010-05-10 14:33:55 +01001469 StackFrame* pre_top_frame = frames[top_frame_index - 1];
1470 StackFrame* top_frame = frames[top_frame_index];
1471 StackFrame* bottom_js_frame = frames[bottom_js_frame_index];
1472
1473 ASSERT(bottom_js_frame->is_java_script());
1474
1475 // Check the nature of the top frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001476 Isolate* isolate = Isolate::Current();
1477 Code* pre_top_frame_code = pre_top_frame->LookupCode();
Steve Block44f0eee2011-05-26 01:26:41 +01001478 if (pre_top_frame_code->is_inline_cache_stub() &&
1479 pre_top_frame_code->ic_state() == DEBUG_BREAK) {
Steve Block6ded16b2010-05-10 14:33:55 +01001480 // OK, we can drop inline cache calls.
Steve Block8defd9f2010-07-08 12:39:36 +01001481 *mode = Debug::FRAME_DROPPED_IN_IC_CALL;
Steve Block44f0eee2011-05-26 01:26:41 +01001482 } else if (pre_top_frame_code ==
Ben Murdoch8b112d22011-06-08 16:22:53 +01001483 isolate->debug()->debug_break_slot()) {
Steve Block8defd9f2010-07-08 12:39:36 +01001484 // OK, we can drop debug break slot.
1485 *mode = Debug::FRAME_DROPPED_IN_DEBUG_SLOT_CALL;
Steve Block44f0eee2011-05-26 01:26:41 +01001486 } else if (pre_top_frame_code ==
Ben Murdoch8b112d22011-06-08 16:22:53 +01001487 isolate->builtins()->builtin(
Steve Block44f0eee2011-05-26 01:26:41 +01001488 Builtins::kFrameDropper_LiveEdit)) {
Steve Block6ded16b2010-05-10 14:33:55 +01001489 // OK, we can drop our own code.
Steve Block8defd9f2010-07-08 12:39:36 +01001490 *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
Ben Murdoch257744e2011-11-30 15:57:28 +00001491 } else if (pre_top_frame_code ==
1492 isolate->builtins()->builtin(Builtins::kReturn_DebugBreak)) {
1493 *mode = Debug::FRAME_DROPPED_IN_RETURN_CALL;
Steve Block44f0eee2011-05-26 01:26:41 +01001494 } else if (pre_top_frame_code->kind() == Code::STUB &&
1495 pre_top_frame_code->major_key()) {
Steve Block8defd9f2010-07-08 12:39:36 +01001496 // Entry from our unit tests, it's fine, we support this case.
1497 *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
Steve Block6ded16b2010-05-10 14:33:55 +01001498 } else {
1499 return "Unknown structure of stack above changing function";
1500 }
1501
1502 Address unused_stack_top = top_frame->sp();
1503 Address unused_stack_bottom = bottom_js_frame->fp()
1504 - Debug::kFrameDropperFrameSize * kPointerSize // Size of the new frame.
1505 + kPointerSize; // Bigger address end is exclusive.
1506
1507 if (unused_stack_top > unused_stack_bottom) {
1508 return "Not enough space for frame dropper frame";
1509 }
1510
1511 // Committing now. After this point we should return only NULL value.
1512
1513 FixTryCatchHandler(pre_top_frame, bottom_js_frame);
1514 // Make sure FixTryCatchHandler is idempotent.
1515 ASSERT(!FixTryCatchHandler(pre_top_frame, bottom_js_frame));
1516
Steve Block44f0eee2011-05-26 01:26:41 +01001517 Handle<Code> code = Isolate::Current()->builtins()->FrameDropper_LiveEdit();
Steve Block6ded16b2010-05-10 14:33:55 +01001518 top_frame->set_pc(code->entry());
1519 pre_top_frame->SetCallerFp(bottom_js_frame->fp());
1520
Ben Murdochbb769b22010-08-11 14:56:33 +01001521 *restarter_frame_function_pointer =
1522 Debug::SetUpFrameDropperFrame(bottom_js_frame, code);
1523
1524 ASSERT((**restarter_frame_function_pointer)->IsJSFunction());
Steve Block6ded16b2010-05-10 14:33:55 +01001525
1526 for (Address a = unused_stack_top;
1527 a < unused_stack_bottom;
1528 a += kPointerSize) {
1529 Memory::Object_at(a) = Smi::FromInt(0);
1530 }
1531
1532 return NULL;
1533}
1534
1535
1536static bool IsDropableFrame(StackFrame* frame) {
1537 return !frame->is_exit();
1538}
1539
1540// Fills result array with statuses of functions. Modifies the stack
1541// removing all listed function if possible and if do_drop is true.
1542static const char* DropActivationsInActiveThread(
1543 Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001544 Isolate* isolate = Isolate::Current();
1545 Debug* debug = isolate->debug();
1546 ZoneScope scope(isolate, DELETE_ON_EXIT);
Steve Block6ded16b2010-05-10 14:33:55 +01001547 Vector<StackFrame*> frames = CreateStackMap();
1548
1549 int array_len = Smi::cast(shared_info_array->length())->value();
1550
1551 int top_frame_index = -1;
1552 int frame_index = 0;
1553 for (; frame_index < frames.length(); frame_index++) {
1554 StackFrame* frame = frames[frame_index];
Steve Block44f0eee2011-05-26 01:26:41 +01001555 if (frame->id() == debug->break_frame_id()) {
Steve Block6ded16b2010-05-10 14:33:55 +01001556 top_frame_index = frame_index;
1557 break;
1558 }
1559 if (CheckActivation(shared_info_array, result, frame,
1560 LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
1561 // We are still above break_frame. It is not a target frame,
1562 // it is a problem.
1563 return "Debugger mark-up on stack is not found";
1564 }
1565 }
1566
1567 if (top_frame_index == -1) {
1568 // We haven't found break frame, but no function is blocking us anyway.
1569 return NULL;
1570 }
1571
1572 bool target_frame_found = false;
1573 int bottom_js_frame_index = top_frame_index;
1574 bool c_code_found = false;
1575
1576 for (; frame_index < frames.length(); frame_index++) {
1577 StackFrame* frame = frames[frame_index];
1578 if (!IsDropableFrame(frame)) {
1579 c_code_found = true;
1580 break;
1581 }
1582 if (CheckActivation(shared_info_array, result, frame,
1583 LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
1584 target_frame_found = true;
1585 bottom_js_frame_index = frame_index;
1586 }
1587 }
1588
1589 if (c_code_found) {
1590 // There is a C frames on stack. Check that there are no target frames
1591 // below them.
1592 for (; frame_index < frames.length(); frame_index++) {
1593 StackFrame* frame = frames[frame_index];
1594 if (frame->is_java_script()) {
1595 if (CheckActivation(shared_info_array, result, frame,
1596 LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
1597 // Cannot drop frame under C frames.
1598 return NULL;
1599 }
1600 }
1601 }
1602 }
1603
1604 if (!do_drop) {
1605 // We are in check-only mode.
1606 return NULL;
1607 }
1608
1609 if (!target_frame_found) {
1610 // Nothing to drop.
1611 return NULL;
1612 }
1613
Steve Block8defd9f2010-07-08 12:39:36 +01001614 Debug::FrameDropMode drop_mode = Debug::FRAMES_UNTOUCHED;
Ben Murdochbb769b22010-08-11 14:56:33 +01001615 Object** restarter_frame_function_pointer = NULL;
Steve Block6ded16b2010-05-10 14:33:55 +01001616 const char* error_message = DropFrames(frames, top_frame_index,
Ben Murdochbb769b22010-08-11 14:56:33 +01001617 bottom_js_frame_index, &drop_mode,
1618 &restarter_frame_function_pointer);
Steve Block6ded16b2010-05-10 14:33:55 +01001619
1620 if (error_message != NULL) {
1621 return error_message;
1622 }
1623
1624 // Adjust break_frame after some frames has been dropped.
1625 StackFrame::Id new_id = StackFrame::NO_ID;
1626 for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) {
1627 if (frames[i]->type() == StackFrame::JAVA_SCRIPT) {
1628 new_id = frames[i]->id();
1629 break;
1630 }
1631 }
Steve Block44f0eee2011-05-26 01:26:41 +01001632 debug->FramesHaveBeenDropped(new_id, drop_mode,
Ben Murdochbb769b22010-08-11 14:56:33 +01001633 restarter_frame_function_pointer);
Steve Block6ded16b2010-05-10 14:33:55 +01001634
1635 // Replace "blocked on active" with "replaced on active" status.
1636 for (int i = 0; i < array_len; i++) {
1637 if (result->GetElement(i) ==
1638 Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001639 Handle<Object> replaced(
1640 Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK));
Steve Block44f0eee2011-05-26 01:26:41 +01001641 SetElementNonStrict(result, i, replaced);
Steve Block6ded16b2010-05-10 14:33:55 +01001642 }
1643 }
1644 return NULL;
1645}
1646
1647
1648class InactiveThreadActivationsChecker : public ThreadVisitor {
1649 public:
1650 InactiveThreadActivationsChecker(Handle<JSArray> shared_info_array,
1651 Handle<JSArray> result)
1652 : shared_info_array_(shared_info_array), result_(result),
1653 has_blocked_functions_(false) {
1654 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01001655 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1656 for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
Steve Block6ded16b2010-05-10 14:33:55 +01001657 has_blocked_functions_ |= CheckActivation(
1658 shared_info_array_, result_, it.frame(),
1659 LiveEdit::FUNCTION_BLOCKED_ON_OTHER_STACK);
1660 }
1661 }
1662 bool HasBlockedFunctions() {
1663 return has_blocked_functions_;
1664 }
1665
1666 private:
1667 Handle<JSArray> shared_info_array_;
1668 Handle<JSArray> result_;
1669 bool has_blocked_functions_;
1670};
1671
1672
1673Handle<JSArray> LiveEdit::CheckAndDropActivations(
1674 Handle<JSArray> shared_info_array, bool do_drop) {
1675 int len = Smi::cast(shared_info_array->length())->value();
1676
Steve Block44f0eee2011-05-26 01:26:41 +01001677 Handle<JSArray> result = FACTORY->NewJSArray(len);
Steve Block6ded16b2010-05-10 14:33:55 +01001678
1679 // Fill the default values.
1680 for (int i = 0; i < len; i++) {
Steve Block44f0eee2011-05-26 01:26:41 +01001681 SetElementNonStrict(
1682 result,
1683 i,
1684 Handle<Smi>(Smi::FromInt(FUNCTION_AVAILABLE_FOR_PATCH)));
Steve Block6ded16b2010-05-10 14:33:55 +01001685 }
1686
1687
1688 // First check inactive threads. Fail if some functions are blocked there.
1689 InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array,
1690 result);
Steve Block44f0eee2011-05-26 01:26:41 +01001691 Isolate::Current()->thread_manager()->IterateArchivedThreads(
1692 &inactive_threads_checker);
Steve Block6ded16b2010-05-10 14:33:55 +01001693 if (inactive_threads_checker.HasBlockedFunctions()) {
1694 return result;
1695 }
1696
1697 // Try to drop activations from the current stack.
1698 const char* error_message =
1699 DropActivationsInActiveThread(shared_info_array, result, do_drop);
1700 if (error_message != NULL) {
1701 // Add error message as an array extra element.
1702 Vector<const char> vector_message(error_message, StrLength(error_message));
Steve Block44f0eee2011-05-26 01:26:41 +01001703 Handle<String> str = FACTORY->NewStringFromAscii(vector_message);
1704 SetElementNonStrict(result, len, str);
Steve Block6ded16b2010-05-10 14:33:55 +01001705 }
1706 return result;
1707}
1708
1709
Steve Block44f0eee2011-05-26 01:26:41 +01001710LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
1711 FunctionLiteral* fun)
1712 : isolate_(isolate) {
1713 if (isolate_->active_function_info_listener() != NULL) {
1714 isolate_->active_function_info_listener()->FunctionStarted(fun);
Andrei Popescu402d9372010-02-26 13:31:12 +00001715 }
1716}
Steve Block6ded16b2010-05-10 14:33:55 +01001717
1718
Andrei Popescu402d9372010-02-26 13:31:12 +00001719LiveEditFunctionTracker::~LiveEditFunctionTracker() {
Steve Block44f0eee2011-05-26 01:26:41 +01001720 if (isolate_->active_function_info_listener() != NULL) {
1721 isolate_->active_function_info_listener()->FunctionDone();
Andrei Popescu402d9372010-02-26 13:31:12 +00001722 }
1723}
Steve Block6ded16b2010-05-10 14:33:55 +01001724
1725
1726void LiveEditFunctionTracker::RecordFunctionInfo(
1727 Handle<SharedFunctionInfo> info, FunctionLiteral* lit) {
Steve Block44f0eee2011-05-26 01:26:41 +01001728 if (isolate_->active_function_info_listener() != NULL) {
1729 isolate_->active_function_info_listener()->FunctionInfo(info, lit->scope());
Andrei Popescu402d9372010-02-26 13:31:12 +00001730 }
1731}
Steve Block6ded16b2010-05-10 14:33:55 +01001732
1733
1734void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
Steve Block44f0eee2011-05-26 01:26:41 +01001735 isolate_->active_function_info_listener()->FunctionCode(code);
Andrei Popescu402d9372010-02-26 13:31:12 +00001736}
Steve Block6ded16b2010-05-10 14:33:55 +01001737
1738
Steve Block44f0eee2011-05-26 01:26:41 +01001739bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
1740 return isolate->active_function_info_listener() != NULL;
Andrei Popescu402d9372010-02-26 13:31:12 +00001741}
1742
Steve Block6ded16b2010-05-10 14:33:55 +01001743
1744#else // ENABLE_DEBUGGER_SUPPORT
1745
1746// This ifdef-else-endif section provides working or stub implementation of
1747// LiveEditFunctionTracker.
Steve Block44f0eee2011-05-26 01:26:41 +01001748LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
1749 FunctionLiteral* fun) {
Steve Block6ded16b2010-05-10 14:33:55 +01001750}
1751
1752
1753LiveEditFunctionTracker::~LiveEditFunctionTracker() {
1754}
1755
1756
1757void LiveEditFunctionTracker::RecordFunctionInfo(
1758 Handle<SharedFunctionInfo> info, FunctionLiteral* lit) {
1759}
1760
1761
1762void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
1763}
1764
1765
Ben Murdoch257744e2011-11-30 15:57:28 +00001766bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
Steve Block6ded16b2010-05-10 14:33:55 +01001767 return false;
1768}
1769
1770#endif // ENABLE_DEBUGGER_SUPPORT
1771
1772
1773
Andrei Popescu402d9372010-02-26 13:31:12 +00001774} } // namespace v8::internal