Commit 73c9be9b authored by yangguo's avatar yangguo Committed by Commit bot

Debugger: allow stepping into resolver from Promise constructor.

R=rossberg@chromium.org
BUG=chromium:451967
LOG=N

Review URL: https://codereview.chromium.org/1404783002

Cr-Commit-Position: refs/heads/master@{#31296}
parent dd3f1ecf
......@@ -1185,7 +1185,7 @@ function InnerArrayFilter(f, receiver, array, length) {
var accumulator = new InternalArray();
var accumulator_length = 0;
var is_array = IS_ARRAY(array);
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
var stepping = DEBUG_IS_STEPPING(f);
for (var i = 0; i < length; i++) {
if (HAS_INDEX(array, i, is_array)) {
var element = array[i];
......@@ -1216,7 +1216,7 @@ function InnerArrayForEach(f, receiver, array, length) {
if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
var is_array = IS_ARRAY(array);
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
var stepping = DEBUG_IS_STEPPING(f);
for (var i = 0; i < length; i++) {
if (HAS_INDEX(array, i, is_array)) {
var element = array[i];
......@@ -1242,7 +1242,7 @@ function InnerArraySome(f, receiver, array, length) {
if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
var is_array = IS_ARRAY(array);
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
var stepping = DEBUG_IS_STEPPING(f);
for (var i = 0; i < length; i++) {
if (HAS_INDEX(array, i, is_array)) {
var element = array[i];
......@@ -1272,7 +1272,7 @@ function InnerArrayEvery(f, receiver, array, length) {
if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
var is_array = IS_ARRAY(array);
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
var stepping = DEBUG_IS_STEPPING(f);
for (var i = 0; i < length; i++) {
if (HAS_INDEX(array, i, is_array)) {
var element = array[i];
......@@ -1300,7 +1300,7 @@ function InnerArrayMap(f, receiver, array, length) {
var accumulator = new InternalArray(length);
var is_array = IS_ARRAY(array);
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
var stepping = DEBUG_IS_STEPPING(f);
for (var i = 0; i < length; i++) {
if (HAS_INDEX(array, i, is_array)) {
var element = array[i];
......@@ -1469,7 +1469,7 @@ function InnerArrayReduce(callback, current, array, length, argumentsLength) {
throw MakeTypeError(kReduceNoInitial);
}
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(callback);
var stepping = DEBUG_IS_STEPPING(callback);
for (; i < length; i++) {
if (HAS_INDEX(array, i, is_array)) {
var element = array[i];
......@@ -1512,7 +1512,7 @@ function InnerArrayReduceRight(callback, current, array, length,
throw MakeTypeError(kReduceNoInitial);
}
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(callback);
var stepping = DEBUG_IS_STEPPING(callback);
for (; i >= 0; i--) {
if (HAS_INDEX(array, i, is_array)) {
var element = array[i];
......
......@@ -246,7 +246,7 @@ function SetForEach(f, receiver) {
var iterator = new SetIterator(this, ITERATOR_KIND_VALUES);
var key;
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
var stepping = DEBUG_IS_STEPPING(f);
var value_array = [UNDEFINED];
while (%SetIteratorNext(iterator, value_array)) {
if (stepping) %DebugPrepareStepInIfStepping(f);
......@@ -429,7 +429,7 @@ function MapForEach(f, receiver) {
if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
var iterator = new MapIterator(this, ITERATOR_KIND_ENTRIES);
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
var stepping = DEBUG_IS_STEPPING(f);
var value_array = [UNDEFINED, UNDEFINED];
while (%MapIteratorNext(iterator, value_array)) {
if (stepping) %DebugPrepareStepInIfStepping(f);
......
......@@ -33,7 +33,7 @@ function GeneratorObjectNext(value) {
var continuation = %GeneratorGetContinuation(this);
if (continuation > 0) {
// Generator is suspended.
if (DEBUG_IS_ACTIVE) %DebugPrepareStepInIfStepping(this);
DEBUG_PREPARE_STEP_IN_IF_STEPPING(this);
try {
return %_GeneratorNext(this, value);
} catch (e) {
......
......@@ -305,7 +305,7 @@ define NOT_FOUND = -1;
# Check whether debug is active.
define DEBUG_IS_ACTIVE = (%_DebugIsActive() != 0);
macro DEBUG_IS_STEPPING(function) = (%_DebugIsActive() != 0 && %DebugCallbackSupportsStepping(function));
macro DEBUG_PREPARE_STEP_IN_IF_STEPPING(function) = if (DEBUG_IS_STEPPING(function)) %DebugPrepareStepInIfStepping(function);
macro DEBUG_PREPARE_STEP_IN_IF_STEPPING(function) = if (%_DebugIsActive() != 0) %DebugPrepareStepInIfStepping(function);
# SharedFlag equivalents
define kNotShared = false;
......
......@@ -34,7 +34,7 @@ var GlobalPromise = function Promise(resolver) {
throw MakeTypeError(kResolverNotAFunction, resolver);
var promise = PromiseInit(this);
try {
%DebugPushPromise(promise, Promise);
%DebugPushPromise(promise, Promise, resolver);
resolver(function(x) { PromiseResolve(promise, x) },
function(r) { PromiseReject(promise, r) });
} catch (e) {
......@@ -100,8 +100,7 @@ function PromiseCoerce(constructor, x) {
function PromiseHandle(value, handler, deferred) {
try {
%DebugPushPromise(deferred.promise, PromiseHandle);
DEBUG_PREPARE_STEP_IN_IF_STEPPING(handler);
%DebugPushPromise(deferred.promise, PromiseHandle, handler);
var result = handler(value);
if (result === deferred.promise)
throw MakeTypeError(kPromiseCyclic, result);
......
......@@ -1612,33 +1612,55 @@ RUNTIME_FUNCTION(Runtime_GetScript) {
}
bool DebugStepInIsActive(Debug* debug) {
return debug->is_active() && debug->IsStepping() &&
debug->last_step_action() == StepIn;
}
// Check whether debugger is about to step into the callback that is passed
// to a built-in function such as Array.forEach.
// 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);
Debug* debug = isolate->debug();
if (!debug->is_active() || !debug->IsStepping() ||
debug->last_step_action() != StepIn) {
if (!DebugStepInIsActive(isolate->debug())) {
return isolate->heap()->false_value();
}
CONVERT_ARG_CHECKED(Object, callback, 0);
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.
return isolate->heap()->ToBoolean(
callback->IsJSFunction() &&
(JSFunction::cast(callback)->IsSubjectToDebugging() ||
JSFunction::cast(callback)->shared()->bound()));
JSFunction* fun;
if (object->IsJSFunction()) {
fun = JSFunction::cast(object);
} else {
fun = JSGeneratorObject::cast(object)->function();
}
return isolate->heap()->ToBoolean(fun->IsSubjectToDebugging() ||
fun->shared()->bound());
}
void FloodDebugSubjectWithOneShot(Debug* debug, Handle<JSFunction> function) {
if (function->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.
// 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);
RUNTIME_ASSERT(isolate->debug()->is_active());
Debug* debug = isolate->debug();
if (!debug->IsStepping()) return isolate->heap()->undefined_value();
if (!DebugStepInIsActive(debug)) return isolate->heap()->undefined_value();
HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
......@@ -1650,21 +1672,23 @@ RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) {
fun = Handle<JSFunction>(
Handle<JSGeneratorObject>::cast(object)->function(), isolate);
}
// 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(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();
}
......
......@@ -201,7 +201,7 @@ namespace internal {
F(GetScript, 1, 1) \
F(DebugCallbackSupportsStepping, 1, 1) \
F(DebugPrepareStepInIfStepping, 1, 1) \
F(DebugPushPromise, 2, 1) \
F(DebugPushPromise, 3, 1) \
F(DebugPopPromise, 0, 1) \
F(DebugPromiseEvent, 1, 1) \
F(DebugAsyncTaskEvent, 1, 1) \
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-debug-as debug
var Debug = debug.Debug;
var exception = null;
var breaks = [];
function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.Break) return;
try {
breaks.push(exec_state.frame(0).sourceLineText().trimLeft());
exec_state.prepareStep(Debug.StepAction.StepIn, 1);
} catch (e) {
exception = e;
}
}
Debug.setListener(listener);
function resolver(resolve, reject) {
1;
2;
3;
resolve();
}
debugger;
var p = new Promise(resolver);
Debug.setListener(null);
var expected_breaks = [
"debugger;",
"var p = new Promise(resolver);",
"1;",
"2;",
"3;",
"resolve();",
"}",
"Debug.setListener(null);"
];
assertEquals(expected_breaks, breaks);
assertNull(exception);
......@@ -10,7 +10,7 @@ Debug.setBreakOnException();
try {
try {
%DebugPushPromise(new Promise(function() {}), function() {});
%DebugPushPromise(new Promise(function() {}), function() {}, function() {});
} catch (e) {
}
throw new Error();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment