new gc callbacks with isolate parameters
authordcarney@chromium.org <dcarney@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 17 Sep 2013 12:37:22 +0000 (12:37 +0000)
committerdcarney@chromium.org <dcarney@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 17 Sep 2013 12:37:22 +0000 (12:37 +0000)
R=svenpanne@chromium.org
BUG=

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16770 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

include/v8.h
src/api.cc
src/heap.cc
src/heap.h
test/cctest/test-api.cc
test/cctest/test-mark-compact.cc

index 92bfa45..79f4478 100644 (file)
@@ -3871,8 +3871,6 @@ enum GCCallbackFlags {
 typedef void (*GCPrologueCallback)(GCType type, GCCallbackFlags flags);
 typedef void (*GCEpilogueCallback)(GCType type, GCCallbackFlags flags);
 
-typedef void (*GCCallback)();
-
 
 /**
  * Collection of V8 heap information.
@@ -4056,6 +4054,51 @@ class V8_EXPORT Isolate {
   void SetReference(const Persistent<Object>& parent,
                     const Persistent<Value>& child);
 
+  typedef void (*GCPrologueCallback)(Isolate* isolate,
+                                     GCType type,
+                                     GCCallbackFlags flags);
+  typedef void (*GCEpilogueCallback)(Isolate* isolate,
+                                     GCType type,
+                                     GCCallbackFlags flags);
+
+  /**
+   * Enables the host application to receive a notification before a
+   * garbage collection.  Allocations are not allowed in the
+   * callback function, you therefore cannot manipulate objects (set
+   * or delete properties for example) since it is possible such
+   * operations will result in the allocation of objects. It is possible
+   * to specify the GCType filter for your callback. But it is not possible to
+   * register the same callback function two times with different
+   * GCType filters.
+   */
+  void AddGCPrologueCallback(
+      GCPrologueCallback callback, GCType gc_type_filter = kGCTypeAll);
+
+  /**
+   * This function removes callback which was installed by
+   * AddGCPrologueCallback function.
+   */
+  void RemoveGCPrologueCallback(GCPrologueCallback callback);
+
+  /**
+   * Enables the host application to receive a notification after a
+   * garbage collection.  Allocations are not allowed in the
+   * callback function, you therefore cannot manipulate objects (set
+   * or delete properties for example) since it is possible such
+   * operations will result in the allocation of objects. It is possible
+   * to specify the GCType filter for your callback. But it is not possible to
+   * register the same callback function two times with different
+   * GCType filters.
+   */
+  void AddGCEpilogueCallback(
+      GCEpilogueCallback callback, GCType gc_type_filter = kGCTypeAll);
+
+  /**
+   * This function removes callback which was installed by
+   * AddGCEpilogueCallback function.
+   */
+  void RemoveGCEpilogueCallback(GCEpilogueCallback callback);
+
  private:
   Isolate();
   Isolate(const Isolate&);
@@ -4413,16 +4456,6 @@ class V8_EXPORT V8 {
   static void RemoveGCPrologueCallback(GCPrologueCallback callback);
 
   /**
-   * The function is deprecated. Please use AddGCPrologueCallback instead.
-   * Enables the host application to receive a notification before a
-   * garbage collection.  Allocations are not allowed in the
-   * callback function, you therefore cannot manipulate objects (set
-   * or delete properties for example) since it is possible such
-   * operations will result in the allocation of objects.
-   */
-  V8_DEPRECATED(static void SetGlobalGCPrologueCallback(GCCallback));
-
-  /**
    * Enables the host application to receive a notification after a
    * garbage collection.  Allocations are not allowed in the
    * callback function, you therefore cannot manipulate objects (set
@@ -4442,16 +4475,6 @@ class V8_EXPORT V8 {
   static void RemoveGCEpilogueCallback(GCEpilogueCallback callback);
 
   /**
-   * The function is deprecated. Please use AddGCEpilogueCallback instead.
-   * Enables the host application to receive a notification after a
-   * major garbage collection.  Allocations are not allowed in the
-   * callback function, you therefore cannot manipulate objects (set
-   * or delete properties for example) since it is possible such
-   * operations will result in the allocation of objects.
-   */
-  V8_DEPRECATED(static void SetGlobalGCEpilogueCallback(GCCallback));
-
-  /**
    * Enables the host application to provide a mechanism to be notified
    * and perform custom logging when V8 Allocates Executable Memory.
    */
index 45c9f04..e79b340 100644 (file)
@@ -6685,45 +6685,65 @@ void Isolate::SetReference(const Persistent<Object>& parent,
 }
 
 
-void V8::SetGlobalGCPrologueCallback(GCCallback callback) {
-  i::Isolate* isolate = i::Isolate::Current();
-  if (IsDeadCheck(isolate, "v8::V8::SetGlobalGCPrologueCallback()")) return;
-  isolate->heap()->SetGlobalGCPrologueCallback(callback);
+void Isolate::AddGCPrologueCallback(GCPrologueCallback callback,
+                                    GCType gc_type) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  isolate->heap()->AddGCPrologueCallback(callback, gc_type);
 }
 
 
-void V8::SetGlobalGCEpilogueCallback(GCCallback callback) {
-  i::Isolate* isolate = i::Isolate::Current();
-  if (IsDeadCheck(isolate, "v8::V8::SetGlobalGCEpilogueCallback()")) return;
-  isolate->heap()->SetGlobalGCEpilogueCallback(callback);
+void Isolate::RemoveGCPrologueCallback(GCPrologueCallback callback) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  isolate->heap()->RemoveGCPrologueCallback(callback);
+}
+
+
+void Isolate::AddGCEpilogueCallback(GCEpilogueCallback callback,
+                                    GCType gc_type) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  isolate->heap()->AddGCEpilogueCallback(callback, gc_type);
+}
+
+
+void Isolate::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  isolate->heap()->RemoveGCEpilogueCallback(callback);
 }
 
 
 void V8::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) {
   i::Isolate* isolate = i::Isolate::Current();
   if (IsDeadCheck(isolate, "v8::V8::AddGCPrologueCallback()")) return;
-  isolate->heap()->AddGCPrologueCallback(callback, gc_type);
+  isolate->heap()->AddGCPrologueCallback(
+      reinterpret_cast<v8::Isolate::GCPrologueCallback>(callback),
+      gc_type,
+      false);
 }
 
 
 void V8::RemoveGCPrologueCallback(GCPrologueCallback callback) {
   i::Isolate* isolate = i::Isolate::Current();
   if (IsDeadCheck(isolate, "v8::V8::RemoveGCPrologueCallback()")) return;
-  isolate->heap()->RemoveGCPrologueCallback(callback);
+  isolate->heap()->RemoveGCPrologueCallback(
+      reinterpret_cast<v8::Isolate::GCPrologueCallback>(callback));
 }
 
 
 void V8::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
   i::Isolate* isolate = i::Isolate::Current();
   if (IsDeadCheck(isolate, "v8::V8::AddGCEpilogueCallback()")) return;
