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

Side by Side Diff: src/liveedit.cc

Issue 914003: LiveEdit: patch positions in function (Closed)
Patch Set: merge Created 10 years, 9 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/heap.cc ('k') | src/liveedit-delay.js » ('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 328 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 SharedFunctionInfo::cast(array->GetElement(i))); 339 SharedFunctionInfo::cast(array->GetElement(i)));
340 SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create(); 340 SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create();
341 Handle<String> name_handle(String::cast(info->name())); 341 Handle<String> name_handle(String::cast(info->name()));
342 info_wrapper.SetProperties(name_handle, info->start_position(), 342 info_wrapper.SetProperties(name_handle, info->start_position(),
343 info->end_position(), info); 343 info->end_position(), info);
344 array->SetElement(i, *(info_wrapper.GetJSArray())); 344 array->SetElement(i, *(info_wrapper.GetJSArray()));
345 } 345 }
346 } 346 }
347 347
348 348
349 // Visitor that collects all references to a particular code object,
350 // including "CODE_TARGET" references in other code objects.
351 // It works in context of ZoneScope.
352 class ReferenceCollectorVisitor : public ObjectVisitor {
353 public:
354 explicit ReferenceCollectorVisitor(Code* original)
355 : original_(original), rvalues_(10), reloc_infos_(10) {
356 }
357
358 virtual void VisitPointers(Object** start, Object** end) {
359 for (Object** p = start; p < end; p++) {
360 if (*p == original_) {
361 rvalues_.Add(p);
362 }
363 }
364 }
365
366 void VisitCodeTarget(RelocInfo* rinfo) {
367 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
368 if (Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) {
369 reloc_infos_.Add(*rinfo);
370 }
371 }
372
373 virtual void VisitDebugTarget(RelocInfo* rinfo) {
374 VisitCodeTarget(rinfo);
375 }
376
377 // Post-visiting method that iterates over all collected references and
378 // modifies them.
379 void Replace(Code* substitution) {
380 for (int i = 0; i < rvalues_.length(); i++) {
381 *(rvalues_[i]) = substitution;
382 }
383 for (int i = 0; i < reloc_infos_.length(); i++) {
384 reloc_infos_[i].set_target_address(substitution->instruction_start());
385 }
386 }
387
388 private:
389 Code* original_;
390 ZoneList<Object**> rvalues_;
391 ZoneList<RelocInfo> reloc_infos_;
392 };
393
394 // Finds all references to original and replaces them with substitution.
395 static void ReplaceCodeObject(Code* original, Code* substitution) {
396 ASSERT(!Heap::InNewSpace(substitution));
397
398 AssertNoAllocation no_allocations_please;
399
400 // A zone scope for ReferenceCollectorVisitor.
401 ZoneScope scope(DELETE_ON_EXIT);
402
403 ReferenceCollectorVisitor visitor(original);
404
405 // Iterate over all roots. Stack frames may have pointer into original code,
406 // so temporary replace the pointers with offset numbers
407 // in prologue/epilogue.
408 ThreadManager::MarkCompactPrologue(true);
409 Heap::IterateStrongRoots(&visitor, VISIT_ALL);
410 ThreadManager::MarkCompactEpilogue(true);
411
412 // Now iterate over all pointers of all objects, including code_target
413 // implicit pointers.
414 HeapIterator iterator;
415 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
416 obj->Iterate(&visitor);
417 }
418
419 visitor.Replace(substitution);
420 }
421
422
349 void LiveEdit::ReplaceFunctionCode(Handle<JSArray> new_compile_info_array, 423 void LiveEdit::ReplaceFunctionCode(Handle<JSArray> new_compile_info_array,
350 Handle<JSArray> shared_info_array) { 424 Handle<JSArray> shared_info_array) {
351 HandleScope scope; 425 HandleScope scope;
352 426
353 FunctionInfoWrapper compile_info_wrapper(new_compile_info_array); 427 FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
354 SharedInfoWrapper shared_info_wrapper(shared_info_array); 428 SharedInfoWrapper shared_info_wrapper(shared_info_array);
355 429
356 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo(); 430 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
357 431
358 shared_info->set_code(*(compile_info_wrapper.GetFunctionCode()), 432 ReplaceCodeObject(shared_info->code(),
359 UPDATE_WRITE_BARRIER); 433 *(compile_info_wrapper.GetFunctionCode()));
434
360 shared_info->set_start_position(compile_info_wrapper.GetStartPosition()); 435 shared_info->set_start_position(compile_info_wrapper.GetStartPosition());
361 shared_info->set_end_position(compile_info_wrapper.GetEndPosition()); 436 shared_info->set_end_position(compile_info_wrapper.GetEndPosition());
362 // update breakpoints, original code, constructor stub 437 // update breakpoints, original code, constructor stub
363 } 438 }
364 439
365 440
366 void LiveEdit::RelinkFunctionToScript(Handle<JSArray> shared_info_array, 441 void LiveEdit::RelinkFunctionToScript(Handle<JSArray> shared_info_array,
367 Handle<Script> script_handle) { 442 Handle<Script> script_handle) {
368 SharedInfoWrapper shared_info_wrapper(shared_info_array); 443 SharedInfoWrapper shared_info_wrapper(shared_info_array);
369 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo(); 444 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
(...skipping 12 matching lines...) Expand all
382 // If a positions is inside some region that changed, result is currently 457 // If a positions is inside some region that changed, result is currently
383 // undefined. 458 // undefined.
384 static int TranslatePosition(int original_position, 459 static int TranslatePosition(int original_position,
385 Handle<JSArray> position_change_array) { 460 Handle<JSArray> position_change_array) {
386 int position_diff = 0; 461 int position_diff = 0;
387 int array_len = Smi::cast(position_change_array->length())->value(); 462 int array_len = Smi::cast(position_change_array->length())->value();
388 // TODO(635): binary search may be used here 463 // TODO(635): binary search may be used here
389 for (int i = 0; i < array_len; i += 3) { 464 for (int i = 0; i < array_len; i += 3) {
390 int chunk_start = 465 int chunk_start =
391 Smi::cast(position_change_array->GetElement(i))->value(); 466 Smi::cast(position_change_array->GetElement(i))->value();
467 if (original_position < chunk_start) {
468 break;
469 }
392 int chunk_end = 470 int chunk_end =
393 Smi::cast(position_change_array->GetElement(i + 1))->value(); 471 Smi::cast(position_change_array->GetElement(i + 1))->value();
472 // Position mustn't be inside a chunk.
473 ASSERT(original_position >= chunk_end);
394 int chunk_changed_end = 474 int chunk_changed_end =
395 Smi::cast(position_change_array->GetElement(i + 2))->value(); 475 Smi::cast(position_change_array->GetElement(i + 2))->value();
396 position_diff = chunk_changed_end - chunk_end; 476 position_diff = chunk_changed_end - chunk_end;
397 if (original_position < chunk_start) {
398 break;
399 }
400 // Position mustn't be inside a chunk.
401 ASSERT(original_position >= chunk_end);
402 } 477 }
403 478
404 return original_position + position_diff; 479 return original_position + position_diff;
405 } 480 }
406 481
407 482
483 // Auto-growing buffer for writing relocation info code section. This buffer
484 // is a simplified version of buffer from Assembler. Unlike Assembler, this
485 // class is platform-independent and it works without dealing with instructions.
486 // As specified by RelocInfo format, the buffer is filled in reversed order:
487 // from upper to lower addresses.
488 // It uses NewArray/DeleteArray for memory management.
489 class RelocInfoBuffer {
490 public:
491 RelocInfoBuffer(int buffer_initial_capicity, byte* pc) {
492 buffer_size_ = buffer_initial_capicity + kBufferGap;
493 buffer_ = NewArray<byte>(buffer_size_);
494
495 reloc_info_writer_.Reposition(buffer_ + buffer_size_, pc);
496 }
497 ~RelocInfoBuffer() {
498 DeleteArray(buffer_);
499 }
500
501 // As specified by RelocInfo format, the buffer is filled in reversed order:
502 // from upper to lower addresses.
503 void Write(const RelocInfo* rinfo) {
504 if (buffer_ + kBufferGap >= reloc_info_writer_.pos()) {
505 Grow();
506 }
507 reloc_info_writer_.Write(rinfo);
508 }
509
510 Vector<byte> GetResult() {
511 // Return the bytes from pos up to end of buffer.
512 return Vector<byte>(reloc_info_writer_.pos(),
513 buffer_ + buffer_size_ - reloc_info_writer_.pos());
514 }
515
516 private:
517 void Grow() {
518 // Compute new buffer size.
519 int new_buffer_size;
520 if (buffer_size_ < 2 * KB) {
521 new_buffer_size = 4 * KB;
522 } else {
523 new_buffer_size = 2 * buffer_size_;
524 }
525 // Some internal data structures overflow for very large buffers,
526 // they must ensure that kMaximalBufferSize is not too large.
527 if (new_buffer_size > kMaximalBufferSize) {
528 V8::FatalProcessOutOfMemory("RelocInfoBuffer::GrowBuffer");
529 }
530
531 // Setup new buffer.
532 byte* new_buffer = NewArray<byte>(new_buffer_size);
533
534 // Copy the data.
535 int curently_used_size = buffer_ + buffer_size_ - reloc_info_writer_.pos();
536 memmove(new_buffer + new_buffer_size - curently_used_size,
537 reloc_info_writer_.pos(), curently_used_size);
538
539 reloc_info_writer_.Reposition(
540 new_buffer + new_buffer_size - curently_used_size,
541 reloc_info_writer_.last_pc());
542
543 DeleteArray(buffer_);
544 buffer_ = new_buffer;
545 buffer_size_ = new_buffer_size;
546 }
547
548 RelocInfoWriter reloc_info_writer_;
549 byte* buffer_;
550 int buffer_size_;
551
552 static const int kBufferGap = 8;
553 static const int kMaximalBufferSize = 512*MB;
554 };
555
556 // Patch positions in code (changes relocation info section) and possibly
557 // returns new instance of code.
558 static Handle<Code> PatchPositionsInCode(Handle<Code> code,
559 Handle<JSArray> position_change_array) {
560
561 RelocInfoBuffer buffer_writer(code->relocation_size(),
562 code->instruction_start());
563
564 {
565 AssertNoAllocation no_allocations_please;
566 for (RelocIterator it(*code); !it.done(); it.next()) {
567 RelocInfo* rinfo = it.rinfo();
568 if (RelocInfo::IsPosition(rinfo->rmode())) {
569 int position = static_cast<int>(rinfo->data());
570 int new_position = TranslatePosition(position,
571 position_change_array);
572 if (position != new_position) {
573 RelocInfo info_copy(rinfo->pc(), rinfo->rmode(), new_position);
574 buffer_writer.Write(&info_copy);
575 continue;
576 }
577 }
578 buffer_writer.Write(it.rinfo());
579 }
580 }
581
582 Vector<byte> buffer = buffer_writer.GetResult();
583
584 if (buffer.length() == code->relocation_size()) {
585 // Simply patch relocation area of code.
586 memcpy(code->relocation_start(), buffer.start(), buffer.length());
587 return code;
588 } else {
589 // Relocation info section now has different size. We cannot simply
590 // rewrite it inside code object. Instead we have to create a new
591 // code object.
592 Handle<Code> result(Factory::CopyCode(code, buffer));
593 return result;
594 }
595 }
596
597
408 void LiveEdit::PatchFunctionPositions(Handle<JSArray> shared_info_array, 598 void LiveEdit::PatchFunctionPositions(Handle<JSArray> shared_info_array,
409 Handle<JSArray> position_change_array) { 599 Handle<JSArray> position_change_array) {
410 SharedInfoWrapper shared_info_wrapper(shared_info_array); 600 SharedInfoWrapper shared_info_wrapper(shared_info_array);
411 Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo(); 601 Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo();
412 602
413 info->set_start_position(TranslatePosition(info->start_position(), 603 info->set_start_position(TranslatePosition(info->start_position(),
414 position_change_array)); 604 position_change_array));
415 info->set_end_position(TranslatePosition(info->end_position(), 605 info->set_end_position(TranslatePosition(info->end_position(),
416 position_change_array)); 606 position_change_array));
417 607
418 // Also patch rinfos (both in working code and original code), breakpoints. 608 info->set_function_token_position(
609 TranslatePosition(info->function_token_position(),
610 position_change_array));
611
612 // Patch relocation info section of the code.
613 Handle<Code> patched_code = PatchPositionsInCode(Handle<Code>(info->code()),
614 position_change_array);
615 if (*patched_code != info->code()) {
616 // Replace all references to the code across the heap. In particular,
617 // some stubs may refer to this code and this code may be being executed
618 // on stack (it is safe to substitute the code object on stack, because
619 // we only change the structure of rinfo and leave instructions untouched).
620 ReplaceCodeObject(info->code(), *patched_code);
621 }
622
623 if (info->debug_info()->IsDebugInfo()) {
624 Handle<DebugInfo> debug_info(DebugInfo::cast(info->debug_info()));
625 Handle<Code> patched_orig_code =
626 PatchPositionsInCode(Handle<Code>(debug_info->original_code()),
627 position_change_array);
628 if (*patched_orig_code != debug_info->original_code()) {
629 // Do not use expensive ReplaceCodeObject for original_code, because we
630 // do not expect any other references except this one.
631 debug_info->set_original_code(*patched_orig_code);
632 }
633
634 Handle<FixedArray> break_point_infos(debug_info->break_points());
635 for (int i = 0; i < break_point_infos->length(); i++) {
636 if (!break_point_infos->get(i)->IsBreakPointInfo()) {
637 continue;
638 }
639 Handle<BreakPointInfo> info(
640 BreakPointInfo::cast(break_point_infos->get(i)));
641 int new_position = TranslatePosition(info->source_position()->value(),
642 position_change_array);
643 info->set_source_position(Smi::FromInt(new_position));
644 }
645 }
646 // TODO(635): Also patch breakpoint objects in JS.
419 } 647 }
420 648
421 649
422 LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) { 650 LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) {
423 if (active_function_info_listener != NULL) { 651 if (active_function_info_listener != NULL) {
424 active_function_info_listener->FunctionStarted(fun); 652 active_function_info_listener->FunctionStarted(fun);
425 } 653 }
426 } 654 }
427 655
428 656
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 702
475 bool LiveEditFunctionTracker::IsActive() { 703 bool LiveEditFunctionTracker::IsActive() {
476 return false; 704 return false;
477 } 705 }
478 706
479 #endif // ENABLE_DEBUGGER_SUPPORT 707 #endif // ENABLE_DEBUGGER_SUPPORT
480 708
481 709
482 710
483 } } // namespace v8::internal 711 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/heap.cc ('k') | src/liveedit-delay.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698