| 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 | 
|---|