Revision: 21658
Author:   [email protected]
Date:     Tue Jun  3 20:12:19 2014 UTC
Log:      Add API support for passing a C++ function as a microtask callback

This allows embedders to enqueue microtasks without having any v8::Context
handy, as happens in Blink in some cases (such as DOM mutations due to editing
triggering MutationObservers).

LOG=Y
[email protected]

Review URL: https://codereview.chromium.org/306053003
http://code.google.com/p/v8/source/detail?r=21658

Modified:
 /branches/bleeding_edge/include/v8.h
 /branches/bleeding_edge/src/api.cc
 /branches/bleeding_edge/src/isolate.cc
 /branches/bleeding_edge/src/isolate.h
 /branches/bleeding_edge/test/cctest/test-api.cc

=======================================
--- /branches/bleeding_edge/include/v8.h        Tue Jun  3 14:38:35 2014 UTC
+++ /branches/bleeding_edge/include/v8.h        Tue Jun  3 20:12:19 2014 UTC
@@ -3966,6 +3966,9 @@
 // --- Leave Script Callback ---
 typedef void (*CallCompletedCallback)();

+// --- Microtask Callback ---
+typedef void (*MicrotaskCallback)(void* data);
+
 // --- Failed Access Check Callback ---
 typedef void (*FailedAccessCheckCallback)(Local<Object> target,
                                           AccessType type,
@@ -4385,6 +4388,11 @@
    */
   void EnqueueMicrotask(Handle<Function> microtask);

+  /**
+   * Experimental: Enqueues the callback to the Microtask Work Queue
+   */
+  void EnqueueMicrotask(MicrotaskCallback microtask, void* data = NULL);
+
    /**
* Experimental: Controls whether the Microtask Work Queue is automatically
    * run when the script call depth decrements to zero.
=======================================
--- /branches/bleeding_edge/src/api.cc  Tue Jun  3 14:38:35 2014 UTC
+++ /branches/bleeding_edge/src/api.cc  Tue Jun  3 20:12:19 2014 UTC
@@ -6677,6 +6677,18 @@
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
   isolate->EnqueueMicrotask(Utils::OpenHandle(*microtask));
 }
+
+
+void Isolate::EnqueueMicrotask(MicrotaskCallback microtask, void* data) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  i::HandleScope scope(isolate);
+  i::Handle<i::CallHandlerInfo> callback_info =
+      i::Handle<i::CallHandlerInfo>::cast(
+          isolate->factory()->NewStruct(i::CALL_HANDLER_INFO_TYPE));
+  SET_FIELD_WRAPPED(callback_info, set_callback, microtask);
+  SET_FIELD_WRAPPED(callback_info, set_data, data);
+  isolate->EnqueueMicrotask(callback_info);
+}


 void Isolate::SetAutorunMicrotasks(bool autorun) {
=======================================
--- /branches/bleeding_edge/src/isolate.cc      Tue Jun  3 14:39:55 2014 UTC
+++ /branches/bleeding_edge/src/isolate.cc      Tue Jun  3 20:12:19 2014 UTC
@@ -2262,7 +2262,8 @@
 }


-void Isolate::EnqueueMicrotask(Handle<JSFunction> microtask) {
+void Isolate::EnqueueMicrotask(Handle<Object> microtask) {
+  ASSERT(microtask->IsJSFunction() || microtask->IsCallHandlerInfo());
   Handle<FixedArray> queue(heap()->microtask_queue(), this);
   int num_tasks = pending_microtask_count();
   ASSERT(num_tasks <= queue->length());
@@ -2301,18 +2302,30 @@

     for (int i = 0; i < num_tasks; i++) {
       HandleScope scope(this);
-      Handle<JSFunction> microtask(JSFunction::cast(queue->get(i)), this);
-      Handle<Object> exception;
-      MaybeHandle<Object> result = Execution::TryCall(
-          microtask, factory()->undefined_value(), 0, NULL, &exception);
-      // If execution is terminating, just bail out.
-      if (result.is_null() &&
-          !exception.is_null() &&
-          *exception == heap()->termination_exception()) {
-        // Clear out any remaining callbacks in the queue.
-        heap()->set_microtask_queue(heap()->empty_fixed_array());
-        set_pending_microtask_count(0);
-        return;
+      Handle<Object> microtask(queue->get(i), this);
+      if (microtask->IsJSFunction()) {
+        Handle<JSFunction> microtask_function =
+            Handle<JSFunction>::cast(microtask);
+        Handle<Object> exception;
+        MaybeHandle<Object> result = Execution::TryCall(
+            microtask_function, factory()->undefined_value(),
+            0, NULL, &exception);
+        // If execution is terminating, just bail out.
+        if (result.is_null() &&
+            !exception.is_null() &&
+            *exception == heap()->termination_exception()) {
+          // Clear out any remaining callbacks in the queue.
+          heap()->set_microtask_queue(heap()->empty_fixed_array());
+          set_pending_microtask_count(0);
+          return;
+        }
+      } else {
+        Handle<CallHandlerInfo> callback_info =
+            Handle<CallHandlerInfo>::cast(microtask);
+        v8::MicrotaskCallback callback =
+            v8::ToCData<v8::MicrotaskCallback>(callback_info->callback());
+        void* data = v8::ToCData<void*>(callback_info->data());
+        callback(data);
       }
     }
   }
=======================================
--- /branches/bleeding_edge/src/isolate.h       Tue Jun  3 08:12:43 2014 UTC
+++ /branches/bleeding_edge/src/isolate.h       Tue Jun  3 20:12:19 2014 UTC
@@ -1077,7 +1077,7 @@
   void RemoveCallCompletedCallback(CallCompletedCallback callback);
   void FireCallCompletedCallback();

-  void EnqueueMicrotask(Handle<JSFunction> microtask);
+  void EnqueueMicrotask(Handle<Object> microtask);
   void RunMicrotasks();

  private:
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Tue Jun 3 15:45:38 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-api.cc Tue Jun 3 20:12:19 2014 UTC
@@ -20687,6 +20687,14 @@
   v8::HandleScope scope(info.GetIsolate());
   CompileRun("ext2Calls++;");
 }
+
+
+void* g_passed_to_three = NULL;
+
+
+static void MicrotaskThree(void* data) {
+  g_passed_to_three = data;
+}


 TEST(EnqueueMicrotask) {
@@ -20722,6 +20730,25 @@
   CompileRun("1+1;");
   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
+
+  g_passed_to_three = NULL;
+  env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
+  CompileRun("1+1;");
+  CHECK_EQ(NULL, g_passed_to_three);
+  CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
+  CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
+
+  int dummy;
+  env->GetIsolate()->EnqueueMicrotask(
+      Function::New(env->GetIsolate(), MicrotaskOne));
+  env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
+  env->GetIsolate()->EnqueueMicrotask(
+      Function::New(env->GetIsolate(), MicrotaskTwo));
+  CompileRun("1+1;");
+  CHECK_EQ(&dummy, g_passed_to_three);
+  CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
+  CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
+  g_passed_to_three = NULL;
 }


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to