Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(615)

Side by Side Diff: src/liveedit.cc

Issue 546125: A brutal approach to V8 script liveedit (Closed)
Patch Set: merge Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/liveedit.h ('k') | src/runtime.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 17 matching lines...) Expand all
28 28
29 #include "v8.h" 29 #include "v8.h"
30 30
31 #include "liveedit.h" 31 #include "liveedit.h"
32 #include "compiler.h" 32 #include "compiler.h"
33 #include "oprofile-agent.h" 33 #include "oprofile-agent.h"
34 #include "scopes.h" 34 #include "scopes.h"
35 #include "global-handles.h" 35 #include "global-handles.h"
36 #include "debug.h" 36 #include "debug.h"
37 37
38 #ifdef ENABLE_DEBUGGER_SUPPORT
39
38 namespace v8 { 40 namespace v8 {
39 namespace internal { 41 namespace internal {
40 42
43 static Handle<JSFunction> LiveEditMakeFunction(bool is_global,
44 Compiler::ValidationState validate,
45 Handle<Script> script,
46 Handle<Context> context,
47 v8::Extension* extension,
48 ScriptDataImpl* pre_data) {
49 const bool is_eval = false;
50 PostponeInterruptsScope postpone;
51
52 ASSERT(!i::Top::global_context().is_null());
53 script->set_context_data((*i::Top::global_context())->data());
54
55 #ifdef ENABLE_DEBUGGER_SUPPORT
56 // no eval or json support
57 // Do not notify debugger (maybe later)
58 //Debugger::OnBeforeCompile(script);
59 #endif
60
61 // Only allow non-global compiles for eval.
62 ASSERT(is_eval || is_global);
63
64 // Build AST.
65 FunctionLiteral* lit = MakeAST(is_global, script, extension, pre_data);
66
67 // Check for parse errors.
68 if (lit == NULL) {
69 ASSERT(Top::has_pending_exception());
70 return Handle<JSFunction>::null();
71 }
72
73 // Compile the code.
74 CompilationInfo info(lit, script, is_eval);
75 Handle<Code> code = MakeCodeForLiveEdit(context, &info);
76
77 // Check for stack-overflow exceptions.
78 if (code.is_null()) {
79 Top::StackOverflow();
80 return Handle<JSFunction>::null();
81 }
82
83 const bool support_profiler_in_live_edit = false;
84 if (support_profiler_in_live_edit) {
85 #if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
86 // Log the code generation for the script. Check explicit whether logging is
87 // to avoid allocating when not required.
88 if (Logger::is_logging() || OProfileAgent::is_enabled()) {
89 if (script->name()->IsString()) {
90 SmartPointer<char> data =
91 String::cast(script->name())->ToCString(DISALLOW_NULLS);
92 LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
93 *code, *data));
94 OProfileAgent::CreateNativeCodeRegion(*data,
95 code->instruction_start(),
96 code->instruction_size());
97 } else {
98 LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
99 *code, ""));
100 OProfileAgent::CreateNativeCodeRegion(is_eval ? "Eval" : "Script",
101 code->instruction_start(),
102 code->instruction_size());
103 }
104 }
105 #endif
106 }
107
108 // Allocate function.
109 Handle<JSFunction> fun =
110 Factory::NewFunctionBoilerplate(lit->name(),
111 lit->materialized_literal_count(),
112 code);
113
114 ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
115 Compiler::SetFunctionInfo(fun, lit, true, script);
116
117 // Hint to the runtime system used when allocating space for initial
118 // property space by setting the expected number of properties for
119 // the instances of the function.
120 SetExpectedNofPropertiesFromEstimate(fun, lit->expected_property_count());
121
122 #ifdef ENABLE_DEBUGGER_SUPPORT
123 // Do not notify debugger (maybe later)
124 // Debugger::OnAfterCompile(script, fun);
125 #endif
126
127 return fun;
128 }
129
130 static StaticResource<SafeStringInputBuffer> safe_string_input_buffer;
131
132 class UnusedReferenceChecker {
133 public:
134 UnusedReferenceChecker() : head_(NULL) {
135 }
136
137 ~UnusedReferenceChecker() {
138 for (Item* item = head_; item != NULL; item = item->next) {
139 GlobalHandles::Destroy(item->ref);
140 }
141 }
142
143 void Add(Object* obj) {
144 Item* item = new Item();
145 item->next = head_;
146 head_ = item;
147 Object** ref = GlobalHandles::Create(obj).location();
148 GlobalHandles::MakeWeak(ref, item, &Callback);
149 item->ref = ref;
150 item->collected = false;
151 }
152
153 void Check() {
154 Heap::CollectAllGarbage(false);
155 for (Item* item = head_; item != NULL; item = item->next) {
156 if (!item->collected) {
157 const int kSize = 10;
158 Handle<FixedArray> array = Factory::NewFixedArray(kSize);
159 int found = FindReferences(*item->ref, 0, *array, array->length());
160 printf("Item ");
161 (*item->ref)->ShortPrint();
162 printf(" still referenced by %d item(s):\n", found);
163 for (int i = 0; i < found; i++) {
164 if (i >= array->length()) {
165 printf("... there's more.\n");
166 break;
167 }
168 array->get(i)->ShortPrint();
169 printf("\n");
170 }
171 }
172 ASSERT(item->collected);
173 }
174
175 }
176
177 static void Callback(Persistent<Value> object, void* parameter) {
178 Item* item = reinterpret_cast<Item*>(parameter);
179 item->collected = true;
180 }
181
182 private:
183 struct Item : public ZoneObject {
184 Object** ref;
185 bool collected;
186 Item* next;
187 };
188 Item* head_;
189
190 class VisitorImpl : public ObjectVisitor {
191 public:
192 VisitorImpl(Object* target) : target_(target), found_(false) {}
193
194 bool HasFound() {
195 return found_;
196 }
197
198 protected:
199 void VisitPointers(Object** start, Object** end) {
200 for (Object** pp = start; pp < end; pp++) {
201 if (*pp == target_) {
202 found_ = true;
203 break;
204 }
205 }
206 }
207
208 private:
209 Object* target_;
210 bool found_;
211 };
212
213 static int FindReferences(Object* target, int max_references,
214 FixedArray* instances, int instances_size) {
215 NoHandleAllocation ha;
216 AssertNoAllocation no_alloc;
217
218 // Iterate the heap.
219 int count = 0;
220 HeapIterator iterator;
221 HeapObject* heap_obj = NULL;
222 while (((heap_obj = iterator.next()) != NULL) &&
223 (max_references == 0 || count < max_references)) {
224
225 // Skip context extension objects and argument arrays as these are
226 // checked in the context of functions using them.
227 HeapObject* obj = heap_obj;
228
229 VisitorImpl visitor(target);
230 obj->Iterate(&visitor);
231 if (visitor.HasFound()) {
232 if (instances != NULL && count < instances_size) {
233 instances->set(count, obj);
234 }
235 count++;
236 }
237 }
238
239 // Return the number of referencing objects found.
240 return count;
241 }
242 };
243
244 void CompileAndAnalyzeScript(Handle<Script> script) {
245 Extension* extension = NULL;
246 Handle<String> source = Handle<String>(String::cast(script->source()));
247 ScriptDataImpl* pre_data = NULL;
248 if (pre_data == NULL && source->length() >= FLAG_min_preparse_length) {
249 Access<SafeStringInputBuffer> buf(&safe_string_input_buffer);
250 buf->Reset(source.location());
251 pre_data = PreParse(source, buf.value(), extension);
252 }
253
254 // Compile the function and add it to the cache.
255 Handle<JSFunction> res = LiveEditMakeFunction(true,
256 Compiler::DONT_VALIDATE_JSON,
257 script,
258 Handle<Context>::null(),
259 NULL,
260 pre_data);
261 // Compilation.
262 ASSERT(res->IsJSFunction());
263 }
264
265 // Let us be careful with double pointers.
266 // Here expected input types are explicit.
267 template<typename FROM, typename TO>
268 TO** DoublePointerNarrowingCast(FROM** from) {
269 TO* t1 = NULL;
270 FROM* t2 = t1;
271 USE(t2);
272 return reinterpret_cast<TO**>(from);
273 }
274
275 template<typename FROM, typename TO>
276 TO** DoublePointerWideningCast(FROM** from) {
277 FROM* t1 = NULL;
278 TO* t2 = t1;
279 USE(t2);
280 return reinterpret_cast<TO**>(from);
281 }
282
283 // For a function (i.e. closure: code + data) describes expectations that
284 // code has about its data. If new version of code has the same expectations
285 // as the old version has, all live closure instances may be safely patched
286 // with a new code.
287 // TODO(peter.rybin): make sure this description is accurate enough.
288 class CodeInfo {
289 private:
290 struct ScopeSlotInfo {
291 String** var_name;
292 int index;
293 ScopeSlotInfo() : var_name(NULL) {}
294 };
295
296 Vector<ScopeSlotInfo> slots;
297 int num_parameters;
298
299 public:
300 void RecordNumParameters(int num_parameters) {
301 this->num_parameters = num_parameters;
302 }
303 // Stores the scope info in some internal format.
304 void RecordScopes(Scope* scope) {
305 // Saves some description of scope. It stores name and indexes of
306 // variables in the whole scope chain. Null-named slots delimit
307 // scopes of this chain.
308 Scope* outer_scope = scope->outer_scope();
309 if (outer_scope == NULL) {
310 return;
311 }
312 ZoneList<ScopeSlotInfo> slots(10);
313 do {
314 ZoneList<Variable*> list(10);
315 outer_scope->CollectUsedVariables(&list);
316 int j = 0;
317 for (int i = 0; i < list.length(); i++) {
318 Variable* var1 = list[i];
319 Slot* slot = var1->slot();
320 if (slot != NULL && slot->type() == Slot::CONTEXT) {
321 if (j != i) {
322 list[j] = var1;
323 }
324 j++;
325 }
326 }
327
328 // Sort it.
329 // TODO(peter.rybin): next time try bubble sort.
330 for (int k = 1; k < j; k++) {
331 int l = k;
332 for (int m = k + 1; m < j; m++) {
333 if (list[l]->slot()->index() > list[m]->slot()->index()) {
334 l = m;
335 }
336 }
337 list[k] = list[l];
338 }
339 for (int i = 0; i < j; i++) {
340 ScopeSlotInfo info;
341 info.var_name = DoublePointerNarrowingCast<Object,String>(
342 GlobalHandles::Create(*list[i]->name()).location());
343 info.index = list[i]->slot()->index();
344 slots.Add(info);
345 }
346 slots.Add(ScopeSlotInfo());
347 outer_scope = outer_scope->outer_scope();
348 } while (outer_scope != NULL);
349 this->slots = slots.ToVector();
350 }
351
352 // Compares itself with other info. When they are equal it means that
353 // different code versions have the same expectations about their data.
354 bool CompareTo(CodeInfo* info2) {
355 CodeInfo* info1 = this;
356 if (info1->num_parameters != info2->num_parameters) {
357 return false;
358 }
359 if (info1->slots.length() != info2->slots.length()) {
360 return false;
361 }
362 for (int i = 0; i < info1->slots.length(); i++) {
363 ScopeSlotInfo* slot1 = &info1->slots[i];
364 ScopeSlotInfo* slot2 = &info2->slots[i];
365 if (slot1->index != slot2->index) {
366 return false;
367 }
368 if (slot1->var_name == NULL) {
369 if (slot2->var_name != NULL) {
370 return false;
371 }
372 } else {
373 if (!(*slot1->var_name)->Equals(*slot2->var_name)) {
374 return false;
375 }
376 }
377 }
378 return true;
379 }
380
381 void DisposeHandles() {
382 for (int j = 0; j < slots.length(); j++) {
383 if (slots[j].var_name != NULL) {
384 // TODO does it have to be so brutal?
385 GlobalHandles::Destroy(DoublePointerWideningCast<String,Object>(
386 slots[j].var_name));
387 }
388 }
389 }
390 void Print() {
391 for (int i = 0; i < slots.length(); i++) {
392 if (slots[i].var_name == NULL) {
393 printf(" | ");
394 } else {
395 SmartPointer<char> str = (*slots[i].var_name)->ToCString();
396 printf(" %d/%s", slots[i].index,*str);
397 }
398 }
399 printf(" params %d", num_parameters);
400 }
401 };
402
403 // Saved information about a function. It is stored in array. It points
404 // to other items in this array by their indexes.
405 struct FunctionInfo {
406 int outer_index;
407 int next_sibling_index;
408 CodeInfo code_info;
409 int start_pos;
410 int end_pos;
411 Code** function_code;
412
413 FunctionInfo() : function_code(NULL) {}
414 };
41 415
42 class FunctionInfoListener { 416 class FunctionInfoListener {
43 public: 417 public:
418 FunctionInfoListener(): function_infos_(10),
419 current_pos_(-1), last_sibling_pos_(-1) {}
420
421 Vector<FunctionInfo> GetFunctionInfos() {
422 Vector<FunctionInfo> temp = function_infos_.ToVector();
423 // new index -> old index
424
425 ZoneList<int> old_index_map_builder(temp.length());
426 for (int i = 0; i < temp.length(); i++) {
427 old_index_map_builder.Add(i);
428 }
429 Vector<int> old_index_map = old_index_map_builder.ToVector();
430 for (int i = 0; i < temp.length(); i++) {
431 int k = i;
432 for (int j = i + 1; j < temp.length(); j++) {
433 if (temp[k].start_pos > temp[j].start_pos) {
434 k = j;
435 }
436 }
437 if (k != i) {
438 FunctionInfo temp_info = temp[k];
439 int temp_index = old_index_map[k];
440 temp[k] = temp[i];
441 old_index_map[k] = temp_index;
442 temp[i] = temp_info;
443 old_index_map[i] = temp_index;
444 }
445 }
446 int index = 0;
447 ResetIndexes(temp, &index, -1, -1, old_index_map);
448 ASSERT(index == temp.length());
449
450 return temp;
451 }
452
453 static void DisposeData(Vector<FunctionInfo> data) {
454 for (int i = 0; i < data.length(); i++) {
455 FunctionInfo* info = &data[i];
456 CodeInfo* code_info = &info->code_info;
457 code_info->DisposeHandles();
458 if (info->function_code != NULL) {
459 // TODO does it have to be so brutal?
460 GlobalHandles::Destroy(DoublePointerWideningCast<Code,Object>(info->func tion_code));
461 }
462 }
463 }
464
465 friend class LiveEditFunctionTracker;
466
467 private:
468 void ResetIndexes(Vector<FunctionInfo> array, int* current_index,
469 int new_parent_index,
470 int old_parent_index,
471 Vector<int> old_index_map) {
472 int previous_sibling = -1;
473 while (*current_index < array.length() && array[*current_index].outer_index == old_parent_index) {
474 int index = *current_index;
475 array[index].outer_index = new_parent_index;
476 if (previous_sibling != -1) {
477 array[previous_sibling].next_sibling_index = index;
478 }
479 previous_sibling = index;
480 (*current_index)++;
481 ResetIndexes(array, current_index, index, old_index_map[index], old_index_ map);
482 }
483 if (previous_sibling != -1) {
484 array[previous_sibling].next_sibling_index = -1;
485 }
486 }
487
44 void FunctionStarted(FunctionLiteral* fun) { 488 void FunctionStarted(FunctionLiteral* fun) {
45 // Implementation follows. 489 // printf("Start '%s' %d %d\n", *fun->name()->ToCString(), fun->start_positi on(), fun->end_position());
490 FunctionInfo info;
491 info.code_info.RecordNumParameters(fun->num_parameters());
492 info.start_pos = fun->start_position();
493 info.end_pos = fun->end_position();
494 info.outer_index = current_pos_;
495 info.next_sibling_index = last_sibling_pos_;
496 last_sibling_pos_ = -1;
497 current_pos_ = function_infos_.length();
498 function_infos_.Add(info);
499 if (info.outer_index != -1) {
500 FunctionInfo& outer_info = function_infos_[info.outer_index];
501 ASSERT(info.start_pos >= outer_info.start_pos);
502 ASSERT(info.end_pos <= outer_info.end_pos);
503 }
46 } 504 }
47 505
48 void FunctionDone() { 506 void FunctionDone() {
49 // Implementation follows. 507 last_sibling_pos_ = current_pos_;
508 current_pos_ = function_infos_[current_pos_].outer_index;
509 // printf("Done\n");
50 } 510 }
51 511
52 void FunctionScope(Scope* scope){ 512 void FunctionScope(Scope* scope){
53 // Implementation follows. 513 function_infos_[current_pos_].code_info.RecordScopes(scope);
54 } 514 }
55 515
56 void FunctionCode(Handle<Code> function_code) { 516 void FunctionCode(Handle<Code> function_code) {
57 // Implementation follows. 517 function_infos_[current_pos_].function_code = DoublePointerNarrowingCast<Obj ect, Code>(GlobalHandles::Create(*function_code).location());
58 } 518 }
519
520 ZoneList<FunctionInfo> function_infos_;
521 int current_pos_;
522 int last_sibling_pos_;
59 }; 523 };
60 524
61 static FunctionInfoListener* active_function_info_listener = NULL; 525 static FunctionInfoListener* active_function_info_listener = NULL;
62 526
63 LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) { 527 LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) {
64 if (active_function_info_listener != NULL) { 528 if (active_function_info_listener != NULL) {
65 active_function_info_listener->FunctionStarted(fun); 529 active_function_info_listener->FunctionStarted(fun);
66 } 530 }
67 } 531 }
68 LiveEditFunctionTracker::~LiveEditFunctionTracker() { 532 LiveEditFunctionTracker::~LiveEditFunctionTracker() {
69 if (active_function_info_listener != NULL) { 533 if (active_function_info_listener != NULL) {
70 active_function_info_listener->FunctionDone(); 534 active_function_info_listener->FunctionDone();
71 } 535 }
72 } 536 }
73 void LiveEditFunctionTracker::RecordFunctionCode(Handle<Code> code) { 537 void LiveEditFunctionTracker::RecordFunctionCode(Handle<Code> code) {
74 if (active_function_info_listener != NULL) { 538 if (active_function_info_listener != NULL) {
75 active_function_info_listener->FunctionCode(code); 539 active_function_info_listener->FunctionCode(code);
76 } 540 }
77 } 541 }
78 void LiveEditFunctionTracker::RecordFunctionScope(Scope* scope) { 542 void LiveEditFunctionTracker::RecordFunctionScope(Scope* scope) {
79 if (active_function_info_listener != NULL) { 543 if (active_function_info_listener != NULL) {
80 active_function_info_listener->FunctionScope(scope); 544 active_function_info_listener->FunctionScope(scope);
81 } 545 }
82 } 546 }
83 bool LiveEditFunctionTracker::IsActive() { 547 bool LiveEditFunctionTracker::IsActive() {
84 return active_function_info_listener != NULL; 548 return active_function_info_listener != NULL;
85 } 549 }
86 550
551 class PosTranslator {
552 public:
553 PosTranslator(int start, int old_len, int new_len)
554 : start_(start), old_len_(old_len), new_len_(new_len) {}
555 int Translate(int pos) {
556 if (pos <= start_) {
557 return pos;
558 }
559 if (pos >= start_ + old_len_) {
560 return pos + new_len_ - old_len_;
561 }
562 return -1;
563 }
564
565 private:
566 int start_;
567 int old_len_;
568 int new_len_;
569 };
570
571
572 // Chooses the innermost function that covers the change region.
573 // TODO(peter.rybin): function should cover change region by its body region,
574 // not by its entire text
575 int ChooseChangedFunction(Vector<FunctionInfo> fun_infos,
576 int change_pos, int change_len) {
577
578 // First condition: function should start before the change region.
579 // Function #0 (whole-script function) always does, but we want
580 // the one, that comes last in this list.
581 int index = 0;
582 while (index + 1 < fun_infos.length() &&
583 fun_infos[index + 1].start_pos <= change_pos) {
584 index++;
585 }
586 // Now we have stand at the last function that begins before the change
587 // region. The function that covers entire change region is either
588 // this function or enclosing one.
589 for (; fun_infos[index].end_pos < change_pos + change_len;
590 index = fun_infos[index].outer_index) {
591 ASSERT(index != -1);
592 }
593 return index;
594 }
595
596 void PatchCode(FunctionInfo* new_info,
597 Handle<SharedFunctionInfo> shared_info,
598 UnusedReferenceChecker* ref_checker) {
599 if (shared_info.is_null()) {
600 // Function not found. Probably it's normal.
601 // TODO explain why it's normal.
602 return;
603 }
604 ref_checker->Add(shared_info->code());
605 shared_info->set_code(*new_info->function_code, UPDATE_WRITE_BARRIER);
606 shared_info->set_start_position(new_info->start_pos);
607 shared_info->set_end_position(new_info->end_pos);
608 // TODO: update breakpoints, original code, constructor stub
609 }
610
611 void PatchPositions(FunctionInfo* new_info,
612 Handle<SharedFunctionInfo> shared_info,
613 PosTranslator* pos_translator) {
614 if (shared_info.is_null()) {
615 // Function not found. Probably it's normal.
616 // TODO explain why it's normal.
617 return;
618 }
619 int new_start_pos = pos_translator->Translate(
620 shared_info->start_position());
621 int new_end_pos = pos_translator->Translate(shared_info->end_position());
622 ASSERT(new_start_pos == new_info->start_pos);
623 ASSERT(new_end_pos == new_info->end_pos);
624 shared_info->set_start_position(new_start_pos);
625 shared_info->set_end_position(new_end_pos);
626
627 // TODO
628 // breakpoints, rinfos, shared function positions
629 }
630
631 void LinkToOldScript(FunctionInfo* old_info, Handle<Script> old_script,
632 Handle<SharedFunctionInfo> shared_info) {
633 if (shared_info.is_null()) {
634 // Function not found. Probably it's normal.
635 // TODO explain why it's normal.
636 return;
637 }
638 shared_info->set_script(*old_script);
639 }
640
641 // Helps to find SharedFunctionInfo based on its source positions.
642 class FunctionListHelper {
643 public:
644 FunctionListHelper(Handle<FixedArray> shared_functions,
645 int shared_functions_len,
646 Vector<FunctionInfo> info_list)
647 : shared_functions_(shared_functions),
648 shared_functions_len_(shared_functions_len),
649 info_list_(info_list) {
650 }
651
652 Handle<SharedFunctionInfo> Get(int index) {
653 FunctionInfo* old_info = &info_list_[index];
654 for (int i = 0; i < shared_functions_len_; i++) {
655 SharedFunctionInfo* info =
656 SharedFunctionInfo::cast(shared_functions_->get(i));
657 if (info->start_position() == old_info->start_pos &&
658 info->end_position() == old_info->end_pos) {
659 return Handle<SharedFunctionInfo>(info);
660 }
661 }
662 {
663 printf("Failed to find positions %d %d in\n:", old_info->start_pos, old_in fo->end_pos);
664 for (int i = 0; i < shared_functions_len_; i++) {
665 SharedFunctionInfo* info =
666 SharedFunctionInfo::cast(shared_functions_->get(i));
667 printf(" %d %d\n", info->start_position(), info->end_position());
668 }
669 }
670 return Handle<SharedFunctionInfo>();
671 }
672 private:
673 Handle<FixedArray> shared_functions_;
674 int shared_functions_len_;
675 Vector<FunctionInfo> info_list_;
676 };
677
678 void ChangeScriptLive(Handle<Script> original_script,
679 Handle<String> original_source,
680 Handle<String> new_source,
681 Handle<FixedArray> function_shared_info,
682 int function_shared_info_len,
683 int change_pos, int change_len_old, int change_len_new) {
684
685 printf("Old script:\n");
686 original_source->Print();
687 printf("\n");
688 printf("New script:\n");
689 new_source->Print();
690 printf("\n");
691
692 {
693 CompilationZoneScope zone_scope(DELETE_ON_EXIT);
694
695 Vector<FunctionInfo> old_infos;
696 Vector<FunctionInfo> new_infos;
697 {
698 FunctionInfoListener old_listener;
699 active_function_info_listener = &old_listener;
700 CompileAndAnalyzeScript(original_script);
701 old_infos = old_listener.GetFunctionInfos();
702 active_function_info_listener = NULL;
703 //TODO: check compilation errors
704 }
705
706 // Temporary change source string.
707 original_script->set_source(*new_source);
708 {
709 FunctionInfoListener new_listener;
710 active_function_info_listener = &new_listener;
711 CompileAndAnalyzeScript(original_script);
712 new_infos = new_listener.GetFunctionInfos();
713 active_function_info_listener = NULL;
714 //TODO: check compilation errors
715 }
716 // Change source string back, we'll change it permanently later.
717 original_script->set_source(*original_source);
718
719 int function_being_changed;
720 {
721 int old_func_index =
722 ChooseChangedFunction(old_infos, change_pos, change_len_old);
723 int new_func_index =
724 ChooseChangedFunction(new_infos, change_pos, change_len_new);
725 // Old and new functions should have the same indexes in their lists
726 // up to old_func_index/new_func_index
727 ASSERT(old_func_index == new_func_index);
728 USE(new_func_index);
729 function_being_changed = old_func_index;
730 }
731 printf("Changed function is %d %d (index %d)\n",
732 new_infos[function_being_changed].start_pos,
733 new_infos[function_being_changed].end_pos,
734 function_being_changed);
735
736 // Go to outer functions until code expectations are equal
737 while (!old_infos[function_being_changed].code_info.CompareTo(
738 &new_infos[function_being_changed].code_info)) {
739
740 ASSERT(old_infos[function_being_changed].outer_index ==
741 new_infos[function_being_changed].outer_index);
742 printf("Scope has changed from ");
743 old_infos[function_being_changed].code_info.Print();
744 printf(" to ");
745 new_infos[function_being_changed].code_info.Print();
746 printf("\n");
747 function_being_changed = old_infos[function_being_changed].outer_index;
748 ASSERT(function_being_changed != -1);
749 printf("function has been chosen: %d %d (index %d)\n",
750 new_infos[function_being_changed].start_pos,
751 new_infos[function_being_changed].end_pos,
752 function_being_changed);
753 }
754
755 // TODO(peter.rybin): Check frames on stack.
756 // Committing all changes.
757 original_script->set_source(*new_source);
758
759 Handle<Script> old_script = Factory::NewScript(original_source);
760 old_script->set_name(original_script->name());
761 old_script->set_line_offset(original_script->line_offset());
762 old_script->set_column_offset(original_script->column_offset());
763 old_script->set_data(original_script->data());
764 old_script->set_type(original_script->type());
765 old_script->set_context_data(original_script->context_data());
766 old_script->set_compilation_type(original_script->compilation_type());
767
768 Debugger::OnAfterCompile(old_script, Handle<JSFunction>(), true);
769
770
771 FunctionListHelper old_list_helper(function_shared_info,
772 function_shared_info_len, old_infos);
773
774 UnusedReferenceChecker ref_checker;
775
776 PatchCode(&new_infos[function_being_changed],
777 old_list_helper.Get(function_being_changed),
778 &ref_checker);
779
780 PosTranslator translator(change_pos, change_len_old, change_len_new);
781 for (int i = 0; i < function_being_changed; i++) {
782 PatchPositions(&new_infos[i], old_list_helper.Get(i), &translator);
783 }
784
785 // We are jumping to the sibling of our function (in both lists).
786 // From this index all following items in the lists are our siblings
787 // or their inner functions.
788 int old_next_sibling = old_infos[function_being_changed].next_sibling_index;
789 int new_next_sibling = new_infos[function_being_changed].next_sibling_index;
790
791 if (old_next_sibling == -1) {
792 ASSERT(new_next_sibling == -1);
793 } else {
794 ASSERT(old_infos.length() - old_next_sibling ==
795 new_infos.length() - new_next_sibling);
796
797 for (int i = old_next_sibling, j = new_next_sibling;
798 i < old_infos.length(); i++, j++) {
799 PatchPositions(&new_infos[j], old_list_helper.Get(i), &translator);
800 }
801 }
802
803 // All functions before next_sibling index are inner functions of the
804 // function that we are patching. We leave those functions unpatched.
805 for (int i = function_being_changed + 1; i < old_next_sibling; i++) {
806 LinkToOldScript(&old_infos[i], old_script, old_list_helper.Get(i));
807 }
808
809 FunctionInfoListener::DisposeData(old_infos);
810 FunctionInfoListener::DisposeData(new_infos);
811
812 ref_checker.Check();
813 }
814 }
815
87 } } // namespace v8::internal 816 } } // namespace v8::internal
817
818 #endif // ENABLE_DEBUGGER_SUPPORT
OLDNEW
« no previous file with comments | « src/liveedit.h ('k') | src/runtime.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698