Introduce debug events for promises.

R=aandrey@chromium.org, rossberg@chromium.org
BUG=v8:3093
LOG=Y

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22086 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
yangguo@chromium.org 2014-06-30 11:12:42 +00:00
parent 7aa8cb462f
commit f6c4178aa7
10 changed files with 122 additions and 5 deletions

View File

@ -20,7 +20,8 @@ enum DebugEvent {
BeforeCompile = 4,
AfterCompile = 5,
CompileError = 6,
BreakForCommand = 7
PromiseEvent = 7,
BreakForCommand = 8
};

View File

@ -19,7 +19,8 @@ Debug.DebugEvent = { Break: 1,
NewFunction: 3,
BeforeCompile: 4,
AfterCompile: 5,
CompileError: 6 };
CompileError: 6,
PromiseEvent: 7 };
// Types of exceptions that can be broken upon.
Debug.ExceptionBreak = { Caught : 0,
@ -1199,6 +1200,32 @@ function MakeScriptObject_(script, include_source) {
}
function MakePromiseEvent(event_data) {
if (event_data.type = "new Promise") {
return new NewPromiseEvent(event_data);
}
}
function PromiseGetter() {
return MakeMirror(this.promise_);
}
function NewPromiseEvent(event_data) {
this.resolver_ = event_data.resolver;
this.promise_ = event_data.promise;
}
NewPromiseEvent.prototype.promise = PromiseGetter;
NewPromiseEvent.prototype.resolver = function() {
return MakeMirror(this.resolver_);
}
function DebugCommandProcessor(exec_state, opt_is_running) {
this.exec_state_ = exec_state;
this.running_ = opt_is_running || false;

View File

@ -2544,6 +2544,13 @@ MaybeHandle<Object> Debug::MakeCompileEvent(Handle<Script> script,
}
MaybeHandle<Object> Debug::MakePromiseEvent(Handle<JSObject> event_data) {
// Create the promise event object.
Handle<Object> argv[] = { event_data };
return MakeJSObject("MakePromiseEvent", ARRAY_SIZE(argv), argv);
}
void Debug::OnException(Handle<Object> exception, bool uncaught) {
if (in_debug_scope() || ignore_events()) return;
@ -2689,6 +2696,25 @@ void Debug::OnAfterCompile(Handle<Script> script) {
}
void Debug::OnPromiseEvent(Handle<JSObject> data) {
if (in_debug_scope() || ignore_events()) return;
HandleScope scope(isolate_);
DebugScope debug_scope(this);
if (debug_scope.failed()) return;
// Create the script collected state object.
Handle<Object> event_data;
// Bail out and don't call debugger if exception.
if (!MakePromiseEvent(data).ToHandle(&event_data)) return;
// Process debug event.
ProcessDebugEvent(v8::PromiseEvent,
Handle<JSObject>::cast(event_data),
true);
}
void Debug::ProcessDebugEvent(v8::DebugEvent event,
Handle<JSObject> event_data,
bool auto_continue) {

View File

@ -365,6 +365,7 @@ class Debug {
void OnCompileError(Handle<Script> script);
void OnBeforeCompile(Handle<Script> script);
void OnAfterCompile(Handle<Script> script);
void OnPromiseEvent(Handle<JSObject> data);
// API facing.
void SetEventListener(Handle<Object> callback, Handle<Object> data);
@ -535,6 +536,8 @@ class Debug {
Handle<Object> promise);
MUST_USE_RESULT MaybeHandle<Object> MakeCompileEvent(
Handle<Script> script, v8::DebugEvent type);
MUST_USE_RESULT MaybeHandle<Object> MakePromiseEvent(
Handle<JSObject> promise_event);
// Mirror cache handling.
void ClearMirrorCache();

View File

@ -38,6 +38,11 @@ var promiseRaw = GLOBAL_PRIVATE("Promise#raw");
if (!IS_SPEC_FUNCTION(resolver))
throw MakeTypeError('resolver_not_a_function', [resolver]);
var promise = PromiseInit(this);
if (DEBUG_IS_ACTIVE) {
%DebugPromiseEvent({ type : "new Promise",
promise: this,
resolver: resolver });
}
try {
%DebugPromiseHandlePrologue(function() { return promise });
resolver(function(x) { PromiseResolve(promise, x) },

View File

@ -5530,6 +5530,15 @@ RUNTIME_FUNCTION(Runtime_DebugPromiseHandleEpilogue) {
}
RUNTIME_FUNCTION(Runtime_DebugPromiseEvent) {
ASSERT(args.length() == 1);
HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0);
isolate->debug()->OnPromiseEvent(data);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_DeleteProperty) {
HandleScope scope(isolate);
ASSERT(args.length() == 3);

View File

@ -77,6 +77,7 @@ namespace internal {
F(DebugPrepareStepInIfStepping, 1, 1) \
F(DebugPromiseHandlePrologue, 1, 1) \
F(DebugPromiseHandleEpilogue, 0, 1) \
F(DebugPromiseEvent, 1, 1) \
F(FlattenString, 1, 1) \
F(LoadMutableDouble, 2, 1) \
F(TryMigrateInstance, 1, 1) \

View File

@ -0,0 +1,40 @@
// 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: --expose-debug-as debug
Debug = debug.Debug;
var exception = null;
var new_promise;
function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.PromiseEvent) return;
try {
assertTrue(event_data.resolver().isFunction());
assertEquals(resolver, event_data.resolver().value());
assertTrue(event_data.resolver().resolved());
assertEquals("resolver", event_data.resolver().name());
assertTrue(event_data.resolver().source().indexOf("Token") > 0);
assertTrue(event_data.promise().isPromise());
new_promise = event_data.promise().value();
assertEquals("pending", event_data.promise().status());
} catch (e) {
print(e + e.stack)
exception = e;
}
}
Debug.setListener(listener);
function resolver(resolve, reject) {
resolve(); // Token
}
var p = new Promise(resolver);
assertEquals(new_promise, p);
assertNull(exception);
Debug.setListener(null);

View File

@ -0,0 +1,5 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
// Flags: --allow-natives-syntax --harmony
var _data = new Object();
%DebugPromiseEvent(_data);

View File

@ -47,11 +47,11 @@ EXPAND_MACROS = [
# that the parser doesn't bit-rot. Change the values as needed when you add,
# remove or change runtime functions, but make sure we don't lose our ability
# to parse them!
EXPECTED_FUNCTION_COUNT = 415
EXPECTED_FUZZABLE_COUNT = 330
EXPECTED_FUNCTION_COUNT = 416
EXPECTED_FUZZABLE_COUNT = 331
EXPECTED_CCTEST_COUNT = 6
EXPECTED_UNKNOWN_COUNT = 4
EXPECTED_BUILTINS_COUNT = 806
EXPECTED_BUILTINS_COUNT = 809
# Don't call these at all.