Fix clearing of dead dependent codes and verify weak embedded maps on full GC.
authorulan@chromium.org <ulan@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 4 Feb 2013 10:56:50 +0000 (10:56 +0000)
committerulan@chromium.org <ulan@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 4 Feb 2013 10:56:50 +0000 (10:56 +0000)
BUG=172488,172489
R=mstarzinger@chromium.org

Review URL: https://chromiumcodereview.appspot.com/12094036

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

src/heap-inl.h
src/heap.cc
src/heap.h
src/lithium.cc
src/mark-compact.cc
src/mark-compact.h
src/objects-debug.cc
src/objects-visiting-inl.h
src/objects.cc
src/objects.h

index b8fb1e8a26ba9d68ce6bd4bbd8a85ca4e33c6a42..7b64a3b20b4fae0d4cbc2c48651d3cf145fa327b 100644 (file)
@@ -781,6 +781,18 @@ AlwaysAllocateScope::~AlwaysAllocateScope() {
 }
 
 
+#ifdef VERIFY_HEAP
+NoWeakEmbeddedMapsVerificationScope::NoWeakEmbeddedMapsVerificationScope() {
+  HEAP->no_weak_embedded_maps_verification_scope_depth_++;
+}
+
+
+NoWeakEmbeddedMapsVerificationScope::~NoWeakEmbeddedMapsVerificationScope() {
+  HEAP->no_weak_embedded_maps_verification_scope_depth_--;
+}
+#endif
+
+
 void VerifyPointersVisitor::VisitPointers(Object** start, Object** end) {
   for (Object** current = start; current < end; current++) {
     if ((*current)->IsHeapObject()) {
index 8d398ec3bcd985da9a0d4600566133fc9765ce25..6637b9af65bd54fefada680625cccff304cf7905 100644 (file)
@@ -157,6 +157,9 @@ Heap::Heap()
       ms_count_at_last_idle_notification_(0),
       gc_count_at_last_idle_gc_(0),
       scavenges_since_last_idle_round_(kIdleScavengeThreshold),
+#ifdef VERIFY_HEAP
+      no_weak_embedded_maps_verification_scope_depth_(0),
+#endif
       promotion_queue_(this),
       configured_(false),
       chunks_queued_for_free_(NULL),
index 4f9b672bf9d24d3e2649c35f4f3e4fa8490336f4..48036b8c25feba8b6124118e9196e46103568edc 100644 (file)
@@ -1322,6 +1322,11 @@ class Heap {
 #ifdef VERIFY_HEAP
   // Verify the heap is in its normal state before or after a GC.
   void Verify();
+
+
+  bool weak_embedded_maps_verification_enabled() {
+    return no_weak_embedded_maps_verification_scope_depth_ == 0;
+  }
 #endif
 
 #ifdef DEBUG
@@ -2214,6 +2219,10 @@ class Heap {
   unsigned int gc_count_at_last_idle_gc_;
   int scavenges_since_last_idle_round_;
 
+#ifdef VERIFY_HEAP
+  int no_weak_embedded_maps_verification_scope_depth_;
+#endif
+
   static const int kMaxMarkSweepsInIdleRound = 7;
   static const int kIdleScavengeThreshold = 5;
 
@@ -2243,6 +2252,9 @@ class Heap {
   friend class MarkCompactCollector;
   friend class MarkCompactMarkingVisitor;
   friend class MapCompact;
+#ifdef VERIFY_HEAP
+  friend class NoWeakEmbeddedMapsVerificationScope;
+#endif
 
   DISALLOW_COPY_AND_ASSIGN(Heap);
 };
@@ -2303,6 +2315,14 @@ class AlwaysAllocateScope {
   DisallowAllocationFailure disallow_allocation_failure_;
 };
 
+#ifdef VERIFY_HEAP
+class NoWeakEmbeddedMapsVerificationScope {
+ public:
+  inline NoWeakEmbeddedMapsVerificationScope();
+  inline ~NoWeakEmbeddedMapsVerificationScope();
+};
+#endif
+
 
 // Visitor class to verify interior pointers in spaces that do not contain
 // or care about intergenerational references. All heap object pointers have to
index 108eb7f777fe2720853c8a121e3fd1bb67dc2962..d630b9fe4b2f250f1680ba148f65287c2b207c26 100644 (file)
@@ -452,6 +452,12 @@ void LChunk::RegisterDependentCodeForEmbeddedMaps(Handle<Code> code) {
       }
     }
   }
+#ifdef VERIFY_HEAP
+  // This disables verification of weak embedded maps after full GC.
+  // AddDependentCode can cause a GC, which would observe the state where
+  // this code is not yet in the depended code lists of the embedded maps.
+  NoWeakEmbeddedMapsVerificationScope disable_verification_of_embedded_maps;
+#endif
   for (int i = 0; i < maps.length(); i++) {
     maps.at(i)->AddDependentCode(code);
   }
index bdd4785e3e729368ab1c6bf297e48457f9b5c6b4..3c6ab302faf4d395b0c24dab8adc303e2eafebd7 100644 (file)
@@ -87,7 +87,7 @@ class VerifyMarkingVisitor: public ObjectVisitor {
 
   void VisitEmbeddedPointer(RelocInfo* rinfo) {
     ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
-    if (!FLAG_weak_embedded_maps_in_optimized_code ||
+    if (!FLAG_weak_embedded_maps_in_optimized_code || !FLAG_collect_maps ||
         rinfo->host()->kind() != Code::OPTIMIZED_FUNCTION ||
         !rinfo->target_object()->IsMap() ||
         !Map::cast(rinfo->target_object())->CanTransition()) {
@@ -414,6 +414,13 @@ void MarkCompactCollector::CollectGarbage() {
   }
 #endif
 
+#ifdef VERIFY_HEAP
+  if (FLAG_collect_maps && FLAG_weak_embedded_maps_in_optimized_code &&
+      heap()->weak_embedded_maps_verification_enabled()) {
+    VerifyWeakEmbeddedMapsInOptimizedCode();
+  }
+#endif
+
   Finish();
 
   if (marking_parity_ == EVEN_MARKING_PARITY) {
@@ -465,6 +472,19 @@ void MarkCompactCollector::VerifyMarkbitsAreClean() {
     CHECK_EQ(0, Page::FromAddress(obj->address())->LiveBytes());
   }
 }
+
+
+void MarkCompactCollector::VerifyWeakEmbeddedMapsInOptimizedCode() {
+  HeapObjectIterator code_iterator(heap()->code_space());
+  for (HeapObject* obj = code_iterator.Next();
+       obj != NULL;
+       obj = code_iterator.Next()) {
+    Code* code = Code::cast(obj);
+    if (code->kind() != Code::OPTIMIZED_FUNCTION) continue;
+    if (code->marked_for_deoptimization()) continue;
+    code->VerifyEmbeddedMapsDependency();
+  }
+}
 #endif  // VERIFY_HEAP
 
 
@@ -890,6 +910,7 @@ void MarkCompactCollector::Prepare(GCTracer* tracer) {
 #endif
 }
 
+
 class DeoptimizeMarkedCodeFilter : public OptimizedFunctionFilter {
  public:
   virtual bool TakeFunction(JSFunction* function) {
@@ -2367,10 +2388,10 @@ void MarkCompactCollector::ClearNonLiveDependentCodes(Map* map) {
     if (IsMarked(code) && !code->marked_for_deoptimization()) {
       if (new_number_of_codes != i) {
         codes->set_code_at(new_number_of_codes, code);
-        Object** slot = codes->code_slot_at(new_number_of_codes);
-        RecordSlot(slot, slot, code);
-        new_number_of_codes++;
       }
+      Object** slot = codes->code_slot_at(new_number_of_codes);
+      RecordSlot(slot, slot, code);
+      new_number_of_codes++;
     }
   }
   for (int i = new_number_of_codes; i < number_of_codes; i++) {
index 9cdb46a4f9df60b35845117c020ec604f61555b6..9159b401b371121fd84f7dec67a0747d3f5765fe 100644 (file)
@@ -607,6 +607,7 @@ class MarkCompactCollector {
   void VerifyMarkbitsAreClean();
   static void VerifyMarkbitsAreClean(PagedSpace* space);
   static void VerifyMarkbitsAreClean(NewSpace* space);
+  void VerifyWeakEmbeddedMapsInOptimizedCode();
 #endif
 
   // Sweep a single page from the given space conservatively.
index 593e955efb9d3d6c366ea90db3c0b9ca7e2243b9..60463684999001b779eef13970299db1d6a3ed08 100644 (file)
@@ -30,6 +30,7 @@
 #include "disassembler.h"
 #include "disasm.h"
 #include "jsregexp.h"
+#include "macro-assembler.h"
 #include "objects-visiting.h"
 
 namespace v8 {
@@ -595,6 +596,21 @@ void Code::CodeVerify() {
 }
 
 
+void Code::VerifyEmbeddedMapsDependency() {
+  int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
+  for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
+    RelocInfo::Mode mode = it.rinfo()->rmode();
+    if (mode == RelocInfo::EMBEDDED_OBJECT &&
+      it.rinfo()->target_object()->IsMap()) {
+      Map* map = Map::cast(it.rinfo()->target_object());
+      if (map->CanTransition()) {
+        CHECK(map->dependent_codes()->Contains(this));
+      }
+    }
+  }
+}
+
+
 void JSArray::JSArrayVerify() {
   JSObjectVerify();
   CHECK(length()->IsNumber() || length()->IsUndefined());
index 4fabba4852eeaa83cdbf57c235040494bc33b435..93245c0f5fcd43e1b56580053c6232df119ef8f8 100644 (file)
@@ -175,8 +175,8 @@ void StaticMarkingVisitor<StaticVisitor>::VisitEmbeddedPointer(
   ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
   ASSERT(!rinfo->target_object()->IsConsString());
   HeapObject* object = HeapObject::cast(rinfo->target_object());
-  if (!FLAG_weak_embedded_maps_in_optimized_code ||
-      !FLAG_collect_maps || rinfo->host()->kind() != Code::OPTIMIZED_FUNCTION ||
+  if (!FLAG_weak_embedded_maps_in_optimized_code || !FLAG_collect_maps ||
+      rinfo->host()->kind() != Code::OPTIMIZED_FUNCTION ||
       !object->IsMap() || !Map::cast(object)->CanTransition()) {
     heap->mark_compact_collector()->RecordRelocSlot(rinfo, object);
     StaticVisitor::MarkObject(heap, object);
index fb8c7040100af0ac8e88226a22f0a06daa0b5def..948f4a6d5c42057738a478c9f0bb98f4138e7210 100644 (file)
@@ -9501,6 +9501,15 @@ Handle<DependentCodes> DependentCodes::Append(Handle<DependentCodes> codes,
 }
 
 
+bool DependentCodes::Contains(Code* code) {
+  int limit = number_of_codes();
+  for (int i = 0; i < limit; i++) {
+    if (code_at(i) == code) return true;
+  }
+  return false;
+}
+
+
 MaybeObject* JSReceiver::SetPrototype(Object* value,
                                       bool skip_hidden_prototypes) {
 #ifdef DEBUG
index 10f74fc7d6a85a264da749899f32ec02b96492e0..12413123c09c2a922da3f76a7fbe3679a3dd0609 100644 (file)
@@ -4547,6 +4547,10 @@ class Code: public HeapObject {
 
   void PrintDeoptLocation(int bailout_id);
 
+#ifdef VERIFY_HEAP
+  void VerifyEmbeddedMapsDependency();
+#endif
+
   // Max loop nesting marker used to postpose OSR. We don't take loop
   // nesting that is deeper than 5 levels into account.
   static const int kMaxLoopNestingMarker = 6;
@@ -4693,6 +4697,7 @@ class DependentCodes: public FixedArray {
   static Handle<DependentCodes> Append(Handle<DependentCodes> codes,
                                        Handle<Code> value);
   static inline DependentCodes* cast(Object* object);
+  bool Contains(Code* code);
  private:
   static const int kNumberOfCodesIndex = 0;
   static const int kCodesIndex = 1;