Add a flag to track detached contexts.
authorulan <ulan@chromium.org>
Thu, 5 Feb 2015 09:35:47 +0000 (01:35 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 5 Feb 2015 09:35:59 +0000 (09:35 +0000)
When embedder detaches the global objects, its context must be garbage
collected eventually.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#26450}

include/v8.h
src/bootstrapper.cc
src/flag-definitions.h
src/heap/heap.cc
src/heap/heap.h
src/isolate.cc
src/isolate.h

index eb7a8c3..b9edecd 100644 (file)
@@ -6200,7 +6200,7 @@ class Internals {
   static const int kNullValueRootIndex = 7;
   static const int kTrueValueRootIndex = 8;
   static const int kFalseValueRootIndex = 9;
-  static const int kEmptyStringRootIndex = 155;
+  static const int kEmptyStringRootIndex = 156;
 
   // The external allocation limit should be below 256 MB on all architectures
   // to avoid that resource-constrained embedders run low on memory.
index 22e5953..ac24ccd 100644 (file)
@@ -374,6 +374,9 @@ void Bootstrapper::DetachGlobal(Handle<Context> env) {
   global_proxy->set_native_context(*factory->null_value());
   SetObjectPrototype(global_proxy, factory->null_value());
   global_proxy->map()->set_constructor(*factory->null_value());
+  if (FLAG_track_detached_contexts) {
+    env->GetIsolate()->AddDetachedContext(env);
+  }
 }
 
 
index ef89cac..d458aae 100644 (file)
@@ -615,6 +615,8 @@ DEFINE_BOOL(trace_incremental_marking, false,
             "trace progress of the incremental marking")
 DEFINE_BOOL(track_gc_object_stats, false,
             "track object counts and memory usage")
+DEFINE_BOOL(track_detached_contexts, false,
+            "track native contexts that are expected to be garbage collected")
 #ifdef VERIFY_HEAP
 DEFINE_BOOL(verify_heap, false, "verify heap pointers before and after GC")
 #endif
index 05c302f..4f262ff 100644 (file)
@@ -854,6 +854,9 @@ bool Heap::CollectGarbage(GarbageCollector collector, const char* gc_reason,
     }
 
     GarbageCollectionEpilogue();
+    if (collector == MARK_COMPACTOR && FLAG_track_detached_contexts) {
+      isolate()->CheckDetachedContextsAfterGC();
+    }
     tracer()->Stop(collector);
   }
 
@@ -3071,6 +3074,8 @@ void Heap::CreateInitialObjects() {
     set_keyed_load_dummy_vector(empty_fixed_array());
   }
 
+  set_detached_contexts(empty_fixed_array());
+
   Handle<SeededNumberDictionary> slow_element_dictionary =
       SeededNumberDictionary::New(isolate(), 0, TENURED);
   slow_element_dictionary->set_requires_slow_elements();
index 2975d09..e78a7be 100644 (file)
@@ -183,7 +183,8 @@ namespace internal {
   V(FixedArray, materialized_objects, MaterializedObjects)                     \
   V(FixedArray, allocation_sites_scratchpad, AllocationSitesScratchpad)        \
   V(FixedArray, microtask_queue, MicrotaskQueue)                               \
-  V(FixedArray, keyed_load_dummy_vector, KeyedLoadDummyVector)
+  V(FixedArray, keyed_load_dummy_vector, KeyedLoadDummyVector)                 \
+  V(FixedArray, detached_contexts, DetachedContexts)
 
 // Entries in this list are limited to Smis and are not visited during GC.
 #define SMI_ROOT_LIST(V)                                                   \
index 6321b90..37020da 100644 (file)
@@ -2568,6 +2568,54 @@ std::string Isolate::GetTurboCfgFileName() {
 }
 
 
+// Heap::detached_contexts tracks detached contexts as pairs
+// (number of GC since the context was detached, the context).
+void Isolate::AddDetachedContext(Handle<Context> context) {
+  HandleScope scope(this);
+  Handle<WeakCell> cell = factory()->NewWeakCell(context);
+  Handle<FixedArray> detached_contexts(heap()->detached_contexts());
+  int length = detached_contexts->length();
+  detached_contexts = FixedArray::CopySize(detached_contexts, length + 2);
+  detached_contexts->set(length, Smi::FromInt(0));
+  detached_contexts->set(length + 1, *cell);
+  heap()->set_detached_contexts(*detached_contexts);
+}
+
+
+void Isolate::CheckDetachedContextsAfterGC() {
+  HandleScope scope(this);
+  Handle<FixedArray> detached_contexts(heap()->detached_contexts());
+  int length = detached_contexts->length();
+  if (length == 0) return;
+  int new_length = 0;
+  for (int i = 0; i < length; i += 2) {
+    int mark_sweeps = Smi::cast(detached_contexts->get(i))->value();
+    WeakCell* cell = WeakCell::cast(detached_contexts->get(i + 1));
+    if (!cell->cleared()) {
+      detached_contexts->set(new_length, Smi::FromInt(mark_sweeps + 1));
+      detached_contexts->set(new_length + 1, cell);
+      new_length += 2;
+    }
+  }
+  PrintF("%d detached contexts are collected out of %d\n", length - new_length,
+         length);
+  for (int i = 0; i < new_length; i += 2) {
+    int mark_sweeps = Smi::cast(detached_contexts->get(i))->value();
+    WeakCell* cell = WeakCell::cast(detached_contexts->get(i + 1));
+    if (mark_sweeps > 3) {
+      PrintF("detached context 0x%p\n survived %d GCs (leak?)\n",
+             static_cast<void*>(cell->value()), mark_sweeps);
+    }
+  }
+  if (length == new_length) {
+    heap()->set_detached_contexts(heap()->empty_fixed_array());
+  } else {
+    heap()->RightTrimFixedArray<Heap::FROM_GC>(*detached_contexts,
+                                               length - new_length);
+  }
+}
+
+
 bool StackLimitCheck::JsHasOverflowed() const {
   StackGuard* stack_guard = isolate_->stack_guard();
 #ifdef USE_SIMULATOR
index 21ac999..4fb8272 100644 (file)
@@ -1141,6 +1141,9 @@ class Isolate {
     return store_buffer_hash_set_2_address_;
   }
 
+  void AddDetachedContext(Handle<Context> context);
+  void CheckDetachedContextsAfterGC();
+
  private:
   explicit Isolate(bool enable_serializer);
 
@@ -1362,6 +1365,7 @@ class Isolate {
   v8::Isolate::UseCounterCallback use_counter_callback_;
   BasicBlockProfiler* basic_block_profiler_;
 
+
   friend class ExecutionAccess;
   friend class HandleScopeImplementer;
   friend class OptimizingCompilerThread;