blob: c4cb68e75206defad3f5b0807cd079708e3a49dc [file] [log] [blame]
Andrei Popescu402d9372010-02-26 13:31:12 +00001// Copyright 2010 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28
29#include "v8.h"
30
31#include "liveedit.h"
Ben Murdochf87a2032010-10-22 12:50:53 +010032
Andrei Popescu402d9372010-02-26 13:31:12 +000033#include "compiler.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010034#include "compilation-cache.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"
Steve Block6ded16b2010-05-10 14:33:55 +010038#include "memory.h"
Ben Murdochf87a2032010-10-22 12:50:53 +010039#include "oprofile-agent.h"
40#include "parser.h"
41#include "scopeinfo.h"
42#include "scopes.h"
Andrei Popescu402d9372010-02-26 13:31:12 +000043
44namespace v8 {
45namespace internal {
46
47
Steve Block6ded16b2010-05-10 14:33:55 +010048#ifdef ENABLE_DEBUGGER_SUPPORT
49
50
51// A simple implementation of dynamic programming algorithm. It solves
52// the problem of finding the difference of 2 arrays. It uses a table of results
53// of subproblems. Each cell contains a number together with 2-bit flag
54// that helps building the chunk list.
55class Differencer {
Andrei Popescu402d9372010-02-26 13:31:12 +000056 public:
Steve Block6ded16b2010-05-10 14:33:55 +010057 explicit Differencer(Comparator::Input* input)
58 : input_(input), len1_(input->getLength1()), len2_(input->getLength2()) {
59 buffer_ = NewArray<int>(len1_ * len2_);
60 }
61 ~Differencer() {
62 DeleteArray(buffer_);
Andrei Popescu402d9372010-02-26 13:31:12 +000063 }
64
Steve Block6ded16b2010-05-10 14:33:55 +010065 void Initialize() {
66 int array_size = len1_ * len2_;
67 for (int i = 0; i < array_size; i++) {
68 buffer_[i] = kEmptyCellValue;
69 }
Andrei Popescu402d9372010-02-26 13:31:12 +000070 }
71
Steve Block6ded16b2010-05-10 14:33:55 +010072 // Makes sure that result for the full problem is calculated and stored
73 // in the table together with flags showing a path through subproblems.
74 void FillTable() {
75 CompareUpToTail(0, 0);
Andrei Popescu402d9372010-02-26 13:31:12 +000076 }
77
Steve Block6ded16b2010-05-10 14:33:55 +010078 void SaveResult(Comparator::Output* chunk_writer) {
79 ResultWriter writer(chunk_writer);
80
81 int pos1 = 0;
82 int pos2 = 0;
83 while (true) {
84 if (pos1 < len1_) {
85 if (pos2 < len2_) {
86 Direction dir = get_direction(pos1, pos2);
87 switch (dir) {
88 case EQ:
89 writer.eq();
90 pos1++;
91 pos2++;
92 break;
93 case SKIP1:
94 writer.skip1(1);
95 pos1++;
96 break;
97 case SKIP2:
98 case SKIP_ANY:
99 writer.skip2(1);
100 pos2++;
101 break;
102 default:
103 UNREACHABLE();
104 }
105 } else {
106 writer.skip1(len1_ - pos1);
107 break;
108 }
109 } else {
110 if (len2_ != pos2) {
111 writer.skip2(len2_ - pos2);
112 }
113 break;
114 }
115 }
116 writer.close();
117 }
118
119 private:
120 Comparator::Input* input_;
121 int* buffer_;
122 int len1_;
123 int len2_;
124
125 enum Direction {
126 EQ = 0,
127 SKIP1,
128 SKIP2,
129 SKIP_ANY,
130
131 MAX_DIRECTION_FLAG_VALUE = SKIP_ANY
132 };
133
134 // Computes result for a subtask and optionally caches it in the buffer table.
135 // All results values are shifted to make space for flags in the lower bits.
136 int CompareUpToTail(int pos1, int pos2) {
137 if (pos1 < len1_) {
138 if (pos2 < len2_) {
139 int cached_res = get_value4(pos1, pos2);
140 if (cached_res == kEmptyCellValue) {
141 Direction dir;
142 int res;
143 if (input_->equals(pos1, pos2)) {
144 res = CompareUpToTail(pos1 + 1, pos2 + 1);
145 dir = EQ;
146 } else {
147 int res1 = CompareUpToTail(pos1 + 1, pos2) +
148 (1 << kDirectionSizeBits);
149 int res2 = CompareUpToTail(pos1, pos2 + 1) +
150 (1 << kDirectionSizeBits);
151 if (res1 == res2) {
152 res = res1;
153 dir = SKIP_ANY;
154 } else if (res1 < res2) {
155 res = res1;
156 dir = SKIP1;
157 } else {
158 res = res2;
159 dir = SKIP2;
160 }
161 }
162 set_value4_and_dir(pos1, pos2, res, dir);
163 cached_res = res;
164 }
165 return cached_res;
166 } else {
167 return (len1_ - pos1) << kDirectionSizeBits;
168 }
169 } else {
170 return (len2_ - pos2) << kDirectionSizeBits;
171 }
172 }
173
174 inline int& get_cell(int i1, int i2) {
175 return buffer_[i1 + i2 * len1_];
176 }
177
178 // Each cell keeps a value plus direction. Value is multiplied by 4.
179 void set_value4_and_dir(int i1, int i2, int value4, Direction dir) {
180 ASSERT((value4 & kDirectionMask) == 0);
181 get_cell(i1, i2) = value4 | dir;
182 }
183
184 int get_value4(int i1, int i2) {
185 return get_cell(i1, i2) & (kMaxUInt32 ^ kDirectionMask);
186 }
187 Direction get_direction(int i1, int i2) {
188 return static_cast<Direction>(get_cell(i1, i2) & kDirectionMask);
189 }
190
191 static const int kDirectionSizeBits = 2;
192 static const int kDirectionMask = (1 << kDirectionSizeBits) - 1;
193 static const int kEmptyCellValue = -1 << kDirectionSizeBits;
194
195 // This method only holds static assert statement (unfortunately you cannot
196 // place one in class scope).
197 void StaticAssertHolder() {
198 STATIC_ASSERT(MAX_DIRECTION_FLAG_VALUE < (1 << kDirectionSizeBits));
199 }
200
201 class ResultWriter {
202 public:
203 explicit ResultWriter(Comparator::Output* chunk_writer)
204 : chunk_writer_(chunk_writer), pos1_(0), pos2_(0),
205 pos1_begin_(-1), pos2_begin_(-1), has_open_chunk_(false) {
206 }
207 void eq() {
208 FlushChunk();
209 pos1_++;
210 pos2_++;
211 }
212 void skip1(int len1) {
213 StartChunk();
214 pos1_ += len1;
215 }
216 void skip2(int len2) {
217 StartChunk();
218 pos2_ += len2;
219 }
220 void close() {
221 FlushChunk();
222 }
223
224 private:
225 Comparator::Output* chunk_writer_;
226 int pos1_;
227 int pos2_;
228 int pos1_begin_;
229 int pos2_begin_;
230 bool has_open_chunk_;
231
232 void StartChunk() {
233 if (!has_open_chunk_) {
234 pos1_begin_ = pos1_;
235 pos2_begin_ = pos2_;
236 has_open_chunk_ = true;
237 }
238 }
239
240 void FlushChunk() {
241 if (has_open_chunk_) {
242 chunk_writer_->AddChunk(pos1_begin_, pos2_begin_,
243 pos1_ - pos1_begin_, pos2_ - pos2_begin_);
244 has_open_chunk_ = false;
245 }
246 }
247 };
248};
249
250
251void Comparator::CalculateDifference(Comparator::Input* input,
252 Comparator::Output* result_writer) {
253 Differencer differencer(input);
254 differencer.Initialize();
255 differencer.FillTable();
256 differencer.SaveResult(result_writer);
257}
258
259
260static bool CompareSubstrings(Handle<String> s1, int pos1,
261 Handle<String> s2, int pos2, int len) {
262 static StringInputBuffer buf1;
263 static StringInputBuffer buf2;
264 buf1.Reset(*s1);
265 buf1.Seek(pos1);
266 buf2.Reset(*s2);
267 buf2.Seek(pos2);
268 for (int i = 0; i < len; i++) {
269 ASSERT(buf1.has_more() && buf2.has_more());
270 if (buf1.GetNext() != buf2.GetNext()) {
271 return false;
272 }
273 }
274 return true;
275}
276
277
278// Wraps raw n-elements line_ends array as a list of n+1 lines. The last line
279// never has terminating new line character.
280class LineEndsWrapper {
281 public:
282 explicit LineEndsWrapper(Handle<String> string)
283 : ends_array_(CalculateLineEnds(string, false)),
284 string_len_(string->length()) {
285 }
286 int length() {
287 return ends_array_->length() + 1;
288 }
289 // Returns start for any line including start of the imaginary line after
290 // the last line.
291 int GetLineStart(int index) {
292 if (index == 0) {
293 return 0;
294 } else {
295 return GetLineEnd(index - 1);
296 }
297 }
298 int GetLineEnd(int index) {
299 if (index == ends_array_->length()) {
300 // End of the last line is always an end of the whole string.
301 // If the string ends with a new line character, the last line is an
302 // empty string after this character.
303 return string_len_;
304 } else {
305 return GetPosAfterNewLine(index);
306 }
307 }
308
309 private:
310 Handle<FixedArray> ends_array_;
311 int string_len_;
312
313 int GetPosAfterNewLine(int index) {
314 return Smi::cast(ends_array_->get(index))->value() + 1;
Andrei Popescu402d9372010-02-26 13:31:12 +0000315 }
316};
317
Steve Block6ded16b2010-05-10 14:33:55 +0100318
319// Represents 2 strings as 2 arrays of lines.
320class LineArrayCompareInput : public Comparator::Input {
321 public:
322 LineArrayCompareInput(Handle<String> s1, Handle<String> s2,
323 LineEndsWrapper line_ends1, LineEndsWrapper line_ends2)
324 : s1_(s1), s2_(s2), line_ends1_(line_ends1), line_ends2_(line_ends2) {
325 }
326 int getLength1() {
327 return line_ends1_.length();
328 }
329 int getLength2() {
330 return line_ends2_.length();
331 }
332 bool equals(int index1, int index2) {
333 int line_start1 = line_ends1_.GetLineStart(index1);
334 int line_start2 = line_ends2_.GetLineStart(index2);
335 int line_end1 = line_ends1_.GetLineEnd(index1);
336 int line_end2 = line_ends2_.GetLineEnd(index2);
337 int len1 = line_end1 - line_start1;
338 int len2 = line_end2 - line_start2;
339 if (len1 != len2) {
340 return false;
341 }
342 return CompareSubstrings(s1_, line_start1, s2_, line_start2, len1);
343 }
344
345 private:
346 Handle<String> s1_;
347 Handle<String> s2_;
348 LineEndsWrapper line_ends1_;
349 LineEndsWrapper line_ends2_;
350};
351
352
353// Stores compare result in JSArray. Each chunk is stored as 3 array elements:
354// (pos1_begin, pos1_end, pos2_end).
355class LineArrayCompareOutput : public Comparator::Output {
356 public:
357 LineArrayCompareOutput(LineEndsWrapper line_ends1, LineEndsWrapper line_ends2)
358 : array_(Factory::NewJSArray(10)), current_size_(0),
359 line_ends1_(line_ends1), line_ends2_(line_ends2) {
360 }
361
362 void AddChunk(int line_pos1, int line_pos2, int line_len1, int line_len2) {
363 int char_pos1 = line_ends1_.GetLineStart(line_pos1);
364 int char_pos2 = line_ends2_.GetLineStart(line_pos2);
365 int char_len1 = line_ends1_.GetLineStart(line_pos1 + line_len1) - char_pos1;
366 int char_len2 = line_ends2_.GetLineStart(line_pos2 + line_len2) - char_pos2;
367
368 SetElement(array_, current_size_, Handle<Object>(Smi::FromInt(char_pos1)));
369 SetElement(array_, current_size_ + 1,
370 Handle<Object>(Smi::FromInt(char_pos1 + char_len1)));
371 SetElement(array_, current_size_ + 2,
372 Handle<Object>(Smi::FromInt(char_pos2 + char_len2)));
373 current_size_ += 3;
374 }
375
376 Handle<JSArray> GetResult() {
377 return array_;
378 }
379
380 private:
381 Handle<JSArray> array_;
382 int current_size_;
383 LineEndsWrapper line_ends1_;
384 LineEndsWrapper line_ends2_;
385};
386
387
388Handle<JSArray> LiveEdit::CompareStringsLinewise(Handle<String> s1,
389 Handle<String> s2) {
390 LineEndsWrapper line_ends1(s1);
391 LineEndsWrapper line_ends2(s2);
392
393 LineArrayCompareInput input(s1, s2, line_ends1, line_ends2);
394 LineArrayCompareOutput output(line_ends1, line_ends2);
395
396 Comparator::CalculateDifference(&input, &output);
397
398 return output.GetResult();
399}
400
401
402static void CompileScriptForTracker(Handle<Script> script) {
Steve Block6ded16b2010-05-10 14:33:55 +0100403 // TODO(635): support extensions.
Steve Block6ded16b2010-05-10 14:33:55 +0100404 PostponeInterruptsScope postpone;
405
Steve Block6ded16b2010-05-10 14:33:55 +0100406 // Build AST.
Ben Murdochf87a2032010-10-22 12:50:53 +0100407 CompilationInfo info(script);
408 info.MarkAsGlobal();
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800409 if (ParserApi::Parse(&info)) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100410 // Compile the code.
411 LiveEditFunctionTracker tracker(info.function());
412 if (Compiler::MakeCodeForLiveEdit(&info)) {
413 ASSERT(!info.code().is_null());
414 tracker.RecordRootFunctionInfo(info.code());
415 } else {
416 Top::StackOverflow();
417 }
Steve Block6ded16b2010-05-10 14:33:55 +0100418 }
Steve Block6ded16b2010-05-10 14:33:55 +0100419}
420
Ben Murdochf87a2032010-10-22 12:50:53 +0100421
Steve Block6ded16b2010-05-10 14:33:55 +0100422// Unwraps JSValue object, returning its field "value"
423static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) {
424 return Handle<Object>(jsValue->value());
425}
426
Ben Murdochf87a2032010-10-22 12:50:53 +0100427
Steve Block6ded16b2010-05-10 14:33:55 +0100428// Wraps any object into a OpaqueReference, that will hide the object
429// from JavaScript.
430static Handle<JSValue> WrapInJSValue(Object* object) {
431 Handle<JSFunction> constructor = Top::opaque_reference_function();
432 Handle<JSValue> result =
433 Handle<JSValue>::cast(Factory::NewJSObject(constructor));
434 result->set_value(object);
435 return result;
436}
437
Ben Murdochf87a2032010-10-22 12:50:53 +0100438
Steve Block6ded16b2010-05-10 14:33:55 +0100439// Simple helper class that creates more or less typed structures over
440// JSArray object. This is an adhoc method of passing structures from C++
441// to JavaScript.
442template<typename S>
443class JSArrayBasedStruct {
444 public:
445 static S Create() {
446 Handle<JSArray> array = Factory::NewJSArray(S::kSize_);
447 return S(array);
448 }
449 static S cast(Object* object) {
450 JSArray* array = JSArray::cast(object);
451 Handle<JSArray> array_handle(array);
452 return S(array_handle);
453 }
454 explicit JSArrayBasedStruct(Handle<JSArray> array) : array_(array) {
455 }
456 Handle<JSArray> GetJSArray() {
457 return array_;
458 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100459
Steve Block6ded16b2010-05-10 14:33:55 +0100460 protected:
461 void SetField(int field_position, Handle<Object> value) {
462 SetElement(array_, field_position, value);
463 }
464 void SetSmiValueField(int field_position, int value) {
465 SetElement(array_, field_position, Handle<Smi>(Smi::FromInt(value)));
466 }
467 Object* GetField(int field_position) {
John Reck59135872010-11-02 12:39:01 -0700468 return array_->GetElementNoExceptionThrown(field_position);
Steve Block6ded16b2010-05-10 14:33:55 +0100469 }
470 int GetSmiValueField(int field_position) {
471 Object* res = GetField(field_position);
472 return Smi::cast(res)->value();
473 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100474
Steve Block6ded16b2010-05-10 14:33:55 +0100475 private:
476 Handle<JSArray> array_;
477};
478
479
480// Represents some function compilation details. This structure will be used
481// from JavaScript. It contains Code object, which is kept wrapped
482// into a BlindReference for sanitizing reasons.
483class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
484 public:
485 explicit FunctionInfoWrapper(Handle<JSArray> array)
486 : JSArrayBasedStruct<FunctionInfoWrapper>(array) {
487 }
488 void SetInitialProperties(Handle<String> name, int start_position,
489 int end_position, int param_num, int parent_index) {
490 HandleScope scope;
491 this->SetField(kFunctionNameOffset_, name);
492 this->SetSmiValueField(kStartPositionOffset_, start_position);
493 this->SetSmiValueField(kEndPositionOffset_, end_position);
494 this->SetSmiValueField(kParamNumOffset_, param_num);
495 this->SetSmiValueField(kParentIndexOffset_, parent_index);
496 }
Iain Merrick75681382010-08-19 15:07:18 +0100497 void SetFunctionCode(Handle<Code> function_code,
498 Handle<Object> code_scope_info) {
499 Handle<JSValue> code_wrapper = WrapInJSValue(*function_code);
500 this->SetField(kCodeOffset_, code_wrapper);
501
502 Handle<JSValue> scope_wrapper = WrapInJSValue(*code_scope_info);
503 this->SetField(kCodeScopeInfoOffset_, scope_wrapper);
Steve Block6ded16b2010-05-10 14:33:55 +0100504 }
Iain Merrick75681382010-08-19 15:07:18 +0100505 void SetOuterScopeInfo(Handle<Object> scope_info_array) {
506 this->SetField(kOuterScopeInfoOffset_, scope_info_array);
Steve Block6ded16b2010-05-10 14:33:55 +0100507 }
508 void SetSharedFunctionInfo(Handle<SharedFunctionInfo> info) {
509 Handle<JSValue> info_holder = WrapInJSValue(*info);
510 this->SetField(kSharedFunctionInfoOffset_, info_holder);
511 }
512 int GetParentIndex() {
513 return this->GetSmiValueField(kParentIndexOffset_);
514 }
515 Handle<Code> GetFunctionCode() {
516 Handle<Object> raw_result = UnwrapJSValue(Handle<JSValue>(
517 JSValue::cast(this->GetField(kCodeOffset_))));
518 return Handle<Code>::cast(raw_result);
519 }
Iain Merrick75681382010-08-19 15:07:18 +0100520 Handle<Object> GetCodeScopeInfo() {
521 Handle<Object> raw_result = UnwrapJSValue(Handle<JSValue>(
522 JSValue::cast(this->GetField(kCodeScopeInfoOffset_))));
523 return raw_result;
524 }
Steve Block6ded16b2010-05-10 14:33:55 +0100525 int GetStartPosition() {
526 return this->GetSmiValueField(kStartPositionOffset_);
527 }
528 int GetEndPosition() {
529 return this->GetSmiValueField(kEndPositionOffset_);
530 }
531
532 private:
533 static const int kFunctionNameOffset_ = 0;
534 static const int kStartPositionOffset_ = 1;
535 static const int kEndPositionOffset_ = 2;
536 static const int kParamNumOffset_ = 3;
537 static const int kCodeOffset_ = 4;
Iain Merrick75681382010-08-19 15:07:18 +0100538 static const int kCodeScopeInfoOffset_ = 5;
539 static const int kOuterScopeInfoOffset_ = 6;
540 static const int kParentIndexOffset_ = 7;
541 static const int kSharedFunctionInfoOffset_ = 8;
542 static const int kSize_ = 9;
Steve Block6ded16b2010-05-10 14:33:55 +0100543
544 friend class JSArrayBasedStruct<FunctionInfoWrapper>;
545};
546
Ben Murdochf87a2032010-10-22 12:50:53 +0100547
Steve Block6ded16b2010-05-10 14:33:55 +0100548// Wraps SharedFunctionInfo along with some of its fields for passing it
549// back to JavaScript. SharedFunctionInfo object itself is additionally
550// wrapped into BlindReference for sanitizing reasons.
551class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> {
552 public:
553 static bool IsInstance(Handle<JSArray> array) {
554 return array->length() == Smi::FromInt(kSize_) &&
John Reck59135872010-11-02 12:39:01 -0700555 array->GetElementNoExceptionThrown(kSharedInfoOffset_)->IsJSValue();
Steve Block6ded16b2010-05-10 14:33:55 +0100556 }
557
558 explicit SharedInfoWrapper(Handle<JSArray> array)
559 : JSArrayBasedStruct<SharedInfoWrapper>(array) {
560 }
561
562 void SetProperties(Handle<String> name, int start_position, int end_position,
563 Handle<SharedFunctionInfo> info) {
564 HandleScope scope;
565 this->SetField(kFunctionNameOffset_, name);
566 Handle<JSValue> info_holder = WrapInJSValue(*info);
567 this->SetField(kSharedInfoOffset_, info_holder);
568 this->SetSmiValueField(kStartPositionOffset_, start_position);
569 this->SetSmiValueField(kEndPositionOffset_, end_position);
570 }
571 Handle<SharedFunctionInfo> GetInfo() {
572 Object* element = this->GetField(kSharedInfoOffset_);
573 Handle<JSValue> value_wrapper(JSValue::cast(element));
574 Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
575 return Handle<SharedFunctionInfo>::cast(raw_result);
576 }
577
578 private:
579 static const int kFunctionNameOffset_ = 0;
580 static const int kStartPositionOffset_ = 1;
581 static const int kEndPositionOffset_ = 2;
582 static const int kSharedInfoOffset_ = 3;
583 static const int kSize_ = 4;
584
585 friend class JSArrayBasedStruct<SharedInfoWrapper>;
586};
587
Ben Murdochf87a2032010-10-22 12:50:53 +0100588
Steve Block6ded16b2010-05-10 14:33:55 +0100589class FunctionInfoListener {
590 public:
591 FunctionInfoListener() {
592 current_parent_index_ = -1;
593 len_ = 0;
594 result_ = Factory::NewJSArray(10);
595 }
596
597 void FunctionStarted(FunctionLiteral* fun) {
598 HandleScope scope;
599 FunctionInfoWrapper info = FunctionInfoWrapper::Create();
600 info.SetInitialProperties(fun->name(), fun->start_position(),
601 fun->end_position(), fun->num_parameters(),
602 current_parent_index_);
603 current_parent_index_ = len_;
604 SetElement(result_, len_, info.GetJSArray());
605 len_++;
606 }
607
608 void FunctionDone() {
609 HandleScope scope;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100610 FunctionInfoWrapper info =
611 FunctionInfoWrapper::cast(
612 result_->GetElementNoExceptionThrown(current_parent_index_));
Steve Block6ded16b2010-05-10 14:33:55 +0100613 current_parent_index_ = info.GetParentIndex();
614 }
615
Steve Block59151502010-09-22 15:07:15 +0100616 // Saves only function code, because for a script function we
617 // may never create a SharedFunctionInfo object.
618 void FunctionCode(Handle<Code> function_code) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100619 FunctionInfoWrapper info =
620 FunctionInfoWrapper::cast(
621 result_->GetElementNoExceptionThrown(current_parent_index_));
Steve Block59151502010-09-22 15:07:15 +0100622 info.SetFunctionCode(function_code, Handle<Object>(Heap::null_value()));
623 }
624
625 // Saves full information about a function: its code, its scope info
626 // and a SharedFunctionInfo object.
627 void FunctionInfo(Handle<SharedFunctionInfo> shared, Scope* scope) {
628 if (!shared->IsSharedFunctionInfo()) {
629 return;
630 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100631 FunctionInfoWrapper info =
632 FunctionInfoWrapper::cast(
633 result_->GetElementNoExceptionThrown(current_parent_index_));
Steve Block59151502010-09-22 15:07:15 +0100634 info.SetFunctionCode(Handle<Code>(shared->code()),
635 Handle<Object>(shared->scope_info()));
636 info.SetSharedFunctionInfo(shared);
637
638 Handle<Object> scope_info_list(SerializeFunctionScope(scope));
639 info.SetOuterScopeInfo(scope_info_list);
640 }
641
642 Handle<JSArray> GetResult() { return result_; }
643
Steve Block6ded16b2010-05-10 14:33:55 +0100644 private:
645 Object* SerializeFunctionScope(Scope* scope) {
646 HandleScope handle_scope;
647
648 Handle<JSArray> scope_info_list = Factory::NewJSArray(10);
649 int scope_info_length = 0;
650
651 // Saves some description of scope. It stores name and indexes of
652 // variables in the whole scope chain. Null-named slots delimit
653 // scopes of this chain.
654 Scope* outer_scope = scope->outer_scope();
655 if (outer_scope == NULL) {
656 return Heap::undefined_value();
657 }
658 do {
659 ZoneList<Variable*> list(10);
660 outer_scope->CollectUsedVariables(&list);
661 int j = 0;
662 for (int i = 0; i < list.length(); i++) {
663 Variable* var1 = list[i];
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100664 Slot* slot = var1->AsSlot();
Steve Block6ded16b2010-05-10 14:33:55 +0100665 if (slot != NULL && slot->type() == Slot::CONTEXT) {
666 if (j != i) {
667 list[j] = var1;
668 }
669 j++;
670 }
671 }
672
673 // Sort it.
674 for (int k = 1; k < j; k++) {
675 int l = k;
676 for (int m = k + 1; m < j; m++) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100677 if (list[l]->AsSlot()->index() > list[m]->AsSlot()->index()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100678 l = m;
679 }
680 }
681 list[k] = list[l];
682 }
683 for (int i = 0; i < j; i++) {
684 SetElement(scope_info_list, scope_info_length, list[i]->name());
685 scope_info_length++;
686 SetElement(scope_info_list, scope_info_length,
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100687 Handle<Smi>(Smi::FromInt(list[i]->AsSlot()->index())));
Steve Block6ded16b2010-05-10 14:33:55 +0100688 scope_info_length++;
689 }
690 SetElement(scope_info_list, scope_info_length,
691 Handle<Object>(Heap::null_value()));
692 scope_info_length++;
693
694 outer_scope = outer_scope->outer_scope();
695 } while (outer_scope != NULL);
696
697 return *scope_info_list;
698 }
699
Steve Block6ded16b2010-05-10 14:33:55 +0100700 Handle<JSArray> result_;
701 int len_;
702 int current_parent_index_;
703};
704
Ben Murdochf87a2032010-10-22 12:50:53 +0100705
Andrei Popescu402d9372010-02-26 13:31:12 +0000706static FunctionInfoListener* active_function_info_listener = NULL;
707
Steve Block6ded16b2010-05-10 14:33:55 +0100708JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script,
709 Handle<String> source) {
710 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
711
712 FunctionInfoListener listener;
713 Handle<Object> original_source = Handle<Object>(script->source());
714 script->set_source(*source);
715 active_function_info_listener = &listener;
716 CompileScriptForTracker(script);
717 active_function_info_listener = NULL;
718 script->set_source(*original_source);
719
720 return *(listener.GetResult());
721}
722
723
724void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> array) {
725 HandleScope scope;
726 int len = Smi::cast(array->length())->value();
727 for (int i = 0; i < len; i++) {
728 Handle<SharedFunctionInfo> info(
John Reck59135872010-11-02 12:39:01 -0700729 SharedFunctionInfo::cast(array->GetElementNoExceptionThrown(i)));
Steve Block6ded16b2010-05-10 14:33:55 +0100730 SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create();
731 Handle<String> name_handle(String::cast(info->name()));
732 info_wrapper.SetProperties(name_handle, info->start_position(),
733 info->end_position(), info);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100734 SetElement(array, i, info_wrapper.GetJSArray());
Steve Block6ded16b2010-05-10 14:33:55 +0100735 }
736}
737
738
739// Visitor that collects all references to a particular code object,
740// including "CODE_TARGET" references in other code objects.
741// It works in context of ZoneScope.
742class ReferenceCollectorVisitor : public ObjectVisitor {
743 public:
744 explicit ReferenceCollectorVisitor(Code* original)
Steve Block791712a2010-08-27 10:21:07 +0100745 : original_(original), rvalues_(10), reloc_infos_(10), code_entries_(10) {
Steve Block6ded16b2010-05-10 14:33:55 +0100746 }
747
748 virtual void VisitPointers(Object** start, Object** end) {
749 for (Object** p = start; p < end; p++) {
750 if (*p == original_) {
751 rvalues_.Add(p);
752 }
753 }
754 }
755
Steve Block791712a2010-08-27 10:21:07 +0100756 virtual void VisitCodeEntry(Address entry) {
757 if (Code::GetObjectFromEntryAddress(entry) == original_) {
758 code_entries_.Add(entry);
759 }
760 }
761
762 virtual void VisitCodeTarget(RelocInfo* rinfo) {
Steve Block6ded16b2010-05-10 14:33:55 +0100763 if (RelocInfo::IsCodeTarget(rinfo->rmode()) &&
764 Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) {
765 reloc_infos_.Add(*rinfo);
766 }
767 }
768
769 virtual void VisitDebugTarget(RelocInfo* rinfo) {
770 VisitCodeTarget(rinfo);
771 }
772
773 // Post-visiting method that iterates over all collected references and
774 // modifies them.
775 void Replace(Code* substitution) {
776 for (int i = 0; i < rvalues_.length(); i++) {
777 *(rvalues_[i]) = substitution;
778 }
Steve Block791712a2010-08-27 10:21:07 +0100779 Address substitution_entry = substitution->instruction_start();
Steve Block6ded16b2010-05-10 14:33:55 +0100780 for (int i = 0; i < reloc_infos_.length(); i++) {
Steve Block791712a2010-08-27 10:21:07 +0100781 reloc_infos_[i].set_target_address(substitution_entry);
782 }
783 for (int i = 0; i < code_entries_.length(); i++) {
784 Address entry = code_entries_[i];
785 Memory::Address_at(entry) = substitution_entry;
Steve Block6ded16b2010-05-10 14:33:55 +0100786 }
787 }
788
789 private:
790 Code* original_;
791 ZoneList<Object**> rvalues_;
792 ZoneList<RelocInfo> reloc_infos_;
Steve Block791712a2010-08-27 10:21:07 +0100793 ZoneList<Address> code_entries_;
Steve Block6ded16b2010-05-10 14:33:55 +0100794};
795
796
Steve Block6ded16b2010-05-10 14:33:55 +0100797// Finds all references to original and replaces them with substitution.
798static void ReplaceCodeObject(Code* original, Code* substitution) {
799 ASSERT(!Heap::InNewSpace(substitution));
800
801 AssertNoAllocation no_allocations_please;
802
803 // A zone scope for ReferenceCollectorVisitor.
804 ZoneScope scope(DELETE_ON_EXIT);
805
806 ReferenceCollectorVisitor visitor(original);
807
808 // Iterate over all roots. Stack frames may have pointer into original code,
809 // so temporary replace the pointers with offset numbers
810 // in prologue/epilogue.
811 {
Steve Block6ded16b2010-05-10 14:33:55 +0100812 Heap::IterateStrongRoots(&visitor, VISIT_ALL);
Steve Block6ded16b2010-05-10 14:33:55 +0100813 }
814
815 // Now iterate over all pointers of all objects, including code_target
816 // implicit pointers.
817 HeapIterator iterator;
818 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
819 obj->Iterate(&visitor);
820 }
821
822 visitor.Replace(substitution);
823}
824
825
826// Check whether the code is natural function code (not a lazy-compile stub
827// code).
828static bool IsJSFunctionCode(Code* code) {
829 return code->kind() == Code::FUNCTION;
830}
831
832
Ben Murdochb0fe1622011-05-05 13:52:32 +0100833// Returns true if an instance of candidate were inlined into function's code.
834static bool IsInlined(JSFunction* function, SharedFunctionInfo* candidate) {
835 AssertNoAllocation no_gc;
836
837 if (function->code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
838
839 DeoptimizationInputData* data =
840 DeoptimizationInputData::cast(function->code()->deoptimization_data());
841
842 if (data == Heap::empty_fixed_array()) return false;
843
844 FixedArray* literals = data->LiteralArray();
845
846 int inlined_count = data->InlinedFunctionCount()->value();
847 for (int i = 0; i < inlined_count; ++i) {
848 JSFunction* inlined = JSFunction::cast(literals->get(i));
849 if (inlined->shared() == candidate) return true;
850 }
851
852 return false;
853}
854
855
856class DependentFunctionsDeoptimizingVisitor : public OptimizedFunctionVisitor {
857 public:
858 explicit DependentFunctionsDeoptimizingVisitor(
859 SharedFunctionInfo* function_info)
860 : function_info_(function_info) {}
861
862 virtual void EnterContext(Context* context) {
863 }
864
865 virtual void VisitFunction(JSFunction* function) {
866 if (function->shared() == function_info_ ||
867 IsInlined(function, function_info_)) {
868 Deoptimizer::DeoptimizeFunction(function);
869 }
870 }
871
872 virtual void LeaveContext(Context* context) {
873 }
874
875 private:
876 SharedFunctionInfo* function_info_;
877};
878
879
880static void DeoptimizeDependentFunctions(SharedFunctionInfo* function_info) {
881 AssertNoAllocation no_allocation;
882
883 DependentFunctionsDeoptimizingVisitor visitor(function_info);
884 Deoptimizer::VisitAllOptimizedFunctions(&visitor);
885}
886
887
John Reck59135872010-11-02 12:39:01 -0700888MaybeObject* LiveEdit::ReplaceFunctionCode(
889 Handle<JSArray> new_compile_info_array,
890 Handle<JSArray> shared_info_array) {
Steve Block6ded16b2010-05-10 14:33:55 +0100891 HandleScope scope;
892
893 if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
894 return Top::ThrowIllegalOperation();
895 }
896
897 FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
898 SharedInfoWrapper shared_info_wrapper(shared_info_array);
899
900 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
901
902 if (IsJSFunctionCode(shared_info->code())) {
903 ReplaceCodeObject(shared_info->code(),
904 *(compile_info_wrapper.GetFunctionCode()));
Iain Merrick75681382010-08-19 15:07:18 +0100905 Handle<Object> code_scope_info = compile_info_wrapper.GetCodeScopeInfo();
906 if (code_scope_info->IsFixedArray()) {
907 shared_info->set_scope_info(SerializedScopeInfo::cast(*code_scope_info));
908 }
Steve Block6ded16b2010-05-10 14:33:55 +0100909 }
910
911 if (shared_info->debug_info()->IsDebugInfo()) {
912 Handle<DebugInfo> debug_info(DebugInfo::cast(shared_info->debug_info()));
913 Handle<Code> new_original_code =
914 Factory::CopyCode(compile_info_wrapper.GetFunctionCode());
915 debug_info->set_original_code(*new_original_code);
916 }
917
918 shared_info->set_start_position(compile_info_wrapper.GetStartPosition());
919 shared_info->set_end_position(compile_info_wrapper.GetEndPosition());
920
921 shared_info->set_construct_stub(
922 Builtins::builtin(Builtins::JSConstructStubGeneric));
923
Ben Murdochb0fe1622011-05-05 13:52:32 +0100924 DeoptimizeDependentFunctions(*shared_info);
925 CompilationCache::Remove(shared_info);
926
Steve Block6ded16b2010-05-10 14:33:55 +0100927 return Heap::undefined_value();
928}
929
930
Ben Murdochb0fe1622011-05-05 13:52:32 +0100931MaybeObject* LiveEdit::FunctionSourceUpdated(
932 Handle<JSArray> shared_info_array) {
933 HandleScope scope;
934
935 if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
936 return Top::ThrowIllegalOperation();
937 }
938
939 SharedInfoWrapper shared_info_wrapper(shared_info_array);
940 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
941
942 DeoptimizeDependentFunctions(*shared_info);
943 CompilationCache::Remove(shared_info);
944
945 return Heap::undefined_value();
946}
947
948
Steve Block6ded16b2010-05-10 14:33:55 +0100949void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
950 Handle<Object> script_handle) {
951 Handle<SharedFunctionInfo> shared_info =
952 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(function_wrapper));
953 shared_info->set_script(*script_handle);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100954
955 CompilationCache::Remove(shared_info);
Steve Block6ded16b2010-05-10 14:33:55 +0100956}
957
958
959// For a script text change (defined as position_change_array), translates
960// position in unchanged text to position in changed text.
961// Text change is a set of non-overlapping regions in text, that have changed
962// their contents and length. It is specified as array of groups of 3 numbers:
963// (change_begin, change_end, change_end_new_position).
964// Each group describes a change in text; groups are sorted by change_begin.
965// Only position in text beyond any changes may be successfully translated.
966// If a positions is inside some region that changed, result is currently
967// undefined.
968static int TranslatePosition(int original_position,
969 Handle<JSArray> position_change_array) {
970 int position_diff = 0;
971 int array_len = Smi::cast(position_change_array->length())->value();
972 // TODO(635): binary search may be used here
973 for (int i = 0; i < array_len; i += 3) {
John Reck59135872010-11-02 12:39:01 -0700974 Object* element = position_change_array->GetElementNoExceptionThrown(i);
975 int chunk_start = Smi::cast(element)->value();
Steve Block6ded16b2010-05-10 14:33:55 +0100976 if (original_position < chunk_start) {
977 break;
978 }
John Reck59135872010-11-02 12:39:01 -0700979 element = position_change_array->GetElementNoExceptionThrown(i + 1);
980 int chunk_end = Smi::cast(element)->value();
Steve Block6ded16b2010-05-10 14:33:55 +0100981 // Position mustn't be inside a chunk.
982 ASSERT(original_position >= chunk_end);
John Reck59135872010-11-02 12:39:01 -0700983 element = position_change_array->GetElementNoExceptionThrown(i + 2);
984 int chunk_changed_end = Smi::cast(element)->value();
Steve Block6ded16b2010-05-10 14:33:55 +0100985 position_diff = chunk_changed_end - chunk_end;
986 }
987
988 return original_position + position_diff;
989}
990
991
992// Auto-growing buffer for writing relocation info code section. This buffer
993// is a simplified version of buffer from Assembler. Unlike Assembler, this
994// class is platform-independent and it works without dealing with instructions.
995// As specified by RelocInfo format, the buffer is filled in reversed order:
996// from upper to lower addresses.
997// It uses NewArray/DeleteArray for memory management.
998class RelocInfoBuffer {
999 public:
1000 RelocInfoBuffer(int buffer_initial_capicity, byte* pc) {
1001 buffer_size_ = buffer_initial_capicity + kBufferGap;
1002 buffer_ = NewArray<byte>(buffer_size_);
1003
1004 reloc_info_writer_.Reposition(buffer_ + buffer_size_, pc);
1005 }
1006 ~RelocInfoBuffer() {
1007 DeleteArray(buffer_);
1008 }
1009
1010 // As specified by RelocInfo format, the buffer is filled in reversed order:
1011 // from upper to lower addresses.
1012 void Write(const RelocInfo* rinfo) {
1013 if (buffer_ + kBufferGap >= reloc_info_writer_.pos()) {
1014 Grow();
1015 }
1016 reloc_info_writer_.Write(rinfo);
1017 }
1018
1019 Vector<byte> GetResult() {
1020 // Return the bytes from pos up to end of buffer.
1021 int result_size =
1022 static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer_.pos());
1023 return Vector<byte>(reloc_info_writer_.pos(), result_size);
1024 }
1025
1026 private:
1027 void Grow() {
1028 // Compute new buffer size.
1029 int new_buffer_size;
1030 if (buffer_size_ < 2 * KB) {
1031 new_buffer_size = 4 * KB;
1032 } else {
1033 new_buffer_size = 2 * buffer_size_;
1034 }
1035 // Some internal data structures overflow for very large buffers,
1036 // they must ensure that kMaximalBufferSize is not too large.
1037 if (new_buffer_size > kMaximalBufferSize) {
1038 V8::FatalProcessOutOfMemory("RelocInfoBuffer::GrowBuffer");
1039 }
1040
1041 // Setup new buffer.
1042 byte* new_buffer = NewArray<byte>(new_buffer_size);
1043
1044 // Copy the data.
1045 int curently_used_size =
1046 static_cast<int>(buffer_ + buffer_size_ - reloc_info_writer_.pos());
1047 memmove(new_buffer + new_buffer_size - curently_used_size,
1048 reloc_info_writer_.pos(), curently_used_size);
1049
1050 reloc_info_writer_.Reposition(
1051 new_buffer + new_buffer_size - curently_used_size,
1052 reloc_info_writer_.last_pc());
1053
1054 DeleteArray(buffer_);
1055 buffer_ = new_buffer;
1056 buffer_size_ = new_buffer_size;
1057 }
1058
1059 RelocInfoWriter reloc_info_writer_;
1060 byte* buffer_;
1061 int buffer_size_;
1062
Leon Clarkef7060e22010-06-03 12:02:55 +01001063 static const int kBufferGap = RelocInfoWriter::kMaxSize;
Steve Block6ded16b2010-05-10 14:33:55 +01001064 static const int kMaximalBufferSize = 512*MB;
1065};
1066
1067// Patch positions in code (changes relocation info section) and possibly
1068// returns new instance of code.
1069static Handle<Code> PatchPositionsInCode(Handle<Code> code,
1070 Handle<JSArray> position_change_array) {
1071
1072 RelocInfoBuffer buffer_writer(code->relocation_size(),
1073 code->instruction_start());
1074
1075 {
1076 AssertNoAllocation no_allocations_please;
1077 for (RelocIterator it(*code); !it.done(); it.next()) {
1078 RelocInfo* rinfo = it.rinfo();
1079 if (RelocInfo::IsPosition(rinfo->rmode())) {
1080 int position = static_cast<int>(rinfo->data());
1081 int new_position = TranslatePosition(position,
1082 position_change_array);
1083 if (position != new_position) {
1084 RelocInfo info_copy(rinfo->pc(), rinfo->rmode(), new_position);
1085 buffer_writer.Write(&info_copy);
1086 continue;
1087 }
1088 }
1089 buffer_writer.Write(it.rinfo());
1090 }
1091 }
1092
1093 Vector<byte> buffer = buffer_writer.GetResult();
1094
1095 if (buffer.length() == code->relocation_size()) {
1096 // Simply patch relocation area of code.
1097 memcpy(code->relocation_start(), buffer.start(), buffer.length());
1098 return code;
1099 } else {
1100 // Relocation info section now has different size. We cannot simply
1101 // rewrite it inside code object. Instead we have to create a new
1102 // code object.
1103 Handle<Code> result(Factory::CopyCode(code, buffer));
1104 return result;
1105 }
1106}
1107
1108
John Reck59135872010-11-02 12:39:01 -07001109MaybeObject* LiveEdit::PatchFunctionPositions(
Steve Block6ded16b2010-05-10 14:33:55 +01001110 Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array) {
1111
1112 if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
1113 return Top::ThrowIllegalOperation();
1114 }
1115
1116 SharedInfoWrapper shared_info_wrapper(shared_info_array);
1117 Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo();
1118
1119 int old_function_start = info->start_position();
1120 int new_function_start = TranslatePosition(old_function_start,
1121 position_change_array);
1122 info->set_start_position(new_function_start);
1123 info->set_end_position(TranslatePosition(info->end_position(),
1124 position_change_array));
1125
1126 info->set_function_token_position(
1127 TranslatePosition(info->function_token_position(),
1128 position_change_array));
1129
1130 if (IsJSFunctionCode(info->code())) {
1131 // Patch relocation info section of the code.
1132 Handle<Code> patched_code = PatchPositionsInCode(Handle<Code>(info->code()),
1133 position_change_array);
1134 if (*patched_code != info->code()) {
1135 // Replace all references to the code across the heap. In particular,
1136 // some stubs may refer to this code and this code may be being executed
1137 // on stack (it is safe to substitute the code object on stack, because
1138 // we only change the structure of rinfo and leave instructions
1139 // untouched).
1140 ReplaceCodeObject(info->code(), *patched_code);
1141 }
1142 }
1143
1144 return Heap::undefined_value();
1145}
1146
1147
1148static Handle<Script> CreateScriptCopy(Handle<Script> original) {
1149 Handle<String> original_source(String::cast(original->source()));
1150
1151 Handle<Script> copy = Factory::NewScript(original_source);
1152
1153 copy->set_name(original->name());
1154 copy->set_line_offset(original->line_offset());
1155 copy->set_column_offset(original->column_offset());
1156 copy->set_data(original->data());
1157 copy->set_type(original->type());
1158 copy->set_context_data(original->context_data());
1159 copy->set_compilation_type(original->compilation_type());
1160 copy->set_eval_from_shared(original->eval_from_shared());
1161 copy->set_eval_from_instructions_offset(
1162 original->eval_from_instructions_offset());
1163
1164 return copy;
1165}
1166
1167
1168Object* LiveEdit::ChangeScriptSource(Handle<Script> original_script,
1169 Handle<String> new_source,
1170 Handle<Object> old_script_name) {
1171 Handle<Object> old_script_object;
1172 if (old_script_name->IsString()) {
1173 Handle<Script> old_script = CreateScriptCopy(original_script);
1174 old_script->set_name(String::cast(*old_script_name));
1175 old_script_object = old_script;
1176 Debugger::OnAfterCompile(old_script, Debugger::SEND_WHEN_DEBUGGING);
1177 } else {
1178 old_script_object = Handle<Object>(Heap::null_value());
1179 }
1180
1181 original_script->set_source(*new_source);
1182
1183 // Drop line ends so that they will be recalculated.
1184 original_script->set_line_ends(Heap::undefined_value());
1185
1186 return *old_script_object;
1187}
1188
1189
1190
1191void LiveEdit::ReplaceRefToNestedFunction(
1192 Handle<JSValue> parent_function_wrapper,
1193 Handle<JSValue> orig_function_wrapper,
1194 Handle<JSValue> subst_function_wrapper) {
1195
1196 Handle<SharedFunctionInfo> parent_shared =
1197 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(parent_function_wrapper));
1198 Handle<SharedFunctionInfo> orig_shared =
1199 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(orig_function_wrapper));
1200 Handle<SharedFunctionInfo> subst_shared =
1201 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(subst_function_wrapper));
1202
1203 for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) {
1204 if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) {
1205 if (it.rinfo()->target_object() == *orig_shared) {
1206 it.rinfo()->set_target_object(*subst_shared);
1207 }
1208 }
1209 }
1210}
1211
1212
1213// Check an activation against list of functions. If there is a function
1214// that matches, its status in result array is changed to status argument value.
1215static bool CheckActivation(Handle<JSArray> shared_info_array,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001216 Handle<JSArray> result,
1217 StackFrame* frame,
Steve Block6ded16b2010-05-10 14:33:55 +01001218 LiveEdit::FunctionPatchabilityStatus status) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001219 if (!frame->is_java_script()) return false;
1220
1221 Handle<JSFunction> function(
1222 JSFunction::cast(JavaScriptFrame::cast(frame)->function()));
1223
Steve Block6ded16b2010-05-10 14:33:55 +01001224 int len = Smi::cast(shared_info_array->length())->value();
1225 for (int i = 0; i < len; i++) {
John Reck59135872010-11-02 12:39:01 -07001226 JSValue* wrapper =
1227 JSValue::cast(shared_info_array->GetElementNoExceptionThrown(i));
Steve Block6ded16b2010-05-10 14:33:55 +01001228 Handle<SharedFunctionInfo> shared(
1229 SharedFunctionInfo::cast(wrapper->value()));
1230
Ben Murdochb0fe1622011-05-05 13:52:32 +01001231 if (function->shared() == *shared || IsInlined(*function, *shared)) {
Steve Block6ded16b2010-05-10 14:33:55 +01001232 SetElement(result, i, Handle<Smi>(Smi::FromInt(status)));
1233 return true;
1234 }
1235 }
1236 return false;
1237}
1238
1239
1240// Iterates over handler chain and removes all elements that are inside
1241// frames being dropped.
1242static bool FixTryCatchHandler(StackFrame* top_frame,
1243 StackFrame* bottom_frame) {
1244 Address* pointer_address =
1245 &Memory::Address_at(Top::get_address_from_id(Top::k_handler_address));
1246
1247 while (*pointer_address < top_frame->sp()) {
1248 pointer_address = &Memory::Address_at(*pointer_address);
1249 }
1250 Address* above_frame_address = pointer_address;
1251 while (*pointer_address < bottom_frame->fp()) {
1252 pointer_address = &Memory::Address_at(*pointer_address);
1253 }
1254 bool change = *above_frame_address != *pointer_address;
1255 *above_frame_address = *pointer_address;
1256 return change;
1257}
1258
1259
1260// Removes specified range of frames from stack. There may be 1 or more
1261// frames in range. Anyway the bottom frame is restarted rather than dropped,
1262// and therefore has to be a JavaScript frame.
1263// Returns error message or NULL.
1264static const char* DropFrames(Vector<StackFrame*> frames,
1265 int top_frame_index,
Steve Block8defd9f2010-07-08 12:39:36 +01001266 int bottom_js_frame_index,
Ben Murdochbb769b22010-08-11 14:56:33 +01001267 Debug::FrameDropMode* mode,
1268 Object*** restarter_frame_function_pointer) {
Iain Merrick75681382010-08-19 15:07:18 +01001269 if (!Debug::kFrameDropperSupported) {
Steve Block8defd9f2010-07-08 12:39:36 +01001270 return "Stack manipulations are not supported in this architecture.";
1271 }
1272
Steve Block6ded16b2010-05-10 14:33:55 +01001273 StackFrame* pre_top_frame = frames[top_frame_index - 1];
1274 StackFrame* top_frame = frames[top_frame_index];
1275 StackFrame* bottom_js_frame = frames[bottom_js_frame_index];
1276
1277 ASSERT(bottom_js_frame->is_java_script());
1278
1279 // Check the nature of the top frame.
1280 if (pre_top_frame->code()->is_inline_cache_stub() &&
1281 pre_top_frame->code()->ic_state() == DEBUG_BREAK) {
1282 // OK, we can drop inline cache calls.
Steve Block8defd9f2010-07-08 12:39:36 +01001283 *mode = Debug::FRAME_DROPPED_IN_IC_CALL;
1284 } else if (pre_top_frame->code() == Debug::debug_break_slot()) {
1285 // OK, we can drop debug break slot.
1286 *mode = Debug::FRAME_DROPPED_IN_DEBUG_SLOT_CALL;
Steve Block6ded16b2010-05-10 14:33:55 +01001287 } else if (pre_top_frame->code() ==
1288 Builtins::builtin(Builtins::FrameDropper_LiveEdit)) {
1289 // OK, we can drop our own code.
Steve Block8defd9f2010-07-08 12:39:36 +01001290 *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
Steve Block6ded16b2010-05-10 14:33:55 +01001291 } else if (pre_top_frame->code()->kind() == Code::STUB &&
1292 pre_top_frame->code()->major_key()) {
Steve Block8defd9f2010-07-08 12:39:36 +01001293 // Entry from our unit tests, it's fine, we support this case.
1294 *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
Steve Block6ded16b2010-05-10 14:33:55 +01001295 } else {
1296 return "Unknown structure of stack above changing function";
1297 }
1298
1299 Address unused_stack_top = top_frame->sp();
1300 Address unused_stack_bottom = bottom_js_frame->fp()
1301 - Debug::kFrameDropperFrameSize * kPointerSize // Size of the new frame.
1302 + kPointerSize; // Bigger address end is exclusive.
1303
1304 if (unused_stack_top > unused_stack_bottom) {
1305 return "Not enough space for frame dropper frame";
1306 }
1307
1308 // Committing now. After this point we should return only NULL value.
1309
1310 FixTryCatchHandler(pre_top_frame, bottom_js_frame);
1311 // Make sure FixTryCatchHandler is idempotent.
1312 ASSERT(!FixTryCatchHandler(pre_top_frame, bottom_js_frame));
1313
1314 Handle<Code> code(Builtins::builtin(Builtins::FrameDropper_LiveEdit));
1315 top_frame->set_pc(code->entry());
1316 pre_top_frame->SetCallerFp(bottom_js_frame->fp());
1317
Ben Murdochbb769b22010-08-11 14:56:33 +01001318 *restarter_frame_function_pointer =
1319 Debug::SetUpFrameDropperFrame(bottom_js_frame, code);
1320
1321 ASSERT((**restarter_frame_function_pointer)->IsJSFunction());
Steve Block6ded16b2010-05-10 14:33:55 +01001322
1323 for (Address a = unused_stack_top;
1324 a < unused_stack_bottom;
1325 a += kPointerSize) {
1326 Memory::Object_at(a) = Smi::FromInt(0);
1327 }
1328
1329 return NULL;
1330}
1331
1332
1333static bool IsDropableFrame(StackFrame* frame) {
1334 return !frame->is_exit();
1335}
1336
1337// Fills result array with statuses of functions. Modifies the stack
1338// removing all listed function if possible and if do_drop is true.
1339static const char* DropActivationsInActiveThread(
1340 Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop) {
1341
1342 ZoneScope scope(DELETE_ON_EXIT);
1343 Vector<StackFrame*> frames = CreateStackMap();
1344
1345 int array_len = Smi::cast(shared_info_array->length())->value();
1346
1347 int top_frame_index = -1;
1348 int frame_index = 0;
1349 for (; frame_index < frames.length(); frame_index++) {
1350 StackFrame* frame = frames[frame_index];
1351 if (frame->id() == Debug::break_frame_id()) {
1352 top_frame_index = frame_index;
1353 break;
1354 }
1355 if (CheckActivation(shared_info_array, result, frame,
1356 LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
1357 // We are still above break_frame. It is not a target frame,
1358 // it is a problem.
1359 return "Debugger mark-up on stack is not found";
1360 }
1361 }
1362
1363 if (top_frame_index == -1) {
1364 // We haven't found break frame, but no function is blocking us anyway.
1365 return NULL;
1366 }
1367
1368 bool target_frame_found = false;
1369 int bottom_js_frame_index = top_frame_index;
1370 bool c_code_found = false;
1371
1372 for (; frame_index < frames.length(); frame_index++) {
1373 StackFrame* frame = frames[frame_index];
1374 if (!IsDropableFrame(frame)) {
1375 c_code_found = true;
1376 break;
1377 }
1378 if (CheckActivation(shared_info_array, result, frame,
1379 LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
1380 target_frame_found = true;
1381 bottom_js_frame_index = frame_index;
1382 }
1383 }
1384
1385 if (c_code_found) {
1386 // There is a C frames on stack. Check that there are no target frames
1387 // below them.
1388 for (; frame_index < frames.length(); frame_index++) {
1389 StackFrame* frame = frames[frame_index];
1390 if (frame->is_java_script()) {
1391 if (CheckActivation(shared_info_array, result, frame,
1392 LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
1393 // Cannot drop frame under C frames.
1394 return NULL;
1395 }
1396 }
1397 }
1398 }
1399
1400 if (!do_drop) {
1401 // We are in check-only mode.
1402 return NULL;
1403 }
1404
1405 if (!target_frame_found) {
1406 // Nothing to drop.
1407 return NULL;
1408 }
1409
Steve Block8defd9f2010-07-08 12:39:36 +01001410 Debug::FrameDropMode drop_mode = Debug::FRAMES_UNTOUCHED;
Ben Murdochbb769b22010-08-11 14:56:33 +01001411 Object** restarter_frame_function_pointer = NULL;
Steve Block6ded16b2010-05-10 14:33:55 +01001412 const char* error_message = DropFrames(frames, top_frame_index,
Ben Murdochbb769b22010-08-11 14:56:33 +01001413 bottom_js_frame_index, &drop_mode,
1414 &restarter_frame_function_pointer);
Steve Block6ded16b2010-05-10 14:33:55 +01001415
1416 if (error_message != NULL) {
1417 return error_message;
1418 }
1419
1420 // Adjust break_frame after some frames has been dropped.
1421 StackFrame::Id new_id = StackFrame::NO_ID;
1422 for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) {
1423 if (frames[i]->type() == StackFrame::JAVA_SCRIPT) {
1424 new_id = frames[i]->id();
1425 break;
1426 }
1427 }
Ben Murdochbb769b22010-08-11 14:56:33 +01001428 Debug::FramesHaveBeenDropped(new_id, drop_mode,
1429 restarter_frame_function_pointer);
Steve Block6ded16b2010-05-10 14:33:55 +01001430
1431 // Replace "blocked on active" with "replaced on active" status.
1432 for (int i = 0; i < array_len; i++) {
1433 if (result->GetElement(i) ==
1434 Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001435 Handle<Object> replaced(
1436 Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK));
1437 SetElement(result, i, replaced);
Steve Block6ded16b2010-05-10 14:33:55 +01001438 }
1439 }
1440 return NULL;
1441}
1442
1443
1444class InactiveThreadActivationsChecker : public ThreadVisitor {
1445 public:
1446 InactiveThreadActivationsChecker(Handle<JSArray> shared_info_array,
1447 Handle<JSArray> result)
1448 : shared_info_array_(shared_info_array), result_(result),
1449 has_blocked_functions_(false) {
1450 }
1451 void VisitThread(ThreadLocalTop* top) {
1452 for (StackFrameIterator it(top); !it.done(); it.Advance()) {
1453 has_blocked_functions_ |= CheckActivation(
1454 shared_info_array_, result_, it.frame(),
1455 LiveEdit::FUNCTION_BLOCKED_ON_OTHER_STACK);
1456 }
1457 }
1458 bool HasBlockedFunctions() {
1459 return has_blocked_functions_;
1460 }
1461
1462 private:
1463 Handle<JSArray> shared_info_array_;
1464 Handle<JSArray> result_;
1465 bool has_blocked_functions_;
1466};
1467
1468
1469Handle<JSArray> LiveEdit::CheckAndDropActivations(
1470 Handle<JSArray> shared_info_array, bool do_drop) {
1471 int len = Smi::cast(shared_info_array->length())->value();
1472
1473 Handle<JSArray> result = Factory::NewJSArray(len);
1474
1475 // Fill the default values.
1476 for (int i = 0; i < len; i++) {
1477 SetElement(result, i,
1478 Handle<Smi>(Smi::FromInt(FUNCTION_AVAILABLE_FOR_PATCH)));
1479 }
1480
1481
1482 // First check inactive threads. Fail if some functions are blocked there.
1483 InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array,
1484 result);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001485 ThreadManager::IterateArchivedThreads(&inactive_threads_checker);
Steve Block6ded16b2010-05-10 14:33:55 +01001486 if (inactive_threads_checker.HasBlockedFunctions()) {
1487 return result;
1488 }
1489
1490 // Try to drop activations from the current stack.
1491 const char* error_message =
1492 DropActivationsInActiveThread(shared_info_array, result, do_drop);
1493 if (error_message != NULL) {
1494 // Add error message as an array extra element.
1495 Vector<const char> vector_message(error_message, StrLength(error_message));
1496 Handle<String> str = Factory::NewStringFromAscii(vector_message);
1497 SetElement(result, len, str);
1498 }
1499 return result;
1500}
1501
1502
Andrei Popescu402d9372010-02-26 13:31:12 +00001503LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) {
1504 if (active_function_info_listener != NULL) {
1505 active_function_info_listener->FunctionStarted(fun);
1506 }
1507}
Steve Block6ded16b2010-05-10 14:33:55 +01001508
1509
Andrei Popescu402d9372010-02-26 13:31:12 +00001510LiveEditFunctionTracker::~LiveEditFunctionTracker() {
1511 if (active_function_info_listener != NULL) {
1512 active_function_info_listener->FunctionDone();
1513 }
1514}
Steve Block6ded16b2010-05-10 14:33:55 +01001515
1516
1517void LiveEditFunctionTracker::RecordFunctionInfo(
1518 Handle<SharedFunctionInfo> info, FunctionLiteral* lit) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001519 if (active_function_info_listener != NULL) {
Steve Block6ded16b2010-05-10 14:33:55 +01001520 active_function_info_listener->FunctionInfo(info, lit->scope());
Andrei Popescu402d9372010-02-26 13:31:12 +00001521 }
1522}
Steve Block6ded16b2010-05-10 14:33:55 +01001523
1524
1525void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
1526 active_function_info_listener->FunctionCode(code);
Andrei Popescu402d9372010-02-26 13:31:12 +00001527}
Steve Block6ded16b2010-05-10 14:33:55 +01001528
1529
Andrei Popescu402d9372010-02-26 13:31:12 +00001530bool LiveEditFunctionTracker::IsActive() {
1531 return active_function_info_listener != NULL;
1532}
1533
Steve Block6ded16b2010-05-10 14:33:55 +01001534
1535#else // ENABLE_DEBUGGER_SUPPORT
1536
1537// This ifdef-else-endif section provides working or stub implementation of
1538// LiveEditFunctionTracker.
1539LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) {
1540}
1541
1542
1543LiveEditFunctionTracker::~LiveEditFunctionTracker() {
1544}
1545
1546
1547void LiveEditFunctionTracker::RecordFunctionInfo(
1548 Handle<SharedFunctionInfo> info, FunctionLiteral* lit) {
1549}
1550
1551
1552void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
1553}
1554
1555
1556bool LiveEditFunctionTracker::IsActive() {
1557 return false;
1558}
1559
1560#endif // ENABLE_DEBUGGER_SUPPORT
1561
1562
1563
Andrei Popescu402d9372010-02-26 13:31:12 +00001564} } // namespace v8::internal