| Index: src/debug/debug.cc
|
| diff --git a/src/debug/debug.cc b/src/debug/debug.cc
|
| index 654951870b97fc470d7e9b88ff90519a5904e572..7759d6cc3bbc57623abf8f33ca819e57b578fb78 100644
|
| --- a/src/debug/debug.cc
|
| +++ b/src/debug/debug.cc
|
| @@ -840,7 +840,8 @@ void Debug::FloodWithOneShot(Handle<JSFunction> function,
|
| // Debug utility functions are not subject to debugging.
|
| if (function->native_context() == *debug_context()) return;
|
|
|
| - if (!function->shared()->IsSubjectToDebugging()) {
|
| + if (!function->shared()->IsSubjectToDebugging() ||
|
| + IsBlackboxed(function->shared())) {
|
| // Builtin functions are not subject to stepping, but need to be
|
| // deoptimized, because optimized code does not check for debug
|
| // step in at call sites.
|
| @@ -959,7 +960,8 @@ void Debug::PrepareStepOnThrow() {
|
|
|
| // Find the closest Javascript frame we can flood with one-shots.
|
| while (!it.done() &&
|
| - !it.frame()->function()->shared()->IsSubjectToDebugging()) {
|
| + (!it.frame()->function()->shared()->IsSubjectToDebugging() ||
|
| + IsBlackboxed(it.frame()->function()->shared()))) {
|
| it.Advance();
|
| }
|
|
|
| @@ -1019,6 +1021,8 @@ void Debug::PrepareStep(StepAction step_action) {
|
| if (location.IsReturn()) step_action = StepOut;
|
| // A step-next at a tail call is a step-out.
|
| if (location.IsTailCall() && step_action == StepNext) step_action = StepOut;
|
| + // A step-next in blackboxed function is a step-out.
|
| + if (step_action == StepNext && IsBlackboxed(shared)) step_action = StepOut;
|
|
|
| thread_local_.last_statement_position_ =
|
| summary.abstract_code()->SourceStatementPosition(summary.code_offset());
|
| @@ -1034,8 +1038,10 @@ void Debug::PrepareStep(StepAction step_action) {
|
| // Advance to caller frame.
|
| frames_it.Advance();
|
| // Skip native and extension functions on the stack.
|
| - while (!frames_it.done() &&
|
| - !frames_it.frame()->function()->shared()->IsSubjectToDebugging()) {
|
| + while (
|
| + !frames_it.done() &&
|
| + (!frames_it.frame()->function()->shared()->IsSubjectToDebugging() ||
|
| + IsBlackboxed(frames_it.frame()->function()->shared()))) {
|
| // Builtin functions are not subject to stepping, but need to be
|
| // deoptimized to include checks for step-in at call sites.
|
| Deoptimizer::DeoptimizeFunction(frames_it.frame()->function());
|
| @@ -1751,15 +1757,18 @@ void Debug::OnException(Handle<Object> exception, Handle<Object> promise) {
|
| }
|
|
|
| {
|
| - // Check whether the break location is muted.
|
| JavaScriptFrameIterator it(isolate_);
|
| - if (!it.done() && IsMutedAtCurrentLocation(it.frame())) return;
|
| + // Check whether the top frame is blackboxed or the break location is muted.
|
| + if (!it.done() && (IsBlackboxed(it.frame()->function()->shared()) ||
|
| + IsMutedAtCurrentLocation(it.frame()))) {
|
| + return;
|
| + }
|
| }
|
|
|
| DebugScope debug_scope(this);
|
| if (debug_scope.failed()) return;
|
|
|
| - if (debug_event_listener_) {
|
| + if (debug_delegate_) {
|
| HandleScope scope(isolate_);
|
|
|
| // Create the execution state.
|
| @@ -1767,7 +1776,7 @@ void Debug::OnException(Handle<Object> exception, Handle<Object> promise) {
|
| // Bail out and don't call debugger if exception.
|
| if (!MakeExecutionState().ToHandle(&exec_state)) return;
|
|
|
| - debug_event_listener_->ExceptionThrown(
|
| + debug_delegate_->ExceptionThrown(
|
| GetDebugEventContext(isolate_),
|
| v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
|
| v8::Utils::ToLocal(exception), promise->IsJSObject(), uncaught);
|
| @@ -1797,7 +1806,7 @@ void Debug::OnDebugBreak(Handle<Object> break_points_hit) {
|
| PrintBreakLocation();
|
| #endif // DEBUG
|
|
|
| - if (debug_event_listener_) {
|
| + if (debug_delegate_) {
|
| HandleScope scope(isolate_);
|
|
|
| // Create the execution state.
|
| @@ -1807,7 +1816,7 @@ void Debug::OnDebugBreak(Handle<Object> break_points_hit) {
|
|
|
| bool previous = in_debug_event_listener_;
|
| in_debug_event_listener_ = true;
|
| - debug_event_listener_->BreakProgramRequested(
|
| + debug_delegate_->BreakProgramRequested(
|
| GetDebugEventContext(isolate_),
|
| v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
|
| v8::Utils::ToLocal(break_points_hit));
|
| @@ -1891,11 +1900,46 @@ int Debug::NextAsyncTaskId(Handle<JSObject> promise) {
|
| return async_id->value();
|
| }
|
|
|
| +namespace {
|
| +debug::Location GetDebugLocation(Handle<Script> script, int source_position) {
|
| + Script::PositionInfo info;
|
| + Script::GetPositionInfo(script, source_position, &info, Script::WITH_OFFSET);
|
| + return debug::Location(info.line, info.column);
|
| +}
|
| +} // namespace
|
| +
|
| +bool Debug::IsBlackboxed(SharedFunctionInfo* shared) {
|
| + HandleScope scope(isolate_);
|
| + Handle<SharedFunctionInfo> shared_function_info(shared);
|
| + return IsBlackboxed(shared_function_info);
|
| +}
|
| +
|
| +bool Debug::IsBlackboxed(Handle<SharedFunctionInfo> shared) {
|
| + if (!debug_delegate_) return false;
|
| + if (!shared->computed_debug_is_blackboxed()) {
|
| + bool is_blackboxed = false;
|
| + if (shared->script()->IsScript()) {
|
| + HandleScope handle_scope(isolate_);
|
| + Handle<Script> script(Script::cast(shared->script()));
|
| + if (script->type() == i::Script::TYPE_NORMAL) {
|
| + debug::Location start =
|
| + GetDebugLocation(script, shared->start_position());
|
| + debug::Location end = GetDebugLocation(script, shared->end_position());
|
| + is_blackboxed = debug_delegate_->IsFunctionBlackboxed(
|
| + ToApiHandle<debug::Script>(script), start, end);
|
| + }
|
| + }
|
| + shared->set_debug_is_blackboxed(is_blackboxed);
|
| + shared->set_computed_debug_is_blackboxed(true);
|
| + }
|
| + return shared->debug_is_blackboxed();
|
| +}
|
| +
|
| void Debug::OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id) {
|
| if (in_debug_scope() || ignore_events()) return;
|
|
|
| - if (debug_event_listener_) {
|
| - debug_event_listener_->PromiseEventOccurred(type, id);
|
| + if (debug_delegate_) {
|
| + debug_delegate_->PromiseEventOccurred(type, id);
|
| if (!non_inspector_listener_exists()) return;
|
| }
|
|
|
| @@ -1967,9 +2011,9 @@ void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) {
|
| DebugScope debug_scope(this);
|
| if (debug_scope.failed()) return;
|
|
|
| - if (debug_event_listener_) {
|
| - debug_event_listener_->ScriptCompiled(ToApiHandle<debug::Script>(script),
|
| - event != v8::AfterCompile);
|
| + if (debug_delegate_) {
|
| + debug_delegate_->ScriptCompiled(ToApiHandle<debug::Script>(script),
|
| + event != v8::AfterCompile);
|
| if (!non_inspector_listener_exists()) return;
|
| }
|
|
|
| @@ -2013,15 +2057,13 @@ void Debug::SetEventListener(Handle<Object> callback,
|
| UpdateState();
|
| }
|
|
|
| -
|
| -void Debug::SetDebugEventListener(debug::DebugEventListener* listener) {
|
| - debug_event_listener_ = listener;
|
| +void Debug::SetDebugDelegate(debug::DebugDelegate* delegate) {
|
| + debug_delegate_ = delegate;
|
| UpdateState();
|
| }
|
|
|
| void Debug::UpdateState() {
|
| - bool is_active =
|
| - !event_listener_.is_null() || debug_event_listener_ != nullptr;
|
| + bool is_active = !event_listener_.is_null() || debug_delegate_ != nullptr;
|
| if (is_active || in_debug_scope()) {
|
| // Note that the debug context could have already been loaded to
|
| // bootstrap test cases.
|
| @@ -2078,6 +2120,11 @@ void Debug::HandleDebugBreak() {
|
| if (fun && fun->IsJSFunction()) {
|
| // Don't stop in builtin functions.
|
| if (!JSFunction::cast(fun)->shared()->IsSubjectToDebugging()) return;
|
| + if (isolate_->stack_guard()->CheckDebugBreak() &&
|
| + IsBlackboxed(JSFunction::cast(fun)->shared())) {
|
| + Deoptimizer::DeoptimizeFunction(JSFunction::cast(fun));
|
| + return;
|
| + }
|
| JSGlobalObject* global =
|
| JSFunction::cast(fun)->context()->global_object();
|
| // Don't stop in debugger functions.
|
|
|