From: aandrey Date: Tue, 18 Nov 2014 09:50:12 +0000 (-0800) Subject: Allow stepping into Promise handlers. X-Git-Tag: upstream/4.7.83~5651 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=407d1dfb87bd08b17ef2b30c0f0e0e4edcd02325;p=platform%2Fupstream%2Fv8.git Allow stepping into Promise handlers. BUG=chromium:432468 R=yangguo@chromium.org, adamk@chromium.org, arv@chromium.org LOG=N Review URL: https://codereview.chromium.org/734163002 Cr-Commit-Position: refs/heads/master@{#25389} --- diff --git a/src/debug.cc b/src/debug.cc index 3029adb..f5c2cbb 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -1199,6 +1199,9 @@ void Debug::ClearAllBreakPoints() { void Debug::FloodWithOneShot(Handle function, BreakLocatorType type) { + // Do not ever break in native functions. + if (function->IsFromNativeScript()) return; + PrepareForBreakPoints(); // Make sure the function is compiled and has set up the debug info. @@ -1249,7 +1252,7 @@ void Debug::FloodWithOneShotGeneric(Handle function, FloodBoundFunctionWithOneShot(function); } else if (function->shared()->is_default_constructor()) { FloodDefaultConstructorWithOneShot(function); - } else if (!function->IsFromNativeScript()) { + } else { Isolate* isolate = function->GetIsolate(); // Don't allow step into functions in the native context. if (function->shared()->code() == diff --git a/src/macros.py b/src/macros.py index d8741f7..e8572e6 100644 --- a/src/macros.py +++ b/src/macros.py @@ -291,3 +291,5 @@ const ITERATOR_KIND_ENTRIES = 3; # Check whether debug is active. const 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); diff --git a/src/promise.js b/src/promise.js index 443a3b8..7d5be88 100644 --- a/src/promise.js +++ b/src/promise.js @@ -103,6 +103,7 @@ var lastMicrotaskId = 0; function PromiseHandle(value, handler, deferred) { try { %DebugPushPromise(deferred.promise); + DEBUG_PREPARE_STEP_IN_IF_STEPPING(handler); var result = handler(value); if (result === deferred.promise) throw MakeTypeError('promise_cyclic', [result]); @@ -270,8 +271,15 @@ var lastMicrotaskId = 0; this, function(x) { x = PromiseCoerce(constructor, x); - return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) : - IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x); + if (x === that) { + DEBUG_PREPARE_STEP_IN_IF_STEPPING(onReject); + return onReject(MakeTypeError('promise_cyclic', [x])); + } else if (IsPromise(x)) { + return x.then(onResolve, onReject); + } else { + DEBUG_PREPARE_STEP_IN_IF_STEPPING(onResolve); + return onResolve(x); + } }, onReject, PromiseChain diff --git a/test/mjsunit/es6/debug-stepin-promises.js b/test/mjsunit/es6/debug-stepin-promises.js new file mode 100644 index 0000000..2db6b66 --- /dev/null +++ b/test/mjsunit/es6/debug-stepin-promises.js @@ -0,0 +1,80 @@ +// Copyright 2014 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: --allow-natives-syntax --expose-debug-as debug + +Debug = debug.Debug +var exception = null; +var break_count = 0; +var expected_breaks = 7; + +function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + assertTrue(exec_state.frameCount() != 0, "FAIL: Empty stack trace"); + var source = exec_state.frame(0).sourceLineText(); + print("paused at: " + source); + assertTrue(source.indexOf("// Break " + break_count + ".") > 0, + "Unexpected pause at: " + source); + if (source.indexOf("StepOver.") !== -1) { + exec_state.prepareStep(Debug.StepAction.StepNext, 1); + } else { + exec_state.prepareStep(Debug.StepAction.StepIn, 1); + } + ++break_count; + } else if (event == Debug.DebugEvent.AsyncTaskEvent && + event_data.type() === "willHandle" && + event_data.name() !== "Object.observe" && + break_count > 0) { + exec_state.prepareStep(Debug.StepAction.StepIn, 1); + } + } catch (e) { + exception = e; + print(e, e.stack); + } +}; + +Debug.setListener(listener); + +Promise.resolve(42) + .then(promise1) + .then(Object) // Should skip stepping into native. + .then(Boolean) // Should skip stepping into native. + .then(promise2) + .then(undefined, promise3) + .catch(function(e) { + %AbortJS("FAIL: uncaught exception " + e); + }); + +function promise1() +{ + debugger; // Break 0. + return exception || 1; // Break 1. +} // Break 2. + +function promise2() +{ + throw new Error; // Break 3. +} + +function promise3() +{ + finalize(); // Break 4. StepOver. + return break_count; // Break 5. +} // Break 6. + +function finalize() +{ + var dummy = {}; + Object.observe(dummy, function() { + if (expected_breaks !== break_count) { + %AbortJS("FAIL: expected <" + expected_breaks + "> breaks instead of <" + + break_count + ">"); + } + if (exception !== null) { + %AbortJS("FAIL: exception: " + exception); + } + }); + dummy.foo = 1; +}