Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
deps: revert removal of V8::PromiseEvent
The removal of the promise debug event is an API/ABI breaking change.

Ref: https://codereview.chromium.org/1833563002
Ref: ofrobots#23

PR-URL: #7016
Reviewed-By: Ali Ijaz Sheikh <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
  • Loading branch information
Matt Loring authored and ofrobots committed Aug 25, 2016
commit 06a6c03e573ac49583fc865cecf91dd9a9fcdf3e
6 changes: 4 additions & 2 deletions deps/v8/include/v8-debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ enum DebugEvent {
Exception = 2,
NewFunction = 3,
BeforeCompile = 4,
AfterCompile = 5,
AfterCompile = 5,
CompileError = 6,
AsyncTaskEvent = 7,
PromiseEvent = 7,
AsyncTaskEvent = 8,
};


class V8_EXPORT Debug {
public:
/**
Expand Down
27 changes: 27 additions & 0 deletions deps/v8/src/debug/debug.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1708,6 +1708,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 CallFunction("MakePromiseEvent", arraysize(argv), argv);
}


MaybeHandle<Object> Debug::MakeAsyncTaskEvent(Handle<JSObject> task_event) {
// Create the async task event object.
Handle<Object> argv[] = { task_event };
Expand Down Expand Up @@ -1838,6 +1845,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::OnAsyncTaskEvent(Handle<JSObject> data) {
if (in_debug_scope() || ignore_events()) return;

Expand Down Expand Up @@ -1987,6 +2013,7 @@ void Debug::NotifyMessageHandler(v8::DebugEvent event,
case v8::NewFunction:
case v8::BeforeCompile:
case v8::CompileError:
case v8::PromiseEvent:
case v8::AsyncTaskEvent:
break;
case v8::Exception:
Expand Down
3 changes: 3 additions & 0 deletions deps/v8/src/debug/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ class Debug {
void OnCompileError(Handle<Script> script);
void OnBeforeCompile(Handle<Script> script);
void OnAfterCompile(Handle<Script> script);
void OnPromiseEvent(Handle<JSObject> data);
void OnAsyncTaskEvent(Handle<JSObject> data);

// API facing.
Expand Down Expand Up @@ -579,6 +580,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);
MUST_USE_RESULT MaybeHandle<Object> MakeAsyncTaskEvent(
Handle<JSObject> task_event);

Expand Down
37 changes: 36 additions & 1 deletion deps/v8/src/debug/debug.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ Debug.DebugEvent = { Break: 1,
BeforeCompile: 4,
AfterCompile: 5,
CompileError: 6,
AsyncTaskEvent: 7 };
PromiseEvent: 7,
AsyncTaskEvent: 8 };

// Types of exceptions that can be broken upon.
Debug.ExceptionBreak = { Caught : 0,
Expand Down Expand Up @@ -1140,6 +1141,39 @@ function MakeScriptObject_(script, include_source) {
}


function MakePromiseEvent(event_data) {
return new PromiseEvent(event_data);
}


function PromiseEvent(event_data) {
this.promise_ = event_data.promise;
this.parentPromise_ = event_data.parentPromise;
this.status_ = event_data.status;
this.value_ = event_data.value;
}


PromiseEvent.prototype.promise = function() {
return MakeMirror(this.promise_);
}


PromiseEvent.prototype.parentPromise = function() {
return MakeMirror(this.parentPromise_);
}


PromiseEvent.prototype.status = function() {
return this.status_;
}


PromiseEvent.prototype.value = function() {
return MakeMirror(this.value_);
}


function MakeAsyncTaskEvent(event_data) {
return new AsyncTaskEvent(event_data);
}
Expand Down Expand Up @@ -2483,6 +2517,7 @@ utils.InstallFunctions(utils, DONT_ENUM, [
"MakeExceptionEvent", MakeExceptionEvent,
"MakeBreakEvent", MakeBreakEvent,
"MakeCompileEvent", MakeCompileEvent,
"MakePromiseEvent", MakePromiseEvent,
"MakeAsyncTaskEvent", MakeAsyncTaskEvent,
"IsBreakPointTriggered", IsBreakPointTriggered,
"UpdateScriptBreakPoints", UpdateScriptBreakPoints,
Expand Down
6 changes: 6 additions & 0 deletions deps/v8/src/js/promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ function PromiseSet(promise, status, value, onResolve, onReject) {
SET_PRIVATE(promise, promiseValueSymbol, value);
SET_PRIVATE(promise, promiseOnResolveSymbol, onResolve);
SET_PRIVATE(promise, promiseOnRejectSymbol, onReject);
if (DEBUG_IS_ACTIVE) {
%DebugPromiseEvent({ promise: promise, status: status, value: value });
}
return promise;
}

Expand Down Expand Up @@ -303,6 +306,9 @@ function PromiseThen(onResolve, onReject) {
}
// Mark this promise as having handler.
SET_PRIVATE(this, promiseHasHandlerSymbol, true);
if (DEBUG_IS_ACTIVE) {
%DebugPromiseEvent({ promise: deferred.promise, parentPromise: this });
}
return deferred.promise;
}

Expand Down
9 changes: 9 additions & 0 deletions deps/v8/src/runtime/runtime-debug.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1635,6 +1635,15 @@ RUNTIME_FUNCTION(Runtime_DebugPopPromise) {
}


RUNTIME_FUNCTION(Runtime_DebugPromiseEvent) {
DCHECK(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_DebugAsyncTaskEvent) {
DCHECK(args.length() == 1);
HandleScope scope(isolate);
Expand Down
1 change: 1 addition & 0 deletions deps/v8/src/runtime/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ namespace internal {
F(DebugPrepareStepInIfStepping, 1, 1) \
F(DebugPushPromise, 2, 1) \
F(DebugPopPromise, 0, 1) \
F(DebugPromiseEvent, 1, 1) \
F(DebugAsyncTaskEvent, 1, 1) \
F(DebugIsActive, 0, 1) \
F(DebugBreakInOptimizedCode, 0, 1)
Expand Down
122 changes: 122 additions & 0 deletions deps/v8/test/mjsunit/es6/debug-promises/events.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// 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 eventsExpected = 16;
var exception = null;
var result = [];

function updatePromise(promise, parentPromise, status, value) {
var i;
for (i = 0; i < result.length; ++i) {
if (result[i].promise === promise) {
result[i].parentPromise = parentPromise || result[i].parentPromise;
result[i].status = status || result[i].status;
result[i].value = value || result[i].value;
break;
}
}
assertTrue(i < result.length);
}

function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.PromiseEvent) return;
try {
eventsExpected--;
assertTrue(event_data.promise().isPromise());
if (event_data.status() === 0) {
// New promise.
assertEquals("pending", event_data.promise().status());
result.push({ promise: event_data.promise().value(), status: 0 });
assertTrue(exec_state.frame(0).sourceLineText().indexOf("// event") > 0);
} else if (event_data.status() !== undefined) {
// Resolve/reject promise.
updatePromise(event_data.promise().value(),
undefined,
event_data.status(),
event_data.value().value());
} else {
// Chain promises.
assertTrue(event_data.parentPromise().isPromise());
updatePromise(event_data.promise().value(),
event_data.parentPromise().value());
assertTrue(exec_state.frame(0).sourceLineText().indexOf("// event") > 0);
}
} catch (e) {
print(e + e.stack)
exception = e;
}
}

Debug.setListener(listener);

function resolver(resolve, reject) { resolve(); }

var p1 = new Promise(resolver); // event
var p2 = p1.then().then(); // event
var p3 = new Promise(function(resolve, reject) { // event
reject("rejected");
});
var p4 = p3.then(); // event
var p5 = p1.then(); // event

function assertAsync(b, s) {
if (b) {
print(s, "succeeded");
} else {
%AbortJS(s + " FAILED!");
}
}

function testDone(iteration) {
function checkResult() {
if (eventsExpected === 0) {
assertAsync(result.length === 6, "result.length");

assertAsync(result[0].promise === p1, "result[0].promise");
assertAsync(result[0].parentPromise === undefined,
"result[0].parentPromise");
assertAsync(result[0].status === 1, "result[0].status");
assertAsync(result[0].value === undefined, "result[0].value");

assertAsync(result[1].parentPromise === p1,
"result[1].parentPromise");
assertAsync(result[1].status === 1, "result[1].status");

assertAsync(result[2].promise === p2, "result[2].promise");

assertAsync(result[3].promise === p3, "result[3].promise");
assertAsync(result[3].parentPromise === undefined,
"result[3].parentPromise");
assertAsync(result[3].status === -1, "result[3].status");
assertAsync(result[3].value === "rejected", "result[3].value");

assertAsync(result[4].promise === p4, "result[4].promise");
assertAsync(result[4].parentPromise === p3,
"result[4].parentPromise");
assertAsync(result[4].status === -1, "result[4].status");
assertAsync(result[4].value === "rejected", "result[4].value");

assertAsync(result[5].promise === p5, "result[5].promise");
assertAsync(result[5].parentPromise === p1,
"result[5].parentPromise");
assertAsync(result[5].status === 1, "result[5].status");

assertAsync(exception === null, "exception === null");
Debug.setListener(null);
} else if (iteration > 10) {
%AbortJS("Not all events were received!");
} else {
testDone(iteration + 1);
}
}

var iteration = iteration || 0;
%EnqueueMicrotask(checkResult);
}

testDone();
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 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 --allow-natives-syntax

// Test debug events when we listen to all exceptions and
// there is a catch handler for the exception thrown in a Promise.
// We expect a normal Exception debug event to be triggered.

Debug = debug.Debug;

var events = [];

function listener(event, exec_state, event_data, data) {
if (event == Debug.DebugEvent.PromiseEvent) events.push(event_data.status());
}

Debug.setListener(listener);

var p = new Promise(function(resolve, reject) {
do {
try {
throw new Error("reject");
} finally {
break; // No rethrow.
}
} while (false);
resolve();
});

assertEquals([0 /* create */, 1 /* resolve */], events);
29 changes: 29 additions & 0 deletions deps/v8/test/mjsunit/es6/debug-promises/resolve-after-try-catch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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 --allow-natives-syntax

