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 // 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 Loading... |
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 Loading... |
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 |
OLD | NEW |