Index: src/runtime/runtime-debug.cc |
diff --git a/src/runtime/runtime-debug.cc b/src/runtime/runtime-debug.cc |
index 1ffaa5f95cab4d1e06d8f0b7b70b47c73c0068ec..8bdec1061b1f92af06c7938db61fdbe7d9b7c83c 100644 |
--- a/src/runtime/runtime-debug.cc |
+++ b/src/runtime/runtime-debug.cc |
@@ -1633,15 +1633,50 @@ |
} |
+// Check whether debugger is about to step into the callback that is passed |
+// to a built-in function such as Array.forEach. This check is done before |
+// %DebugPrepareStepInIfStepping and is not strictly necessary. However, if it |
+// returns false, we can skip %DebugPrepareStepInIfStepping, useful in loops. |
+RUNTIME_FUNCTION(Runtime_DebugCallbackSupportsStepping) { |
+ SealHandleScope shs(isolate); |
+ DCHECK(args.length() == 1); |
+ if (!DebugStepInIsActive(isolate->debug())) { |
+ return isolate->heap()->false_value(); |
+ } |
+ CONVERT_ARG_CHECKED(Object, object, 0); |
+ RUNTIME_ASSERT(object->IsJSFunction() || object->IsJSGeneratorObject()); |
+ // We do not step into the callback if it's a builtin other than a bound, |
+ // or not even a function. |
+ JSFunction* fun; |
+ if (object->IsJSFunction()) { |
+ fun = JSFunction::cast(object); |
+ } else { |
+ fun = JSGeneratorObject::cast(object)->function(); |
+ } |
+ return isolate->heap()->ToBoolean(fun->shared()->IsSubjectToDebugging() || |
+ fun->shared()->bound()); |
+} |
+ |
+ |
+void FloodDebugSubjectWithOneShot(Debug* debug, Handle<JSFunction> function) { |
+ if (function->shared()->IsSubjectToDebugging() || |
+ function->shared()->bound()) { |
+ // When leaving the function, step out has been activated, but not performed |
+ // if we do not leave the builtin. To be able to step into the function |
+ // again, we need to clear the step out at this point. |
+ debug->ClearStepOut(); |
+ debug->FloodWithOneShotGeneric(function); |
+ } |
+} |
+ |
+ |
// Set one shot breakpoints for the callback function that is passed to a |
// built-in function such as Array.forEach to enable stepping into the callback, |
// if we are indeed stepping and the callback is subject to debugging. |
RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) { |
DCHECK(args.length() == 1); |
Debug* debug = isolate->debug(); |
- if (debug->in_debug_scope() || !DebugStepInIsActive(debug)) { |
- return isolate->heap()->undefined_value(); |
- } |
+ if (!DebugStepInIsActive(debug)) return isolate->heap()->undefined_value(); |
HandleScope scope(isolate); |
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
@@ -1654,18 +1689,22 @@ |
Handle<JSGeneratorObject>::cast(object)->function(), isolate); |
} |
- debug->ClearStepOut(); |
- debug->FloodWithOneShotGeneric(fun); |
+ FloodDebugSubjectWithOneShot(debug, fun); |
return isolate->heap()->undefined_value(); |
} |
RUNTIME_FUNCTION(Runtime_DebugPushPromise) { |
- DCHECK(args.length() == 2); |
+ DCHECK(args.length() == 3); |
HandleScope scope(isolate); |
CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); |
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 1); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, handler, 2); |
isolate->PushPromise(promise, function); |
+ Debug* debug = isolate->debug(); |
+ if (handler->IsJSFunction() && DebugStepInIsActive(debug)) { |
+ FloodDebugSubjectWithOneShot(debug, Handle<JSFunction>::cast(handler)); |
+ } |
return isolate->heap()->undefined_value(); |
} |