-  isolate->heap()->AddGCEpilogueCallback(callback, gc_type);
+  isolate->heap()->AddGCEpilogueCallback(
+      reinterpret_cast<v8::Isolate::GCEpilogueCallback>(callback),
+      gc_type,
+      false);
 }
 
 
 void V8::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
   i::Isolate* isolate = i::Isolate::Current();
   if (IsDeadCheck(isolate, "v8::V8::RemoveGCEpilogueCallback()")) return;
-  isolate->heap()->RemoveGCEpilogueCallback(callback);
+  isolate->heap()->RemoveGCEpilogueCallback(
+      reinterpret_cast<v8::Isolate::GCEpilogueCallback>(callback));
 }
 
 
index 86c2b4a..b3e8cd7 100644 (file)
@@ -129,8 +129,6 @@ Heap::Heap()
       old_gen_exhausted_(false),
       store_buffer_rebuilder_(store_buffer()),
       hidden_string_(NULL),
-      global_gc_prologue_callback_(NULL),
-      global_gc_epilogue_callback_(NULL),
       gc_safe_size_of_old_object_(NULL),
       total_regexp_code_generated_(0),
       tracer_(NULL),
@@ -1055,12 +1053,17 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector,
 
 
 void Heap::CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags) {
-  if (gc_type == kGCTypeMarkSweepCompact && global_gc_prologue_callback_) {
-    global_gc_prologue_callback_();
-  }
   for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
     if (gc_type & gc_prologue_callbacks_[i].gc_type) {
-      gc_prologue_callbacks_[i].callback(gc_type, flags);
+      if (!gc_prologue_callbacks_[i].pass_isolate_) {
+        v8::GCPrologueCallback callback =
+            reinterpret_cast<v8::GCPrologueCallback>(
+                gc_prologue_callbacks_[i].callback);
+        callback(gc_type, flags);
+      } else {
+        v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate());
+        gc_prologue_callbacks_[i].callback(isolate, gc_type, flags);
+      }
     }
   }
 }
