| OLD | NEW |
| 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 Loading... |
| 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 |
| 395 class FrameCookingThreadVisitor : public ThreadVisitor { |
| 396 public: |
| 397 void VisitThread(ThreadLocalTop* top) { |
| 398 StackFrame::CookFramesForThread(top); |
| 399 } |
| 400 }; |
| 401 |
| 402 class FrameUncookingThreadVisitor : public ThreadVisitor { |
| 403 public: |
| 404 void VisitThread(ThreadLocalTop* top) { |
| 405 StackFrame::UncookFramesForThread(top); |
| 406 } |
| 407 }; |
| 408 |
| 409 static void IterateAllThreads(ThreadVisitor* visitor) { |
| 410 Top::IterateThread(visitor); |
| 411 ThreadManager::IterateThreads(visitor); |
| 412 } |
| 413 |
| 414 // Finds all references to original and replaces them with substitution. |
| 415 static void ReplaceCodeObject(Code* original, Code* substitution) { |
| 416 ASSERT(!Heap::InNewSpace(substitution)); |
| 417 |
| 418 AssertNoAllocation no_allocations_please; |
| 419 |
| 420 // A zone scope for ReferenceCollectorVisitor. |
| 421 ZoneScope scope(DELETE_ON_EXIT); |
| 422 |
| 423 ReferenceCollectorVisitor visitor(original); |
| 424 |
| 425 // Iterate over all roots. Stack frames may have pointer into original code, |
| 426 // so temporary replace the pointers with offset numbers |
| 427 // in prologue/epilogue. |
| 428 { |
| 429 FrameCookingThreadVisitor cooking_visitor; |
| 430 IterateAllThreads(&cooking_visitor); |
| 431 |
| 432 Heap::IterateStrongRoots(&visitor, VISIT_ALL); |
| 433 |
| 434 FrameUncookingThreadVisitor uncooking_visitor; |
| 435 IterateAllThreads(&uncooking_visitor); |
| 436 } |
| 437 |
| 438 // Now iterate over all pointers of all objects, including code_target |
| 439 // implicit pointers. |
| 440 HeapIterator iterator; |
| 441 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { |
| 442 obj->Iterate(&visitor); |
| 443 } |
| 444 |
| 445 visitor.Replace(substitution); |
| 446 } |
| 447 |
| 448 |
| 349 void LiveEdit::ReplaceFunctionCode(Handle<JSArray> new_compile_info_array, | 449 void LiveEdit::ReplaceFunctionCode(Handle<JSArray> new_compile_info_array, |
| 350 Handle<JSArray> shared_info_array) { | 450 Handle<JSArray> shared_info_array) { |
| 351 HandleScope scope; | 451 HandleScope scope; |
| 352 | 452 |
| 353 FunctionInfoWrapper compile_info_wrapper(new_compile_info_array); | 453 FunctionInfoWrapper compile_info_wrapper(new_compile_info_array); |
| 354 SharedInfoWrapper shared_info_wrapper(shared_info_array); | 454 SharedInfoWrapper shared_info_wrapper(shared_info_array); |
| 355 | 455 |
| 356 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo(); | 456 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo(); |
| 357 | 457 |
| 358 shared_info->set_code(*(compile_info_wrapper.GetFunctionCode()), | 458 ReplaceCodeObject(shared_info->code(), |
| 359 UPDATE_WRITE_BARRIER); | 459 *(compile_info_wrapper.GetFunctionCode())); |
| 460 |
| 360 shared_info->set_start_position(compile_info_wrapper.GetStartPosition()); | 461 shared_info->set_start_position(compile_info_wrapper.GetStartPosition()); |
| 361 shared_info->set_end_position(compile_info_wrapper.GetEndPosition()); | 462 shared_info->set_end_position(compile_info_wrapper.GetEndPosition()); |
| 362 // update breakpoints, original code, constructor stub | 463 // update breakpoints, original code, constructor stub |
| 363 } | 464 } |
| 364 | 465 |
| 365 | 466 |
| 366 void LiveEdit::RelinkFunctionToScript(Handle<JSArray> shared_info_array, | 467 void LiveEdit::RelinkFunctionToScript(Handle<JSArray> shared_info_array, |
| 367 Handle<Script> script_handle) { | 468 Handle<Script> script_handle) { |
| 368 SharedInfoWrapper shared_info_wrapper(shared_info_array); | 469 SharedInfoWrapper shared_info_wrapper(shared_info_array); |
| 369 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo(); | 470 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 382 // If a positions is inside some region that changed, result is currently | 483 // If a positions is inside some region that changed, result is currently |
| 383 // undefined. | 484 // undefined. |
| 384 static int TranslatePosition(int original_position, | 485 static int TranslatePosition(int original_position, |
| 385 Handle<JSArray> position_change_array) { | 486 Handle<JSArray> position_change_array) { |
| 386 int position_diff = 0; | 487 int position_diff = 0; |
| 387 int array_len = Smi::cast(position_change_array->length())->value(); | 488 int array_len = Smi::cast(position_change_array->length())->value(); |
| 388 // TODO(635): binary search may be used here | 489 // TODO(635): binary search may be used here |
| 389 for (int i = 0; i < array_len; i += 3) { | 490 for (int i = 0; i < array_len; i += 3) { |
| 390 int chunk_start = | 491 int chunk_start = |
| 391 Smi::cast(position_change_array->GetElement(i))->value(); | 492 Smi::cast(position_change_array->GetElement(i))->value(); |
| 493 if (original_position < chunk_start) { |
| 494 break; |
| 495 } |
| 392 int chunk_end = | 496 int chunk_end = |
| 393 Smi::cast(position_change_array->GetElement(i + 1))->value(); | 497 Smi::cast(position_change_array->GetElement(i + 1))->value(); |
| 498 // Position mustn't be inside a chunk. |
| 499 ASSERT(original_position >= chunk_end); |
| 394 int chunk_changed_end = | 500 int chunk_changed_end = |
| 395 Smi::cast(position_change_array->GetElement(i + 2))->value(); | 501 Smi::cast(position_change_array->GetElement(i + 2))->value(); |
| 396 position_diff = chunk_changed_end - chunk_end; | 502 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 } | 503 } |
| 403 | 504 |
| 404 return original_position + position_diff; | 505 return original_position + position_diff; |
| 405 } | 506 } |
| 406 | 507 |
| 407 | 508 |
| 509 // Auto-growing buffer for writing relocation info code section. This buffer |
| 510 // is a simplified version of buffer from Assembler. Unlike Assembler, this |
| 511 // class is platform-independent and it works without dealing with instructions. |
| 512 // As specified by RelocInfo format, the buffer is filled in reversed order: |
| 513 // from upper to lower addresses. |
| 514 // It uses NewArray/DeleteArray for memory management. |
| 515 class RelocInfoBuffer { |
| 516 public: |
| 517 RelocInfoBuffer(int buffer_initial_capicity, byte* pc) { |
| 518 buffer_size_ = buffer_initial_capicity + kBufferGap; |
| 519 buffer_ = NewArray<byte>(buffer_size_); |
| 520 |
| 521 reloc_info_writer_.Reposition(buffer_ + buffer_size_, pc); |
| 522 } |
| 523 ~RelocInfoBuffer() { |
| 524 DeleteArray(buffer_); |
| 525 } |
| 526 |
| 527 // As specified by RelocInfo format, the buffer is filled in reversed order: |
| 528 // from upper to lower addresses. |
| 529 void Write(const RelocInfo* rinfo) { |
| 530 if (buffer_ + kBufferGap >= reloc_info_writer_.pos()) { |
| 531 Grow(); |
| 532 } |
| 533 reloc_info_writer_.Write(rinfo); |
| 534 } |
| 535 |
| 536 Vector<byte> GetResult() { |
| 537 // Return the bytes from pos up to end of buffer. |
| 538 return Vector<byte>(reloc_info_writer_.pos(), |
| 539 buffer_ + buffer_size_ - reloc_info_writer_.pos()); |
| 540 } |
| 541 |
| 542 private: |
| 543 void Grow() { |
| 544 // Compute new buffer size. |
| 545 int new_buffer_size; |
| 546 if (buffer_size_ < 2 * KB) { |
| 547 new_buffer_size = 4 * KB; |
| 548 } else { |
| 549 new_buffer_size = 2 * buffer_size_; |
| 550 } |
| 551 // Some internal data structures overflow for very large buffers, |
| 552 // they must ensure that kMaximalBufferSize is not too large. |
| 553 if (new_buffer_size > kMaximalBufferSize) { |
| 554 V8::FatalProcessOutOfMemory("RelocInfoBuffer::GrowBuffer"); |
| 555 } |
| 556 |
| 557 // Setup new buffer. |
| 558 byte* new_buffer = NewArray<byte>(new_buffer_size); |
| 559 |
| 560 // Copy the data. |
| 561 int curently_used_size = buffer_ + buffer_size_ - reloc_info_writer_.pos(); |
| 562 memmove(new_buffer + new_buffer_size - curently_used_size, |
| 563 reloc_info_writer_.pos(), curently_used_size); |
| 564 |
| 565 reloc_info_writer_.Reposition( |
| 566 new_buffer + new_buffer_size - curently_used_size, |
| 567 reloc_info_writer_.last_pc()); |
| 568 |
| 569 DeleteArray(buffer_); |
| 570 buffer_ = new_buffer; |
| 571 buffer_size_ = new_buffer_size; |
| 572 } |
| 573 |
| 574 RelocInfoWriter reloc_info_writer_; |
| 575 byte* buffer_; |
| 576 int buffer_size_; |
| 577 |
| 578 static const int kBufferGap = 8; |
| 579 static const int kMaximalBufferSize = 512*MB; |
| 580 }; |
| 581 |
| 582 // Patch positions in code (changes relocation info section) and possibly |
| 583 // returns new instance of code. |
| 584 static Handle<Code> PatchPositionsInCode(Handle<Code> code, |
| 585 Handle<JSArray> position_change_array) { |
| 586 |
| 587 RelocInfoBuffer buffer_writer(code->relocation_size(), |
| 588 code->instruction_start()); |
| 589 |
| 590 { |
| 591 AssertNoAllocation no_allocations_please; |
| 592 for (RelocIterator it(*code); !it.done(); it.next()) { |
| 593 RelocInfo* rinfo = it.rinfo(); |
| 594 if (RelocInfo::IsPosition(rinfo->rmode())) { |
| 595 int position = static_cast<int>(rinfo->data()); |
| 596 int new_position = TranslatePosition(position, |
| 597 position_change_array); |
| 598 if (position != new_position) { |
| 599 RelocInfo info_copy(rinfo->pc(), rinfo->rmode(), new_position); |
| 600 buffer_writer.Write(&info_copy); |
| 601 continue; |
| 602 } |
| 603 } |
| 604 buffer_writer.Write(it.rinfo()); |
| 605 } |
| 606 } |
| 607 |
| 608 Vector<byte> buffer = buffer_writer.GetResult(); |
| 609 |
| 610 if (buffer.length() == code->relocation_size()) { |
| 611 // Simply patch relocation area of code. |
| 612 memcpy(code->relocation_start(), buffer.start(), buffer.length()); |
| 613 return code; |
| 614 } else { |
| 615 // Relocation info section now has different size. We cannot simply |
| 616 // rewrite it inside code object. Instead we have to create a new |
| 617 // code object. |
| 618 Handle<Code> result(Factory::CopyCode(code, buffer)); |
| 619 return result; |
| 620 } |
| 621 } |
| 622 |
| 623 |
| 408 void LiveEdit::PatchFunctionPositions(Handle<JSArray> shared_info_array, | 624 void LiveEdit::PatchFunctionPositions(Handle<JSArray> shared_info_array, |
| 409 Handle<JSArray> position_change_array) { | 625 Handle<JSArray> position_change_array) { |
| 410 SharedInfoWrapper shared_info_wrapper(shared_info_array); | 626 SharedInfoWrapper shared_info_wrapper(shared_info_array); |
| 411 Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo(); | 627 Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo(); |
| 412 | 628 |
| 413 info->set_start_position(TranslatePosition(info->start_position(), | 629 info->set_start_position(TranslatePosition(info->start_position(), |
| 414 position_change_array)); | 630 position_change_array)); |
| 415 info->set_end_position(TranslatePosition(info->end_position(), | 631 info->set_end_position(TranslatePosition(info->end_position(), |
| 416 position_change_array)); | 632 position_change_array)); |
| 417 | 633 |
| 418 // Also patch rinfos (both in working code and original code), breakpoints. | 634 info->set_function_token_position( |
| 635 TranslatePosition(info->function_token_position(), |
| 636 position_change_array)); |
| 637 |
| 638 // Patch relocation info section of the code. |
| 639 Handle<Code> patched_code = PatchPositionsInCode(Handle<Code>(info->code()), |
| 640 position_change_array); |
| 641 if (*patched_code != info->code()) { |
| 642 // Replace all references to the code across the heap. In particular, |
| 643 // some stubs may refer to this code and this code may be being executed |
| 644 // on stack (it is safe to substitute the code object on stack, because |
| 645 // we only change the structure of rinfo and leave instructions untouched). |
| 646 ReplaceCodeObject(info->code(), *patched_code); |
| 647 } |
| 648 |
| 649 if (info->debug_info()->IsDebugInfo()) { |
| 650 Handle<DebugInfo> debug_info(DebugInfo::cast(info->debug_info())); |
| 651 Handle<Code> patched_orig_code = |
| 652 PatchPositionsInCode(Handle<Code>(debug_info->original_code()), |
| 653 position_change_array); |
| 654 if (*patched_orig_code != debug_info->original_code()) { |
| 655 // Do not use expensive ReplaceCodeObject for original_code, because we |
| 656 // do not expect any other references except this one. |
| 657 debug_info->set_original_code(*patched_orig_code); |
| 658 } |
| 659 |
| 660 Handle<FixedArray> break_point_infos(debug_info->break_points()); |
| 661 for (int i = 0; i < break_point_infos->length(); i++) { |
| 662 if (!break_point_infos->get(i)->IsBreakPointInfo()) { |
| 663 continue; |
| 664 } |
| 665 Handle<BreakPointInfo> info( |
| 666 BreakPointInfo::cast(break_point_infos->get(i))); |
| 667 int new_position = TranslatePosition(info->source_position()->value(), |
| 668 position_change_array); |
| 669 info->set_source_position(Smi::FromInt(new_position)); |
| 670 } |
| 671 } |
| 672 // TODO(635): Also patch breakpoint objects in JS. |
| 419 } | 673 } |
| 420 | 674 |
| 421 | 675 |
| 422 LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) { | 676 LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) { |
| 423 if (active_function_info_listener != NULL) { | 677 if (active_function_info_listener != NULL) { |
| 424 active_function_info_listener->FunctionStarted(fun); | 678 active_function_info_listener->FunctionStarted(fun); |
| 425 } | 679 } |
| 426 } | 680 } |
| 427 | 681 |
| 428 | 682 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 | 728 |
| 475 bool LiveEditFunctionTracker::IsActive() { | 729 bool LiveEditFunctionTracker::IsActive() { |
| 476 return false; | 730 return false; |
| 477 } | 731 } |
| 478 | 732 |
| 479 #endif // ENABLE_DEBUGGER_SUPPORT | 733 #endif // ENABLE_DEBUGGER_SUPPORT |
| 480 | 734 |
| 481 | 735 |
| 482 | 736 |
| 483 } } // namespace v8::internal | 737 } } // namespace v8::internal |
| OLD | NEW |