Index: src/debug/liveedit.cc |
diff --git a/src/debug/liveedit.cc b/src/debug/liveedit.cc |
index 3ced3cc427405584f1dfed241f62d992a302cf87..06b4b883ae93d6e3a5ff8c7bec52705668232dfb 100644 |
--- a/src/debug/liveedit.cc |
+++ b/src/debug/liveedit.cc |
@@ -652,33 +652,7 @@ Handle<SharedFunctionInfo> SharedInfoWrapper::GetInfo() { |
void LiveEdit::InitializeThreadLocal(Debug* debug) { |
- debug->thread_local_.frame_drop_mode_ = LIVE_EDIT_FRAMES_UNTOUCHED; |
-} |
- |
- |
-bool LiveEdit::SetAfterBreakTarget(Debug* debug) { |
- Code* code = NULL; |
- Isolate* isolate = debug->isolate_; |
- switch (debug->thread_local_.frame_drop_mode_) { |
- case LIVE_EDIT_FRAMES_UNTOUCHED: |
- return false; |
- case LIVE_EDIT_FRAME_DROPPED_IN_DEBUG_SLOT_CALL: |
- // Debug break slot stub does not return normally, instead it manually |
- // cleans the stack and jumps. We should patch the jump address. |
- code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit); |
- break; |
- case LIVE_EDIT_FRAME_DROPPED_IN_DIRECT_CALL: |
- // Nothing to do, after_break_target is not used here. |
- return true; |
- case LIVE_EDIT_FRAME_DROPPED_IN_RETURN_CALL: |
- code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit); |
- break; |
- case LIVE_EDIT_CURRENTLY_SET_MODE: |
- UNREACHABLE(); |
- break; |
- } |
- debug->after_break_target_ = code->entry(); |
- return true; |
+ debug->thread_local_.restart_fp_ = 0; |
} |
@@ -745,47 +719,6 @@ MaybeHandle<JSArray> LiveEdit::GatherCompileInfo(Handle<Script> script, |
} |
} |
- |
-// Visitor that finds all references to a particular code object, |
-// including "CODE_TARGET" references in other code objects and replaces |
-// them on the fly. |
-class ReplacingVisitor : public ObjectVisitor { |
- public: |
- explicit ReplacingVisitor(Code* original, Code* substitution) |
- : original_(original), substitution_(substitution) { |
- } |
- |
- void VisitPointers(Object** start, Object** end) override { |
- for (Object** p = start; p < end; p++) { |
- if (*p == original_) { |
- *p = substitution_; |
- } |
- } |
- } |
- |
- void VisitCodeEntry(Address entry) override { |
- if (Code::GetObjectFromEntryAddress(entry) == original_) { |
- Address substitution_entry = substitution_->instruction_start(); |
- Memory::Address_at(entry) = substitution_entry; |
- } |
- } |
- |
- void VisitCodeTarget(RelocInfo* rinfo) override { |
- if (RelocInfo::IsCodeTarget(rinfo->rmode()) && |
- Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) { |
- Address substitution_entry = substitution_->instruction_start(); |
- rinfo->set_target_address(substitution_entry); |
- } |
- } |
- |
- void VisitDebugTarget(RelocInfo* rinfo) override { VisitCodeTarget(rinfo); } |
- |
- private: |
- Code* original_; |
- Code* substitution_; |
-}; |
- |
- |
// Finds all references to original and replaces them with substitution. |
static void ReplaceCodeObject(Handle<Code> original, |
Handle<Code> substitution) { |
@@ -796,20 +729,16 @@ static void ReplaceCodeObject(Handle<Code> original, |
// write barriers. |
Heap* heap = original->GetHeap(); |
HeapIterator iterator(heap); |
- |
- DCHECK(!heap->InNewSpace(*substitution)); |
- |
- ReplacingVisitor visitor(*original, *substitution); |
- |
- // Iterate over all roots. Stack frames may have pointer into original code, |
- // so temporary replace the pointers with offset numbers |
- // in prologue/epilogue. |
- heap->IterateRoots(&visitor, VISIT_ALL); |
- |
// Now iterate over all pointers of all objects, including code_target |
// implicit pointers. |
for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { |
- obj->Iterate(&visitor); |
+ if (obj->IsJSFunction()) { |
+ JSFunction* fun = JSFunction::cast(obj); |
+ if (fun->code() == *original) fun->ReplaceCode(*substitution); |
+ } else if (obj->IsSharedFunctionInfo()) { |
+ SharedFunctionInfo* info = SharedFunctionInfo::cast(obj); |
+ if (info->code() == *original) info->set_code(*substitution); |
+ } |
} |
} |
@@ -1277,185 +1206,6 @@ static bool CheckActivation(Handle<JSArray> shared_info_array, |
return false; |
} |
- |
-// Iterates over handler chain and removes all elements that are inside |
-// frames being dropped. |
-static bool FixTryCatchHandler(StackFrame* top_frame, |
- StackFrame* bottom_frame) { |
- Address* pointer_address = |
- &Memory::Address_at(top_frame->isolate()->get_address_from_id( |
- Isolate::kHandlerAddress)); |
- |
- while (*pointer_address < top_frame->sp()) { |
- pointer_address = &Memory::Address_at(*pointer_address); |
- } |
- Address* above_frame_address = pointer_address; |
- while (*pointer_address < bottom_frame->fp()) { |
- pointer_address = &Memory::Address_at(*pointer_address); |
- } |
- bool change = *above_frame_address != *pointer_address; |
- *above_frame_address = *pointer_address; |
- return change; |
-} |
- |
- |
-// Initializes an artificial stack frame. The data it contains is used for: |
-// a. successful work of frame dropper code which eventually gets control, |
-// b. being compatible with a typed frame structure for various stack |
-// iterators. |
-// Frame structure (conforms to InternalFrame structure): |
-// -- function |
-// -- code |
-// -- SMI marker |
-// -- frame base |
-static void SetUpFrameDropperFrame(StackFrame* bottom_js_frame, |
- Handle<Code> code) { |
- DCHECK(bottom_js_frame->is_java_script()); |
- Address fp = bottom_js_frame->fp(); |
- Memory::Object_at(fp + FrameDropperFrameConstants::kFunctionOffset) = |
- Memory::Object_at(fp + StandardFrameConstants::kFunctionOffset); |
- Memory::Object_at(fp + FrameDropperFrameConstants::kFrameTypeOffset) = |
- Smi::FromInt(StackFrame::INTERNAL); |
- Memory::Object_at(fp + FrameDropperFrameConstants::kCodeOffset) = *code; |
-} |
- |
- |
-// Removes specified range of frames from stack. There may be 1 or more |
-// frames in range. Anyway the bottom frame is restarted rather than dropped, |
-// and therefore has to be a JavaScript frame. |
-// Returns error message or NULL. |
-static const char* DropFrames(Vector<StackFrame*> frames, int top_frame_index, |
- int bottom_js_frame_index, |
- LiveEditFrameDropMode* mode) { |
- if (!LiveEdit::kFrameDropperSupported) { |
- return "Stack manipulations are not supported in this architecture."; |
- } |
- |
- StackFrame* pre_top_frame = frames[top_frame_index - 1]; |
- StackFrame* top_frame = frames[top_frame_index]; |
- StackFrame* bottom_js_frame = frames[bottom_js_frame_index]; |
- |
- DCHECK(bottom_js_frame->is_java_script()); |
- |
- // Check the nature of the top frame. |
- Isolate* isolate = bottom_js_frame->isolate(); |
- Code* pre_top_frame_code = pre_top_frame->LookupCode(); |
- bool frame_has_padding = true; |
- if (pre_top_frame_code == |
- isolate->builtins()->builtin(Builtins::kSlot_DebugBreak)) { |
- // OK, we can drop debug break slot. |
- *mode = LIVE_EDIT_FRAME_DROPPED_IN_DEBUG_SLOT_CALL; |
- } else if (pre_top_frame_code == |
- isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit)) { |
- // OK, we can drop our own code. |
- pre_top_frame = frames[top_frame_index - 2]; |
- top_frame = frames[top_frame_index - 1]; |
- *mode = LIVE_EDIT_CURRENTLY_SET_MODE; |
- frame_has_padding = false; |
- } else if (pre_top_frame_code == |
- isolate->builtins()->builtin(Builtins::kReturn_DebugBreak)) { |
- *mode = LIVE_EDIT_FRAME_DROPPED_IN_RETURN_CALL; |
- } else if (pre_top_frame_code->kind() == Code::STUB && |
- CodeStub::GetMajorKey(pre_top_frame_code) == CodeStub::CEntry) { |
- // Entry from our unit tests on 'debugger' statement. |
- // It's fine, we support this case. |
- *mode = LIVE_EDIT_FRAME_DROPPED_IN_DIRECT_CALL; |
- // We don't have a padding from 'debugger' statement call. |
- // Here the stub is CEntry, it's not debug-only and can't be padded. |
- // If anyone would complain, a proxy padded stub could be added. |
- frame_has_padding = false; |
- } else if (pre_top_frame->type() == StackFrame::ARGUMENTS_ADAPTOR) { |
- // This must be adaptor that remain from the frame dropping that |
- // is still on stack. A frame dropper frame must be above it. |
- DCHECK(frames[top_frame_index - 2]->LookupCode() == |
- isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit)); |
- pre_top_frame = frames[top_frame_index - 3]; |
- top_frame = frames[top_frame_index - 2]; |
- *mode = LIVE_EDIT_CURRENTLY_SET_MODE; |
- frame_has_padding = false; |
- } else if (pre_top_frame_code->kind() == Code::BYTECODE_HANDLER) { |
- // Interpreted bytecode takes up two stack frames, one for the bytecode |
- // handler and one for the interpreter entry trampoline. Therefore we shift |
- // up by one frame. |
- *mode = LIVE_EDIT_FRAME_DROPPED_IN_DIRECT_CALL; |
- pre_top_frame = frames[top_frame_index - 2]; |
- top_frame = frames[top_frame_index - 1]; |
- } else { |
- return "Unknown structure of stack above changing function"; |
- } |
- |
- Address unused_stack_top = top_frame->sp(); |
- Address unused_stack_bottom = |
- bottom_js_frame->fp() - FrameDropperFrameConstants::kFixedFrameSize + |
- 2 * kPointerSize; // Bigger address end is exclusive. |
- |
- Address* top_frame_pc_address = top_frame->pc_address(); |
- |
- // top_frame may be damaged below this point. Do not used it. |
- DCHECK(!(top_frame = NULL)); |
- |
- if (unused_stack_top > unused_stack_bottom) { |
- if (frame_has_padding) { |
- int shortage_bytes = |
- static_cast<int>(unused_stack_top - unused_stack_bottom); |
- |
- Address padding_start = |
- pre_top_frame->fp() - |
- (FrameDropperFrameConstants::kFixedFrameSize - kPointerSize); |
- |
- Address padding_pointer = padding_start; |
- Smi* padding_object = Smi::FromInt(LiveEdit::kFramePaddingValue); |
- while (Memory::Object_at(padding_pointer) == padding_object) { |
- padding_pointer -= kPointerSize; |
- } |
- int padding_counter = |
- Smi::cast(Memory::Object_at(padding_pointer))->value(); |
- if (padding_counter * kPointerSize < shortage_bytes) { |
- return "Not enough space for frame dropper frame " |
- "(even with padding frame)"; |
- } |
- Memory::Object_at(padding_pointer) = |
- Smi::FromInt(padding_counter - shortage_bytes / kPointerSize); |
- |
- StackFrame* pre_pre_frame = frames[top_frame_index - 2]; |
- |
- MemMove(padding_start + kPointerSize - shortage_bytes, |
- padding_start + kPointerSize, |
- FrameDropperFrameConstants::kFixedFrameSize - kPointerSize); |
- |
- pre_top_frame->UpdateFp(pre_top_frame->fp() - shortage_bytes); |
- pre_pre_frame->SetCallerFp(pre_top_frame->fp()); |
- unused_stack_top -= shortage_bytes; |
- |
- STATIC_ASSERT(sizeof(Address) == kPointerSize); |
- top_frame_pc_address -= shortage_bytes / kPointerSize; |
- } else { |
- return "Not enough space for frame dropper frame"; |
- } |
- } |
- |
- // Committing now. After this point we should return only NULL value. |
- |
- FixTryCatchHandler(pre_top_frame, bottom_js_frame); |
- // Make sure FixTryCatchHandler is idempotent. |
- DCHECK(!FixTryCatchHandler(pre_top_frame, bottom_js_frame)); |
- |
- Handle<Code> code = isolate->builtins()->FrameDropper_LiveEdit(); |
- *top_frame_pc_address = code->entry(); |
- pre_top_frame->SetCallerFp(bottom_js_frame->fp()); |
- |
- SetUpFrameDropperFrame(bottom_js_frame, code); |
- |
- for (Address a = unused_stack_top; |
- a < unused_stack_bottom; |
- a += kPointerSize) { |
- Memory::Object_at(a) = Smi::kZero; |
- } |
- |
- return NULL; |
-} |
- |
- |
// Describes a set of call frames that execute any of listed functions. |
// Finding no such frames does not mean error. |
class MultipleFunctionTarget { |
@@ -1543,7 +1293,6 @@ static const char* DropActivationsInActiveThreadImpl(Isolate* isolate, |
Zone zone(isolate->allocator(), ZONE_NAME); |
Vector<StackFrame*> frames = CreateStackMap(isolate, &zone); |
- |
int top_frame_index = -1; |
int frame_index = 0; |
for (; frame_index < frames.length(); frame_index++) { |
@@ -1628,24 +1377,11 @@ static const char* DropActivationsInActiveThreadImpl(Isolate* isolate, |
return target.GetNotFoundMessage(); |
} |
- LiveEditFrameDropMode drop_mode = LIVE_EDIT_FRAMES_UNTOUCHED; |
- const char* error_message = |
- DropFrames(frames, top_frame_index, bottom_js_frame_index, &drop_mode); |
- |
- if (error_message != NULL) { |
- return error_message; |
+ if (!LiveEdit::kFrameDropperSupported) { |
+ return "Stack manipulations are not supported in this architecture."; |
} |
- // Adjust break_frame after some frames has been dropped. |
- StackFrame::Id new_id = StackFrame::NO_ID; |
- for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) { |
- if (frames[i]->type() == StackFrame::JAVA_SCRIPT || |
- frames[i]->type() == StackFrame::INTERPRETED) { |
- new_id = frames[i]->id(); |
- break; |
- } |
- } |
- debug->FramesHaveBeenDropped(new_id, drop_mode); |
+ debug->ScheduleFrameRestart(frames[bottom_js_frame_index]); |
return NULL; |
} |