@@ -1069,12 +1072,18 @@ void Heap::CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags) {
 void Heap::CallGCEpilogueCallbacks(GCType gc_type) {
   for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
     if (gc_type & gc_epilogue_callbacks_[i].gc_type) {
-      gc_epilogue_callbacks_[i].callback(gc_type, kNoGCCallbackFlags);
+      if (!gc_epilogue_callbacks_[i].pass_isolate_) {
+        v8::GCPrologueCallback callback =
+            reinterpret_cast<v8::GCPrologueCallback>(
+                gc_epilogue_callbacks_[i].callback);
+        callback(gc_type, kNoGCCallbackFlags);
+      } else {
+        v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate());
+        gc_epilogue_callbacks_[i].callback(
+            isolate, gc_type, kNoGCCallbackFlags);
+      }
     }
   }
-  if (gc_type == kGCTypeMarkSweepCompact && global_gc_epilogue_callback_) {
-    global_gc_epilogue_callback_();
-  }
 }
 
 
@@ -7071,15 +7080,17 @@ void Heap::TearDown() {
 }
 
 
-void Heap::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) {
+void Heap::AddGCPrologueCallback(v8::Isolate::GCPrologueCallback callback,
+                                 GCType gc_type,
+                                 bool pass_isolate) {
   ASSERT(callback != NULL);
-  GCPrologueCallbackPair pair(callback, gc_type);
+  GCPrologueCallbackPair pair(callback, gc_type, pass_isolate);
   ASSERT(!gc_prologue_callbacks_.Contains(pair));
   return gc_prologue_callbacks_.Add(pair);
 }
 
 
-void Heap::RemoveGCPrologueCallback(GCPrologueCallback callback) {
+void Heap::RemoveGCPrologueCallback(v8::Isolate::GCPrologueCallback callback) {
   ASSERT(callback != NULL);
   for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
     if (gc_prologue_callbacks_[i].callback == callback) {
@@ -7091,15 +7102,17 @@ void Heap::RemoveGCPrologueCallback(GCPrologueCallback callback) {
 }
 
 
-void Heap::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
+void Heap::AddGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback,
+                                 GCType gc_type,
+                                 bool pass_isolate) {
   ASSERT(callback != NULL);
-  GCEpilogueCallbackPair pair(callback, gc_type);
+  GCEpilogueCallbackPair pair(callback, gc_type, pass_isolate);
   ASSERT(!gc_epilogue_callbacks_.Contains(pair));
   return gc_epilogue_callbacks_.Add(pair);
 }
 
 
-void Heap::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
+void Heap::RemoveGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback) {
   ASSERT(callback != NULL);
   for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
     if (gc_epilogue_callbacks_[i].callback == callback) {
index 4dfa076..2f91ebc 100644 (file)
@@ -1272,22 +1272,15 @@ class Heap {
   void GarbageCollectionGreedyCheck();
 #endif
 
-  void AddGCPrologueCallback(
-      GCPrologueCallback callback, GCType gc_type_filter);
-  void RemoveGCPrologueCallback(GCPrologueCallback callback);
+  void AddGCPrologueCallback(v8::Isolate::GCPrologueCallback callback,
+                             GCType gc_type_filter,
+                             bool pass_isolate = true);
+  void RemoveGCPrologueCallback(v8::Isolate::GCPrologueCallback callback);
 
-  void AddGCEpilogueCallback(
-      GCEpilogueCallback callback, GCType gc_type_filter);
-  void RemoveGCEpilogueCallback(GCEpilogueCallback callback);
-
-  void SetGlobalGCPrologueCallback(GCCallback callback) {
-    ASSERT((callback == NULL) ^ (global_gc_prologue_callback_ == NULL));
-    global_gc_prologue_callback_ = callback;
-  }
-  void SetGlobalGCEpilogueCallback(GCCallback callback) {
-    ASSERT((callback == NULL) ^ (global_gc_epilogue_callback_ == NULL));
-    global_gc_epilogue_callback_ = callback;
-  }
+  void AddGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback,
+                             GCType gc_type_filter,
+                             bool pass_isolate = true);
+  void RemoveGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback);
 
   // Heap root getters.  We have versions with and without type::cast() here.
   // You can't use type::cast during GC because the assert fails.
@@ -2032,32 +2025,37 @@ class Heap {
   // GC callback function, called before and after mark-compact GC.
   // Allocations in the callback function are disallowed.
   struct GCPrologueCallbackPair {
-    GCPrologueCallbackPair(GCPrologueCallback callback, GCType gc_type)
-        : callback(callback), gc_type(gc_type) {
+    GCPrologueCallbackPair(v8::Isolate::GCPrologueCallback callback,
+                           GCType gc_type,
+                           bool pass_isolate)
+        : callback(callback), gc_type(gc_type), pass_isolate_(pass_isolate) {
     }
     bool operator==(const GCPrologueCallbackPair& pair) const {
       return pair.callback == callback;
     }
-    GCPrologueCallback callback;
+    v8::Isolate::GCPrologueCallback callback;
     GCType gc_type;
+    // TODO(dcarney): remove variable
+    bool pass_isolate_;
   };
   List<GCPrologueCallbackPair> gc_prologue_callbacks_;
 
   struct GCEpilogueCallbackPair {
-    GCEpilogueCallbackPair(GCEpilogueCallback callback, GCType gc_type)
-        : callback(callback), gc_type(gc_type) {
+    GCEpilogueCallbackPair(v8::Isolate::GCPrologueCallback callback,
+                           GCType gc_type,
+                           bool pass_isolate)
+        : callback(callback), gc_type(gc_type), pass_isolate_(pass_isolate) {
     }
     bool operator==(const GCEpilogueCallbackPair& pair) const {
       return pair.callback == callback;
     }
-    GCEpilogueCallback callback;
+    v8::Isolate::GCPrologueCallback callback;
     GCType gc_type;
+    // TODO(dcarney): remove variable
+    bool pass_isolate_;
   };
   List<GCEpilogueCallbackPair> gc_epilogue_callbacks_;
 
-  GCCallback global_gc_prologue_callback_;
-  GCCallback global_gc_epilogue_callback_;
-
   // Support for computing object sizes during GC.
   HeapObjectCallback gc_safe_size_of_old_object_;
   static int GcSafeSizeOfOldObject(HeapObject* object);
index ff8c00f..1c24017 100644 (file)
@@ -17705,32 +17705,73 @@ TEST(Regress618) {
   }
 }
 
+v8::Isolate* gc_callbacks_isolate = NULL;
 int prologue_call_count = 0;
 int epilogue_call_count = 0;
 int prologue_call_count_second = 0;
 int epilogue_call_count_second = 0;
 
-void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
+void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
+  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
   ++prologue_call_count;
 }
 
 
-void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
+void PrologueCallback(v8::Isolate* isolate,
+                      v8::GCType,
+                      v8::GCCallbackFlags flags) {
+  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
+  CHECK_EQ(gc_callbacks_isolate, isolate);
+  ++prologue_call_count;
+}
+
+
+void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
+  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
   ++epilogue_call_count;
 }
 
 
-void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
+void EpilogueCallback(v8::Isolate* isolate,
+                      v8::GCType,
+                      v8::GCCallbackFlags flags) {
+  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
+  CHECK_EQ(gc_callbacks_isolate, isolate);
+  ++epilogue_call_count;
+}
+
+
+void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
+  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
+  ++prologue_call_count_second;
+}
+
+
+void PrologueCallbackSecond(v8::Isolate* isolate,
+                            v8::GCType,
+                            v8::GCCallbackFlags flags) {
+  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
+  CHECK_EQ(gc_callbacks_isolate, isolate);
   ++prologue_call_count_second;
 }
 
 
-void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
+void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
+  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
   ++epilogue_call_count_second;
 }
 
 
-TEST(GCCallbacks) {
+void EpilogueCallbackSecond(v8::Isolate* isolate,
+                            v8::GCType,
+                            v8::GCCallbackFlags flags) {
+  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
+  CHECK_EQ(gc_callbacks_isolate, isolate);
+  ++epilogue_call_count_second;
+}
+
+
+TEST(GCCallbacksOld) {
   LocalContext context;
 
   v8::V8::AddGCPrologueCallback(PrologueCallback);
@@ -17764,6 +17805,41 @@ TEST(GCCallbacks) {
 }
 
 
+TEST(GCCallbacks) {
+  LocalContext context;
+  v8::Isolate* isolate = context->GetIsolate();
+  gc_callbacks_isolate = isolate;
+  isolate->AddGCPrologueCallback(PrologueCallback);
+  isolate->AddGCEpilogueCallback(EpilogueCallback);
+  CHECK_EQ(0, prologue_call_count);
+  CHECK_EQ(0, epilogue_call_count);
+  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
+  CHECK_EQ(1, prologue_call_count);
+  CHECK_EQ(1, epilogue_call_count);
+  isolate->AddGCPrologueCallback(PrologueCallbackSecond);
+  isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
+  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
+  CHECK_EQ(2, prologue_call_count);
+  CHECK_EQ(2, epilogue_call_count);
+  CHECK_EQ(1, prologue_call_count_second);
+  CHECK_EQ(1, epilogue_call_count_second);
+  isolate->RemoveGCPrologueCallback(PrologueCallback);
+  isolate->RemoveGCEpilogueCallback(EpilogueCallback);
+  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
+  CHECK_EQ(2, prologue_call_count);
+  CHECK_EQ(2, epilogue_call_count);
+  CHECK_EQ(2, prologue_call_count_second);
+  CHECK_EQ(2, epilogue_call_count_second);
+  isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
+  isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
+  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
+  CHECK_EQ(2, prologue_call_count);
+  CHECK_EQ(2, epilogue_call_count);
+  CHECK_EQ(2, prologue_call_count_second);
+  CHECK_EQ(2, epilogue_call_count_second);
+}
+
+
 THREADED_TEST(AddToJSFunctionResultCache) {
   i::FLAG_stress_compaction = false;
   i::FLAG_allow_natives_syntax = true;
index f6e703b..c089871 100644 (file)
@@ -267,39 +267,6 @@ TEST(MapCompact) {
 }
 #endif
 
-static int gc_starts = 0;
-static int gc_ends = 0;
-
-static void GCPrologueCallbackFunc() {
-  CHECK(gc_starts == gc_ends);
-  gc_starts++;
-}
-
-
-static void GCEpilogueCallbackFunc() {
-  CHECK(gc_starts == gc_ends + 1);
-  gc_ends++;
-}
-
-
-TEST(GCCallback) {
-  i::FLAG_stress_compaction = false;
-  CcTest::InitializeVM();
-
-  HEAP->SetGlobalGCPrologueCallback(&GCPrologueCallbackFunc);
-  HEAP->SetGlobalGCEpilogueCallback(&GCEpilogueCallbackFunc);
-
-  // Scavenge does not call GC callback functions.
-  HEAP->PerformScavenge();
-
-  CHECK_EQ(0, gc_starts);
-  CHECK_EQ(gc_ends, gc_starts);
-
-  HEAP->CollectGarbage(OLD_POINTER_SPACE);
-  CHECK_EQ(1, gc_starts);
-  CHECK_EQ(gc_ends, gc_starts);
-}
-
 
 static int NumberOfWeakCalls = 0;
 static void WeakPointerCallback(v8::Isolate* isolate,