Revision: 20282
Author:   [email protected]
Date:     Wed Mar 26 15:14:51 2014 UTC
Log: Reland r19897 "Fix memory leak caused by treating Code::next_code_link as strong in marker.

[email protected]

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

Modified:
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/mark-compact.cc
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects-visiting-inl.h
 /branches/bleeding_edge/src/objects-visiting.h
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/test/cctest/test-heap.cc

=======================================
--- /branches/bleeding_edge/src/heap.cc Wed Mar 26 12:50:13 2014 UTC
+++ /branches/bleeding_edge/src/heap.cc Wed Mar 26 15:14:51 2014 UTC
@@ -1773,6 +1773,18 @@
   }
   return head;
 }
+
+
+template <class T>
+static void ClearWeakList(Heap* heap,
+                          Object* list) {
+  Object* undefined = heap->undefined_value();
+  while (list != undefined) {
+    T* candidate = reinterpret_cast<T*>(list);
+    list = WeakListVisitor<T>::WeakNext(candidate);
+    WeakListVisitor<T>::SetWeakNext(candidate, undefined);
+  }
+}


 template<>
@@ -1868,7 +1880,11 @@
     }
   }

-  static void VisitPhantomObject(Heap*, Context*) {
+  static void VisitPhantomObject(Heap* heap, Context* context) {
+    ClearWeakList<JSFunction>(heap,
+        context->get(Context::OPTIMIZED_FUNCTIONS_LIST));
+    ClearWeakList<Code>(heap, context->get(Context::OPTIMIZED_CODE_LIST));
+ ClearWeakList<Code>(heap, context->get(Context::DEOPTIMIZED_CODE_LIST));
   }

   static int WeakNextOffset() {
@@ -4159,6 +4175,7 @@
   code->set_is_crankshafted(crankshafted);
   code->set_deoptimization_data(empty_fixed_array(), SKIP_WRITE_BARRIER);
   code->set_raw_type_feedback_info(undefined_value());
+  code->set_next_code_link(undefined_value());
   code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER);
   code->set_gc_metadata(Smi::FromInt(0));
   code->set_ic_age(global_ic_age_);
=======================================
--- /branches/bleeding_edge/src/mark-compact.cc Tue Mar 25 11:57:26 2014 UTC
+++ /branches/bleeding_edge/src/mark-compact.cc Wed Mar 26 15:14:51 2014 UTC
@@ -1862,6 +1862,10 @@
   void VisitPointers(Object** start, Object** end) {
     for (Object** p = start; p < end; p++) MarkObjectByPointer(p);
   }
+
+  // Skip the weak next code link in a code object, which is visited in
+  // ProcessTopOptimizedFrame.
+  void VisitNextCodeLink(Object** p) { }

  private:
   void MarkObjectByPointer(Object** p) {
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Wed Mar 26 12:50:13 2014 UTC
+++ /branches/bleeding_edge/src/objects-inl.h   Wed Mar 26 15:14:51 2014 UTC
@@ -1391,6 +1391,11 @@
 void HeapObject::IteratePointer(ObjectVisitor* v, int offset) {
   v->VisitPointer(reinterpret_cast<Object**>(FIELD_ADDR(this, offset)));
 }
+
+
+void HeapObject::IterateNextCodeLink(ObjectVisitor* v, int offset) {
+ v->VisitNextCodeLink(reinterpret_cast<Object**>(FIELD_ADDR(this, offset)));
+}


 double HeapNumber::value() {
@@ -5787,6 +5792,7 @@
 ACCESSORS(Code, handler_table, FixedArray, kHandlerTableOffset)
 ACCESSORS(Code, deoptimization_data, FixedArray, kDeoptimizationDataOffset)
 ACCESSORS(Code, raw_type_feedback_info, Object, kTypeFeedbackInfoOffset)
+ACCESSORS(Code, next_code_link, Object, kNextCodeLinkOffset)


 void Code::WipeOutHeader() {
@@ -5813,20 +5819,6 @@
   CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kTypeFeedbackInfoOffset,
                             value, mode);
 }
-
-
-Object* Code::next_code_link() {
-  CHECK(kind() == OPTIMIZED_FUNCTION);
-  return raw_type_feedback_info();
-}
-
-
-void Code::set_next_code_link(Object* value, WriteBarrierMode mode) {
-  CHECK(kind() == OPTIMIZED_FUNCTION);
-  set_raw_type_feedback_info(value);
-  CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kTypeFeedbackInfoOffset,
-                            value, mode);
-}


 int Code::stub_info() {
=======================================
--- /branches/bleeding_edge/src/objects-visiting-inl.h Mon Mar 17 08:31:21 2014 UTC +++ /branches/bleeding_edge/src/objects-visiting-inl.h Wed Mar 26 15:14:51 2014 UTC
@@ -899,6 +899,7 @@
   IteratePointer(v, kHandlerTableOffset);
   IteratePointer(v, kDeoptimizationDataOffset);
   IteratePointer(v, kTypeFeedbackInfoOffset);
+  IterateNextCodeLink(v, kNextCodeLinkOffset);
   IteratePointer(v, kConstantPoolOffset);

   RelocIterator it(this, mode_mask);
@@ -933,6 +934,9 @@
   StaticVisitor::VisitPointer(
       heap,
reinterpret_cast<Object**>(this->address() + kTypeFeedbackInfoOffset));
+  StaticVisitor::VisitNextCodeLink(
+      heap,
+      reinterpret_cast<Object**>(this->address() + kNextCodeLinkOffset));
   StaticVisitor::VisitPointer(
       heap,
       reinterpret_cast<Object**>(this->address() + kConstantPoolOffset));
=======================================
--- /branches/bleeding_edge/src/objects-visiting.h Thu Mar 13 15:10:35 2014 UTC +++ /branches/bleeding_edge/src/objects-visiting.h Wed Mar 26 15:14:51 2014 UTC
@@ -414,6 +414,8 @@
   INLINE(static void VisitCodeAgeSequence(Heap* heap, RelocInfo* rinfo));
   INLINE(static void VisitExternalReference(RelocInfo* rinfo)) { }
   INLINE(static void VisitRuntimeEntry(RelocInfo* rinfo)) { }
+  // Skip the weak next code link in a code object.
+  INLINE(static void VisitNextCodeLink(Heap* heap, Object** slot)) { }

// TODO(mstarzinger): This should be made protected once refactoring is done.
   // Mark non-optimize code for functions inlined into the given optimized
=======================================
--- /branches/bleeding_edge/src/objects.h       Wed Mar 26 12:50:13 2014 UTC
+++ /branches/bleeding_edge/src/objects.h       Wed Mar 26 15:14:51 2014 UTC
@@ -1898,6 +1898,8 @@
   inline void IteratePointers(ObjectVisitor* v, int start, int end);
   // as above, for the single element at "offset"
   inline void IteratePointer(ObjectVisitor* v, int offset);
+  // as above, for the next code link of a code object.
+  inline void IterateNextCodeLink(ObjectVisitor* v, int offset);

  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(HeapObject);
@@ -5249,7 +5251,6 @@
   // the kind of the code object.
   //   FUNCTION           => type feedback information.
   //   STUB               => various things, e.g. a SMI
-  //   OPTIMIZED_FUNCTION => the next_code_link for optimized code list.
   DECL_ACCESSORS(raw_type_feedback_info, Object)
   inline Object* type_feedback_info();
   inline void set_type_feedback_info(
@@ -5582,8 +5583,8 @@
       kHandlerTableOffset + kPointerSize;
   static const int kTypeFeedbackInfoOffset =
       kDeoptimizationDataOffset + kPointerSize;
- static const int kNextCodeLinkOffset = kTypeFeedbackInfoOffset; // Shared. - static const int kGCMetadataOffset = kTypeFeedbackInfoOffset + kPointerSize; + static const int kNextCodeLinkOffset = kTypeFeedbackInfoOffset + kPointerSize;
+  static const int kGCMetadataOffset = kNextCodeLinkOffset + kPointerSize;
   static const int kICAgeOffset =
       kGCMetadataOffset + kPointerSize;
   static const int kFlagsOffset = kICAgeOffset + kIntSize;
@@ -10733,6 +10734,9 @@

   // Handy shorthand for visiting a single pointer.
   virtual void VisitPointer(Object** p) { VisitPointers(p, p + 1); }
+
+  // Visit weak next_code_link in Code object.
+  virtual void VisitNextCodeLink(Object** p) { VisitPointers(p, p + 1); }

   // To allow lazy clearing of inline caches the visitor has
   // a rich interface for iterating over Code objects..
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap.cc Fri Mar 21 09:28:26 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-heap.cc Wed Mar 26 15:14:51 2014 UTC
@@ -3750,6 +3750,102 @@

   ASSERT(code->marked_for_deoptimization());
 }
+
+
+
+static Handle<JSFunction> OptimizeDummyFunction(const char* name) {
+  EmbeddedVector<char, 256> source;
+  OS::SNPrintF(source,
+              "function %s() { return 0; }"
+              "%s(); %s();"
+              "%%OptimizeFunctionOnNextCall(%s);"
+              "%s();", name, name, name, name, name);
+  CompileRun(source.start());
+  Handle<JSFunction> fun =
+      v8::Utils::OpenHandle(
+          *v8::Handle<v8::Function>::Cast(
+              CcTest::global()->Get(v8_str(name))));
+  return fun;
+}
+
+
+static int GetCodeChainLength(Code* code) {
+  int result = 0;
+  while (code->next_code_link()->IsCode()) {
+    result++;
+    code = Code::cast(code->next_code_link());
+  }
+  return result;
+}
+
+
+TEST(NextCodeLinkIsWeak) {
+  i::FLAG_allow_natives_syntax = true;
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::internal::Heap* heap = CcTest::heap();
+
+  if (!isolate->use_crankshaft()) return;
+  HandleScope outer_scope(heap->isolate());
+  Handle<Code> code;
+  heap->CollectAllAvailableGarbage();
+  int code_chain_length_before, code_chain_length_after;
+  {
+    HandleScope scope(heap->isolate());
+    Handle<JSFunction> mortal = OptimizeDummyFunction("mortal");
+    Handle<JSFunction> immortal = OptimizeDummyFunction("immortal");
+    CHECK_EQ(immortal->code()->next_code_link(), mortal->code());
+    code_chain_length_before = GetCodeChainLength(immortal->code());
+    // Keep the immortal code and let the mortal code die.
+    code = scope.CloseAndEscape(Handle<Code>(immortal->code()));
+    CompileRun("mortal = null; immortal = null;");
+  }
+  heap->CollectAllAvailableGarbage();
+  // Now mortal code should be dead.
+  code_chain_length_after = GetCodeChainLength(*code);
+  CHECK_EQ(code_chain_length_before - 1, code_chain_length_after);
+}
+
+
+static Handle<Code> DummyOptimizedCode(Isolate* isolate) {
+  i::byte buffer[i::Assembler::kMinimalBufferSize];
+  MacroAssembler masm(isolate, buffer, sizeof(buffer));
+  CodeDesc desc;
+  masm.Prologue(BUILD_FUNCTION_FRAME);
+  masm.GetCode(&desc);
+  Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::OPTIMIZED_FUNCTION), undefined);
+  CHECK(code->IsCode());
+  return code;
+}
+
+
+TEST(NextCodeLinkIsWeak2) {
+  i::FLAG_allow_natives_syntax = true;
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::internal::Heap* heap = CcTest::heap();
+
+  if (!isolate->use_crankshaft()) return;
+  HandleScope outer_scope(heap->isolate());
+  heap->CollectAllAvailableGarbage();
+ Handle<Context> context(Context::cast(heap->native_contexts_list()), isolate);
+  Handle<Code> new_head;
+ Handle<Object> old_head(context->get(Context::OPTIMIZED_CODE_LIST), isolate);
+  {
+    HandleScope scope(heap->isolate());
+    Handle<Code> immortal = DummyOptimizedCode(isolate);
+    Handle<Code> mortal = DummyOptimizedCode(isolate);
+    mortal->set_next_code_link(*old_head);
+    immortal->set_next_code_link(*mortal);
+    context->set(Context::OPTIMIZED_CODE_LIST, *immortal);
+    new_head = scope.CloseAndEscape(immortal);
+  }
+  heap->CollectAllAvailableGarbage();
+  // Now mortal code should be dead.
+  CHECK_EQ(*old_head, new_head->next_code_link());
+}


 #ifdef DEBUG

--
--
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