Introduce debug events for promises.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 30 Jun 2014 11:12:42 +0000 (11:12 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 30 Jun 2014 11:12:42 +0000 (11:12 +0000)
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

include/v8-debug.h
src/debug-debugger.js
src/debug.cc
src/debug.h
src/promise.js
src/runtime.cc
src/runtime.h
test/mjsunit/es6/debug-promises-new-event.js [new file with mode: 0644]
test/mjsunit/runtime-gen/debugpromiseevent.js [new file with mode: 0644]
tools/generate-runtime-tests.py

index 90d8544bec88625b186e0c479729c0ae2b7cfc73..dceb99716fed5169321f69d4b22fb4c7a56fcf92 100644 (file)
@@ -20,7 +20,8 @@ enum DebugEvent {
   BeforeCompile = 4,
   AfterCompile  = 5,
   CompileError = 6,
-  BreakForCommand = 7
+  PromiseEvent = 7,
+  BreakForCommand = 8
 };
 
 
index 5de829221a8392bac8102e2098c10ade132aff2f..8afac2e20af6c648b15a03d18c15c698ef5042ca 100644 (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;
index d99e6f54970accfd5b05e1aaea2afe3b10f42e68..a081127eabc6732d93ba2315351c26b678f4a7f7 100644 (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) {
index c295df2654bcf1b30c878d8a900386ba7becd430..cfd70590c27a49bb3da94cd48814e06a0b3c0956 100644 (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();
index 819074e62436a3724d3f07daa2561bd887e268ae..8214445c11a1e8e5f930aa31500e6c022724927e 100644 (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) },
index eba17a19437b86de7c502faf8f1f3d99cf2ba8f8..f341d144377b61cb4becec099cfd51c86aacc519 100644 (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);
index f01f173cfbf9b5c93599b23e603cc24870200309..ebc8598c876fbef46420c4769c5e8750ea9edaeb 100644 (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) \
diff --git a/test/mjsunit/es6/debug-promises-new-event.js b/test/mjsunit/es6/debug-promises-new-event.js
new file mode 100644 (file)
index 0000000..06a9774
--- /dev/null
@@ -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);
diff --git a/test/mjsunit/runtime-gen/debugpromiseevent.js b/test/mjsunit/runtime-gen/debugpromiseevent.js
new file mode 100644 (file)
index 0000000..8f5020b
--- /dev/null
@@ -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);
index 52b7dcb53bd39d8c2372107ca05505f297c0d958..f018cf044471eb3eb46470cff3536b64d5e9335b 100755 (executable)
@@ -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.