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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/heap.cc ('k') | src/liveedit-delay.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/liveedit.cc
diff --git a/src/liveedit.cc b/src/liveedit.cc
index 513cc0233f18de5464080317b4a80027d1c6bdbd..4533f9c7ddab854446ab33ece7b4ed93685d2587 100644
--- a/src/liveedit.cc
+++ b/src/liveedit.cc
@@ -346,8 +346,82 @@ void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> array) {
}
+// Visitor that collects all references to a particular code object,
+// including "CODE_TARGET" references in other code objects.
+// It works in context of ZoneScope.
+class ReferenceCollectorVisitor : public ObjectVisitor {
+ public:
+ explicit ReferenceCollectorVisitor(Code* original)
+ : original_(original), rvalues_(10), reloc_infos_(10) {
+ }
+
+ virtual void VisitPointers(Object** start, Object** end) {
+ for (Object** p = start; p < end; p++) {
+ if (*p == original_) {
+ rvalues_.Add(p);
+ }
+ }
+ }
+
+ void VisitCodeTarget(RelocInfo* rinfo) {
+ ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
+ if (Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) {
+ reloc_infos_.Add(*rinfo);
+ }
+ }
+
+ virtual void VisitDebugTarget(RelocInfo* rinfo) {
+ VisitCodeTarget(rinfo);
+ }
+
+ // Post-visiting method that iterates over all collected references and
+ // modifies them.
+ void Replace(Code* substitution) {
+ for (int i = 0; i < rvalues_.length(); i++) {
+ *(rvalues_[i]) = substitution;
+ }
+ for (int i = 0; i < reloc_infos_.length(); i++) {
+ reloc_infos_[i].set_target_address(substitution->instruction_start());
+ }
+ }
+
+ private:
+ Code* original_;
+ ZoneList<Object**> rvalues_;
+ ZoneList<RelocInfo> reloc_infos_;
+};
+
+// Finds all references to original and replaces them with substitution.
+static void ReplaceCodeObject(Code* original, Code* substitution) {
+ ASSERT(!Heap::InNewSpace(substitution));
+
+ AssertNoAllocation no_allocations_please;
+
+ // A zone scope for ReferenceCollectorVisitor.
+ ZoneScope scope(DELETE_ON_EXIT);
+
+ ReferenceCollectorVisitor visitor(original);
+
+ // Iterate over all roots. Stack frames may have pointer into original code,
+ // so temporary replace the pointers with offset numbers
+ // in prologue/epilogue.
+ ThreadManager::MarkCompactPrologue(true);
+ Heap::IterateStrongRoots(&visitor, VISIT_ALL);
+ ThreadManager::MarkCompactEpilogue(true);
+
+ // Now iterate over all pointers of all objects, including code_target
+ // implicit pointers.
+ HeapIterator iterator;
+ for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
+ obj->Iterate(&visitor);
+ }
+
+ visitor.Replace(substitution);
+}
+
+
void LiveEdit::ReplaceFunctionCode(Handle<JSArray> new_compile_info_array,
- Handle<JSArray> shared_info_array) {
+ Handle<JSArray> shared_info_array) {
HandleScope scope;
FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
@@ -355,8 +429,9 @@ void LiveEdit::ReplaceFunctionCode(Handle<JSArray> new_compile_info_array,
Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
- shared_info->set_code(*(compile_info_wrapper.GetFunctionCode()),
- UPDATE_WRITE_BARRIER);
+ ReplaceCodeObject(shared_info->code(),
+ *(compile_info_wrapper.GetFunctionCode()));
+
shared_info->set_start_position(compile_info_wrapper.GetStartPosition());
shared_info->set_end_position(compile_info_wrapper.GetEndPosition());
// update breakpoints, original code, constructor stub
@@ -389,22 +464,137 @@ static int TranslatePosition(int original_position,
for (int i = 0; i < array_len; i += 3) {
int chunk_start =
Smi::cast(position_change_array->GetElement(i))->value();
- int chunk_end =
- Smi::cast(position_change_array->GetElement(i + 1))->value();
- int chunk_changed_end =
- Smi::cast(position_change_array->GetElement(i + 2))->value();
- position_diff = chunk_changed_end - chunk_end;
if (original_position < chunk_start) {
break;
}
+ int chunk_end =
+ Smi::cast(position_change_array->GetElement(i + 1))->value();
// Position mustn't be inside a chunk.
ASSERT(original_position >= chunk_end);
+ int chunk_changed_end =
+ Smi::cast(position_change_array->GetElement(i + 2))->value();
+ position_diff = chunk_changed_end - chunk_end;
}
return original_position + position_diff;
}
+// Auto-growing buffer for writing relocation info code section. This buffer
+// is a simplified version of buffer from Assembler. Unlike Assembler, this
+// class is platform-independent and it works without dealing with instructions.
+// As specified by RelocInfo format, the buffer is filled in reversed order:
+// from upper to lower addresses.
+// It uses NewArray/DeleteArray for memory management.
+class RelocInfoBuffer {
+ public:
+ RelocInfoBuffer(int buffer_initial_capicity, byte* pc) {
+ buffer_size_ = buffer_initial_capicity + kBufferGap;
+ buffer_ = NewArray<byte>(buffer_size_);
+
+ reloc_info_writer_.Reposition(buffer_ + buffer_size_, pc);
+ }
+ ~RelocInfoBuffer() {
+ DeleteArray(buffer_);
+ }
+
+ // As specified by RelocInfo format, the buffer is filled in reversed order:
+ // from upper to lower addresses.
+ void Write(const RelocInfo* rinfo) {
+ if (buffer_ + kBufferGap >= reloc_info_writer_.pos()) {
+ Grow();
+ }
+ reloc_info_writer_.Write(rinfo);
+ }
+
+ Vector<byte> GetResult() {
+ // Return the bytes from pos up to end of buffer.
+ return Vector<byte>(reloc_info_writer_.pos(),
+ buffer_ + buffer_size_ - reloc_info_writer_.pos());
+ }
+
+ private:
+ void Grow() {
+ // Compute new buffer size.
+ int new_buffer_size;
+ if (buffer_size_ < 2 * KB) {
+ new_buffer_size = 4 * KB;
+ } else {
+ new_buffer_size = 2 * buffer_size_;
+ }
+ // Some internal data structures overflow for very large buffers,
+ // they must ensure that kMaximalBufferSize is not too large.
+ if (new_buffer_size > kMaximalBufferSize) {
+ V8::FatalProcessOutOfMemory("RelocInfoBuffer::GrowBuffer");
+ }
+
+ // Setup new buffer.
+ byte* new_buffer = NewArray<byte>(new_buffer_size);
+
+ // Copy the data.
+ int curently_used_size = buffer_ + buffer_size_ - reloc_info_writer_.pos();
+ memmove(new_buffer + new_buffer_size - curently_used_size,
+ reloc_info_writer_.pos(), curently_used_size);
+
+ reloc_info_writer_.Reposition(
+ new_buffer + new_buffer_size - curently_used_size,
+ reloc_info_writer_.last_pc());
+
+ DeleteArray(buffer_);
+ buffer_ = new_buffer;
+ buffer_size_ = new_buffer_size;
+ }
+
+ RelocInfoWriter reloc_info_writer_;
+ byte* buffer_;
+ int buffer_size_;
+
+ static const int kBufferGap = 8;
+ static const int kMaximalBufferSize = 512*MB;
+};
+
+// Patch positions in code (changes relocation info section) and possibly
+// returns new instance of code.
+static Handle<Code> PatchPositionsInCode(Handle<Code> code,
+ Handle<JSArray> position_change_array) {
+
+ RelocInfoBuffer buffer_writer(code->relocation_size(),
+ code->instruction_start());
+
+ {
+ AssertNoAllocation no_allocations_please;
+ for (RelocIterator it(*code); !it.done(); it.next()) {
+ RelocInfo* rinfo = it.rinfo();
+ if (RelocInfo::IsPosition(rinfo->rmode())) {
+ int position = static_cast<int>(rinfo->data());
+ int new_position = TranslatePosition(position,
+ position_change_array);
+ if (position != new_position) {
+ RelocInfo info_copy(rinfo->pc(), rinfo->rmode(), new_position);
+ buffer_writer.Write(&info_copy);
+ continue;
+ }
+ }
+ buffer_writer.Write(it.rinfo());
+ }
+ }
+
+ Vector<byte> buffer = buffer_writer.GetResult();
+
+ if (buffer.length() == code->relocation_size()) {
+ // Simply patch relocation area of code.
+ memcpy(code->relocation_start(), buffer.start(), buffer.length());
+ return code;
+ } else {
+ // Relocation info section now has different size. We cannot simply
+ // rewrite it inside code object. Instead we have to create a new
+ // code object.
+ Handle<Code> result(Factory::CopyCode(code, buffer));
+ return result;
+ }
+}
+
+
void LiveEdit::PatchFunctionPositions(Handle<JSArray> shared_info_array,
Handle<JSArray> position_change_array) {
SharedInfoWrapper shared_info_wrapper(shared_info_array);
@@ -415,7 +605,45 @@ void LiveEdit::PatchFunctionPositions(Handle<JSArray> shared_info_array,
info->set_end_position(TranslatePosition(info->end_position(),
position_change_array));
- // Also patch rinfos (both in working code and original code), breakpoints.
+ info->set_function_token_position(
+ TranslatePosition(info->function_token_position(),
+ position_change_array));
+
+ // Patch relocation info section of the code.
+ Handle<Code> patched_code = PatchPositionsInCode(Handle<Code>(info->code()),
+ position_change_array);
+ if (*patched_code != info->code()) {
+ // Replace all references to the code across the heap. In particular,
+ // some stubs may refer to this code and this code may be being executed
+ // on stack (it is safe to substitute the code object on stack, because
+ // we only change the structure of rinfo and leave instructions untouched).
+ ReplaceCodeObject(info->code(), *patched_code);
+ }
+
+ if (info->debug_info()->IsDebugInfo()) {
+ Handle<DebugInfo> debug_info(DebugInfo::cast(info->debug_info()));
+ Handle<Code> patched_orig_code =
+ PatchPositionsInCode(Handle<Code>(debug_info->original_code()),
+ position_change_array);
+ if (*patched_orig_code != debug_info->original_code()) {
+ // Do not use expensive ReplaceCodeObject for original_code, because we
+ // do not expect any other references except this one.
+ debug_info->set_original_code(*patched_orig_code);
+ }
+
+ Handle<FixedArray> break_point_infos(debug_info->break_points());
+ for (int i = 0; i < break_point_infos->length(); i++) {
+ if (!break_point_infos->get(i)->IsBreakPointInfo()) {
+ continue;
+ }
+ Handle<BreakPointInfo> info(
+ BreakPointInfo::cast(break_point_infos->get(i)));
+ int new_position = TranslatePosition(info->source_position()->value(),
+ position_change_array);
+ info->set_source_position(Smi::FromInt(new_position));
+ }
+ }
+ // TODO(635): Also patch breakpoint objects in JS.
}
« 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