// Test debug events when we listen to all exceptions and
// there is a catch handler for the exception thrown in a Promise.
// We expect a normal Exception debug event to be triggered.

Debug = debug.Debug;

var events = [];

function listener(event, exec_state, event_data, data) {
if (event == Debug.DebugEvent.PromiseEvent) events.push(event_data.status());
}

Debug.setListener(listener);

var p = new Promise(function (resolve, reject) {
try {
throw new Error("reject");
} catch (e) {
}
resolve();
});

assertEquals([0 /* create */, 1 /* resolve */], events);
30 changes: 30 additions & 0 deletions deps/v8/test/mjsunit/es6/debug-promises/rethrow-in-try-finally.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// 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 --allow-natives-syntax

// Test debug events when we listen to all exceptions and
// there is a catch handler for the exception thrown in a Promise.
// We expect a normal Exception debug event to be triggered.

Debug = debug.Debug;

var events = [];

function listener(event, exec_state, event_data, data) {
if (event == Debug.DebugEvent.PromiseEvent) events.push(event_data.status());
}

Debug.setListener(listener);

var p = new Promise(function(resolve, reject) {
try {
throw new Error("reject");
} finally {
// Implicit rethrow.
}
resolve();
});

assertEquals([0 /* create */, -1 /* rethrown */], events);