diff options
Diffstat (limited to 'deps/v8/src/debug.cc')
-rw-r--r-- | deps/v8/src/debug.cc | 226 |
1 files changed, 162 insertions, 64 deletions
diff --git a/deps/v8/src/debug.cc b/deps/v8/src/debug.cc index a229d39c3e..3d79485b57 100644 --- a/deps/v8/src/debug.cc +++ b/deps/v8/src/debug.cc @@ -40,6 +40,7 @@ #include "global-handles.h" #include "ic.h" #include "ic-inl.h" +#include "isolate-inl.h" #include "list.h" #include "messages.h" #include "natives.h" @@ -401,15 +402,15 @@ void BreakLocationIterator::PrepareStepIn() { // Step in can only be prepared if currently positioned on an IC call, // construct call or CallFunction stub call. Address target = rinfo()->target_address(); - Handle<Code> code(Code::GetCodeFromTargetAddress(target)); - if (code->is_call_stub() || code->is_keyed_call_stub()) { + Handle<Code> target_code(Code::GetCodeFromTargetAddress(target)); + if (target_code->is_call_stub() || target_code->is_keyed_call_stub()) { // Step in through IC call is handled by the runtime system. Therefore make // sure that the any current IC is cleared and the runtime system is // called. If the executing code has a debug break at the location change // the call in the original code as it is the code there that will be // executed in place of the debug break call. - Handle<Code> stub = ComputeCallDebugPrepareStepIn(code->arguments_count(), - code->kind()); + Handle<Code> stub = ComputeCallDebugPrepareStepIn( + target_code->arguments_count(), target_code->kind()); if (IsDebugBreak()) { original_rinfo()->set_target_address(stub->entry()); } else { @@ -419,7 +420,7 @@ void BreakLocationIterator::PrepareStepIn() { #ifdef DEBUG // All the following stuff is needed only for assertion checks so the code // is wrapped in ifdef. - Handle<Code> maybe_call_function_stub = code; + Handle<Code> maybe_call_function_stub = target_code; if (IsDebugBreak()) { Address original_target = original_rinfo()->target_address(); maybe_call_function_stub = @@ -436,8 +437,9 @@ void BreakLocationIterator::PrepareStepIn() { // Step in through CallFunction stub should also be prepared by caller of // this function (Debug::PrepareStep) which should flood target function // with breakpoints. - ASSERT(RelocInfo::IsConstructCall(rmode()) || code->is_inline_cache_stub() - || is_call_function_stub); + ASSERT(RelocInfo::IsConstructCall(rmode()) || + target_code->is_inline_cache_stub() || + is_call_function_stub); #endif } } @@ -474,11 +476,11 @@ void BreakLocationIterator::SetDebugBreakAtIC() { RelocInfo::Mode mode = rmode(); if (RelocInfo::IsCodeTarget(mode)) { Address target = rinfo()->target_address(); - Handle<Code> code(Code::GetCodeFromTargetAddress(target)); + Handle<Code> target_code(Code::GetCodeFromTargetAddress(target)); // Patch the code to invoke the builtin debug break function matching the // calling convention used by the call site. - Handle<Code> dbgbrk_code(Debug::FindDebugBreak(code, mode)); + Handle<Code> dbgbrk_code(Debug::FindDebugBreak(target_code, mode)); rinfo()->set_target_address(dbgbrk_code->entry()); } } @@ -772,7 +774,7 @@ bool Debug::CompileDebuggerScript(int index) { // Execute the shared function in the debugger context. Handle<Context> context = isolate->global_context(); - bool caught_exception = false; + bool caught_exception; Handle<JSFunction> function = factory->NewFunctionFromSharedFunctionInfo(function_info, context); @@ -1103,14 +1105,13 @@ bool Debug::CheckBreakPoint(Handle<Object> break_point_object) { Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id()); // Call HandleBreakPointx. - bool caught_exception = false; - const int argc = 2; - Object** argv[argc] = { - break_id.location(), - reinterpret_cast<Object**>(break_point_object.location()) - }; + bool caught_exception; + Handle<Object> argv[] = { break_id, break_point_object }; Handle<Object> result = Execution::TryCall(check_break_point, - isolate_->js_builtins_object(), argc, argv, &caught_exception); + isolate_->js_builtins_object(), + ARRAY_SIZE(argv), + argv, + &caught_exception); // If exception or non boolean result handle as not triggered if (caught_exception || !result->IsBoolean()) { @@ -1732,6 +1733,10 @@ void Debug::PrepareForBreakPoints() { if (!has_break_points_) { Deoptimizer::DeoptimizeAll(); + // We are going to iterate heap to find all functions without + // debug break slots. + isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask); + AssertNoAllocation no_allocation; Builtins* builtins = isolate_->builtins(); Code* lazy_compile = builtins->builtin(Builtins::kLazyCompile); @@ -1997,9 +2002,10 @@ void Debug::CreateScriptCache() { // Perform two GCs to get rid of all unreferenced scripts. The first GC gets // rid of all the cached script wrappers and the second gets rid of the - // scripts which are no longer referenced. - heap->CollectAllGarbage(false); - heap->CollectAllGarbage(false); + // scripts which are no longer referenced. The second also sweeps precisely, + // which saves us doing yet another GC to make the heap iterable. + heap->CollectAllGarbage(Heap::kNoGCFlags); + heap->CollectAllGarbage(Heap::kMakeHeapIterableMask); ASSERT(script_cache_ == NULL); script_cache_ = new ScriptCache(); @@ -2007,6 +2013,8 @@ void Debug::CreateScriptCache() { // Scan heap for Script objects. int count = 0; HeapIterator iterator; + AssertNoAllocation no_allocation; + for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { if (obj->IsScript() && Script::cast(obj)->HasValidSource()) { script_cache_->Add(Handle<Script>(Script::cast(obj))); @@ -2047,7 +2055,7 @@ Handle<FixedArray> Debug::GetLoadedScripts() { // Perform GC to get unreferenced scripts evicted from the cache before // returning the content. - isolate_->heap()->CollectAllGarbage(false); + isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags); // Get the scripts from the cache. return script_cache_->GetScripts(); @@ -2093,7 +2101,8 @@ Debugger::~Debugger() { Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name, - int argc, Object*** argv, + int argc, + Handle<Object> argv[], bool* caught_exception) { ASSERT(isolate_->context() == *isolate_->debug()->debug_context()); @@ -2110,7 +2119,9 @@ Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name, Handle<Object> js_object = Execution::TryCall( Handle<JSFunction>::cast(constructor), Handle<JSObject>(isolate_->debug()->debug_context()->global()), - argc, argv, caught_exception); + argc, + argv, + caught_exception); return js_object; } @@ -2119,10 +2130,11 @@ Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) { // Create the execution state object. Handle<Object> break_id = isolate_->factory()->NewNumberFromInt( isolate_->debug()->break_id()); - const int argc = 1; - Object** argv[argc] = { break_id.location() }; + Handle<Object> argv[] = { break_id }; return MakeJSObject(CStrVector("MakeExecutionState"), - argc, argv, caught_exception); + ARRAY_SIZE(argv), + argv, + caught_exception); } @@ -2130,11 +2142,9 @@ Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state, Handle<Object> break_points_hit, bool* caught_exception) { // Create the new break event object. - const int argc = 2; - Object** argv[argc] = { exec_state.location(), - break_points_hit.location() }; + Handle<Object> argv[] = { exec_state, break_points_hit }; return MakeJSObject(CStrVector("MakeBreakEvent"), - argc, + ARRAY_SIZE(argv), argv, caught_exception); } @@ -2146,23 +2156,24 @@ Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state, bool* caught_exception) { Factory* factory = isolate_->factory(); // Create the new exception event object. - const int argc = 3; - Object** argv[argc] = { exec_state.location(), - exception.location(), - uncaught ? factory->true_value().location() : - factory->false_value().location()}; + Handle<Object> argv[] = { exec_state, + exception, + factory->ToBoolean(uncaught) }; return MakeJSObject(CStrVector("MakeExceptionEvent"), - argc, argv, caught_exception); + ARRAY_SIZE(argv), + argv, + caught_exception); } Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function, bool* caught_exception) { // Create the new function event object. - const int argc = 1; - Object** argv[argc] = { function.location() }; + Handle<Object> argv[] = { function }; return MakeJSObject(CStrVector("MakeNewFunctionEvent"), - argc, argv, caught_exception); + ARRAY_SIZE(argv), + argv, + caught_exception); } @@ -2173,14 +2184,11 @@ Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script, // Create the compile event object. Handle<Object> exec_state = MakeExecutionState(caught_exception); Handle<Object> script_wrapper = GetScriptWrapper(script); - const int argc = 3; - Object** argv[argc] = { exec_state.location(), - script_wrapper.location(), - before ? factory->true_value().location() : - factory->false_value().location() }; - + Handle<Object> argv[] = { exec_state, + script_wrapper, + factory->ToBoolean(before) }; return MakeJSObject(CStrVector("MakeCompileEvent"), - argc, + ARRAY_SIZE(argv), argv, caught_exception); } @@ -2191,11 +2199,10 @@ Handle<Object> Debugger::MakeScriptCollectedEvent(int id, // Create the script collected event object. Handle<Object> exec_state = MakeExecutionState(caught_exception); Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id)); - const int argc = 2; - Object** argv[argc] = { exec_state.location(), id_object.location() }; + Handle<Object> argv[] = { exec_state, id_object }; return MakeJSObject(CStrVector("MakeScriptCollectedEvent"), - argc, + ARRAY_SIZE(argv), argv, caught_exception); } @@ -2345,12 +2352,13 @@ void Debugger::OnAfterCompile(Handle<Script> script, Handle<JSValue> wrapper = GetScriptWrapper(script); // Call UpdateScriptBreakPoints expect no exceptions. - bool caught_exception = false; - const int argc = 1; - Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) }; + bool caught_exception; + Handle<Object> argv[] = { wrapper }; Execution::TryCall(Handle<JSFunction>::cast(update_script_break_points), - Isolate::Current()->js_builtins_object(), argc, argv, - &caught_exception); + Isolate::Current()->js_builtins_object(), + ARRAY_SIZE(argv), + argv, + &caught_exception); if (caught_exception) { return; } @@ -2481,13 +2489,16 @@ void Debugger::CallJSEventCallback(v8::DebugEvent event, Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_)); // Invoke the JavaScript debug event listener. - const int argc = 4; - Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(), - exec_state.location(), - Handle<Object>::cast(event_data).location(), - event_listener_data_.location() }; - bool caught_exception = false; - Execution::TryCall(fun, isolate_->global(), argc, argv, &caught_exception); + Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event)), + exec_state, + event_data, + event_listener_data_ }; + bool caught_exception; + Execution::TryCall(fun, + isolate_->global(), + ARRAY_SIZE(argv), + argv, + &caught_exception); // Silently ignore exceptions from debug event listeners. } @@ -2856,12 +2867,11 @@ Handle<Object> Debugger::Call(Handle<JSFunction> fun, return isolate_->factory()->undefined_value(); } - static const int kArgc = 2; - Object** argv[kArgc] = { exec_state.location(), data.location() }; + Handle<Object> argv[] = { exec_state, data }; Handle<Object> result = Execution::Call( fun, Handle<Object>(isolate_->debug()->debug_context_->global_proxy()), - kArgc, + ARRAY_SIZE(argv), argv, pending_exception); return result; @@ -2929,6 +2939,94 @@ void Debugger::CallMessageDispatchHandler() { } +EnterDebugger::EnterDebugger() + : isolate_(Isolate::Current()), + prev_(isolate_->debug()->debugger_entry()), + it_(isolate_), + has_js_frames_(!it_.done()), + save_(isolate_) { + Debug* debug = isolate_->debug(); + ASSERT(prev_ != NULL || !debug->is_interrupt_pending(PREEMPT)); + ASSERT(prev_ != NULL || !debug->is_interrupt_pending(DEBUGBREAK)); + + // Link recursive debugger entry. + debug->set_debugger_entry(this); + + // Store the previous break id and frame id. + break_id_ = debug->break_id(); + break_frame_id_ = debug->break_frame_id(); + + // Create the new break info. If there is no JavaScript frames there is no + // break frame id. + if (has_js_frames_) { + debug->NewBreak(it_.frame()->id()); + } else { + debug->NewBreak(StackFrame::NO_ID); + } + + // Make sure that debugger is loaded and enter the debugger context. + load_failed_ = !debug->Load(); + if (!load_failed_) { + // NOTE the member variable save which saves the previous context before + // this change. + isolate_->set_context(*debug->debug_context()); + } +} + + +EnterDebugger::~EnterDebugger() { + ASSERT(Isolate::Current() == isolate_); + Debug* debug = isolate_->debug(); + + // Restore to the previous break state. + debug->SetBreak(break_frame_id_, break_id_); + + // Check for leaving the debugger. + if (prev_ == NULL) { + // Clear mirror cache when leaving the debugger. Skip this if there is a + // pending exception as clearing the mirror cache calls back into + // JavaScript. This can happen if the v8::Debug::Call is used in which + // case the exception should end up in the calling code. + if (!isolate_->has_pending_exception()) { + // Try to avoid any pending debug break breaking in the clear mirror + // cache JavaScript code. + if (isolate_->stack_guard()->IsDebugBreak()) { + debug->set_interrupts_pending(DEBUGBREAK); + isolate_->stack_guard()->Continue(DEBUGBREAK); + } + debug->ClearMirrorCache(); + } + + // Request preemption and debug break when leaving the last debugger entry + // if any of these where recorded while debugging. + if (debug->is_interrupt_pending(PREEMPT)) { + // This re-scheduling of preemption is to avoid starvation in some + // debugging scenarios. + debug->clear_interrupt_pending(PREEMPT); + isolate_->stack_guard()->Preempt(); + } + if (debug->is_interrupt_pending(DEBUGBREAK)) { + debug->clear_interrupt_pending(DEBUGBREAK); + isolate_->stack_guard()->DebugBreak(); + } + + // If there are commands in the queue when leaving the debugger request + // that these commands are processed. + if (isolate_->debugger()->HasCommands()) { + isolate_->stack_guard()->DebugCommand(); + } + + // If leaving the debugger with the debugger no longer active unload it. + if (!isolate_->debugger()->IsDebuggerActive()) { + isolate_->debugger()->UnloadDebugger(); + } + } + + // Leaving this debugger entry. + debug->set_debugger_entry(prev_); +} + + MessageImpl MessageImpl::NewEvent(DebugEvent event, bool running, Handle<JSObject> exec_state, |