Revision: 7295
Author:   [email protected]
Date:     Mon Mar 21 13:49:34 2011
Log:      Create an abstraction (MarkBit) object to hold the location of the
mark bits for an object.  This allows the compiler to avoid
recalculating the location when accessing two bits for incremental
marking or when testing and then setting mark bits.
Review URL: http://codereview.chromium.org/6713075
http://code.google.com/p/v8/source/detail?r=7295

Modified:
 /branches/experimental/gc/src/heap.h
 /branches/experimental/gc/src/incremental-marking.cc
 /branches/experimental/gc/src/incremental-marking.h
 /branches/experimental/gc/src/mark-compact.cc
 /branches/experimental/gc/src/mark-compact.h
 /branches/experimental/gc/src/objects.cc
 /branches/experimental/gc/src/runtime-profiler.cc
 /branches/experimental/gc/src/spaces.cc
 /branches/experimental/gc/src/spaces.h

=======================================
--- /branches/experimental/gc/src/heap.h        Thu Mar 17 10:41:44 2011
+++ /branches/experimental/gc/src/heap.h        Mon Mar 21 13:49:34 2011
@@ -809,6 +809,8 @@

// Heap root getters. We have versions with and without type::cast() here.
   // You can't use type::cast during GC because the assert fails.
+ // TODO(gc): Try removing the unchecked accessors, now that GC marking does
+  // not corrupt the stack.
#define ROOT_ACCESSOR(type, name, camel_name) \ static inline type* name() { \ return type::cast(roots_[k##camel_name##RootIndex]); \
@@ -1128,6 +1130,8 @@
   }

   static inline bool NextGCIsLikelyToBeFull() {
+    if (FLAG_gc_global) return true;
+
     intptr_t total_promoted =
         PromotedSpaceSize() + PromotedExternalMemorySize();

@@ -1771,7 +1775,7 @@
   // otherwise mark the object as overflowed and wait for a rescan of the
   // heap.
   void Push(HeapObject* object) {
-    CHECK(object->IsHeapObject());
+    ASSERT(object->IsHeapObject());
     if (is_full()) {
       object->SetOverflow();
       overflowed_ = true;
@@ -1783,7 +1787,7 @@
   HeapObject* Pop() {
     ASSERT(!is_empty());
     HeapObject* object = *(--top_);
-    CHECK(object->IsHeapObject());
+    ASSERT(object->IsHeapObject());
     return object;
   }

=======================================
--- /branches/experimental/gc/src/incremental-marking.cc Thu Mar 17 10:41:44 2011 +++ /branches/experimental/gc/src/incremental-marking.cc Mon Mar 21 13:49:34 2011
@@ -52,10 +52,12 @@
  private:
   // Mark object pointed to by p.
   INLINE(static void MarkObjectByPointer(Object** p)) {
-    if ((*p)->IsHeapObject()) {
-      HeapObject* object = HeapObject::cast(*p);
-      if (IncrementalMarking::IsWhite(object)) {
-        IncrementalMarking::WhiteToGrey(object);
+    Object* obj = *p;
+    if (obj->IsHeapObject()) {
+      HeapObject* heap_object = HeapObject::cast(obj);
+      MarkBit mark_bit = Marking::MarkBitFrom(heap_object);
+      if (IncrementalMarking::IsWhite(mark_bit)) {
+        IncrementalMarking::WhiteToGrey(heap_object, mark_bit);
       }
     }
   }
@@ -76,11 +78,13 @@

  private:
   void MarkObjectByPointer(Object** p) {
-    if (!(*p)->IsHeapObject()) return;
-
-    HeapObject* object = HeapObject::cast(*p);
-    if (IncrementalMarking::IsWhite(object)) {
-      IncrementalMarking::WhiteToGrey(object);
+    Object* obj = *p;
+    if (!obj->IsHeapObject()) return;
+
+    HeapObject* heap_object = HeapObject::cast(obj);
+    MarkBit mark_bit = Marking::MarkBitFrom(heap_object);
+    if (IncrementalMarking::IsWhite(mark_bit)) {
+      IncrementalMarking::WhiteToGrey(heap_object, mark_bit);
     }
   }
 };
@@ -177,11 +181,11 @@
                             Heap::new_space()->FromSpaceHigh());

   // Clear markbits.
-  Address new_space_top = Heap::new_space()->top();
   Address new_space_bottom = Heap::new_space()->bottom();
-
-  Marking::ClearRange(new_space_bottom,
-                      static_cast<int>(new_space_top - new_space_bottom));
+  uintptr_t new_space_size =
+ RoundUp(Heap::new_space()->top() - new_space_bottom, 32 * kPointerSize);
+
+  Marking::ClearRange(new_space_bottom, new_space_size);

   ClearMarkbits();

@@ -217,7 +221,9 @@
       // correct only for objects that occupy at least two words.
       if (obj->map() != filler_map) {
         obj->Iterate(&marking_visitor);
-        MarkBlack(obj); }
+        MarkBit mark_bit = Marking::MarkBitFrom(obj);
+        MarkBlack(mark_bit);
+      }
     }
     state_ = COMPLETE;
     if (FLAG_trace_incremental_marking) {
@@ -267,13 +273,15 @@
// Explicitly skip one word fillers. Incremental markbit patterns are
         // correct only for objects that occupy at least two words.
         if (obj->map() != filler_map) {
-          ASSERT(IsGrey(obj));
+          ASSERT(IsGrey(Marking::MarkBitFrom(obj)));
           Map* map = obj->map();
           int size = obj->SizeFromMap(map);
           bytes_to_process -= size;
-          if (IsWhite(map)) WhiteToGrey(map);
+          MarkBit map_mark_bit = Marking::MarkBitFrom(map);
+          if (IsWhite(map_mark_bit)) WhiteToGrey(map, map_mark_bit);
           obj->IterateBody(map->instance_type(), size, &marking_visitor);
-          MarkBlack(obj);
+          MarkBit obj_mark_bit = Marking::MarkBitFrom(obj);
+          MarkBlack(obj_mark_bit);
         }
         count++;
       }
=======================================
--- /branches/experimental/gc/src/incremental-marking.h Thu Mar 17 03:33:29 2011 +++ /branches/experimental/gc/src/incremental-marking.h Mon Mar 21 13:49:34 2011
@@ -80,17 +80,22 @@

   static inline void RecordWrite(HeapObject* obj, Object* value) {
     if (!IsStopped() && value->IsHeapObject()) {
-      if (IsBlack(obj) && IsWhite(HeapObject::cast(value))) {
-        BlackToGrey(obj);
-        RestartIfNotMarking();
+      MarkBit value_bit = Marking::MarkBitFrom(HeapObject::cast(value));
+      if (IsWhite(value_bit)) {
+        MarkBit obj_bit = Marking::MarkBitFrom(obj);
+        if (IsBlack(obj_bit)) {
+          BlackToGrey(obj, obj_bit);
+          RestartIfNotMarking();
+        }
       }
     }
   }

   static inline void RecordWriteOf(HeapObject* value) {
     if (state_ != STOPPED) {
-      if (IsWhite(value)) {
-        WhiteToGrey(value);
+      MarkBit value_bit = Marking::MarkBitFrom(value);
+      if (IsWhite(value_bit)) {
+        WhiteToGrey(value, value_bit);
         RestartIfNotMarking();
       }
     }
@@ -99,64 +104,72 @@

   static inline void RecordWrites(HeapObject* obj) {
     if (!IsStopped()) {
-      if (IsBlack(obj)) {
-        BlackToGrey(obj);
+      MarkBit obj_bit = Marking::MarkBitFrom(obj);
+      if (IsBlack(obj_bit)) {
+        BlackToGrey(obj, obj_bit);
         RestartIfNotMarking();
       }
     }
   }

-
-  // Black markbits: 10
-  static inline bool IsBlack(HeapObject* obj) {
-    return Marking::IsMarked(obj->address());
+  // Impossible markbits: 01
+  static inline bool IsImpossible(MarkBit mark_bit) {
+    return !mark_bit.Get() && mark_bit.Next().Get();
+  }
+
+  // Black markbits: 10 - this is required by the sweeper.
+  static inline bool IsBlack(MarkBit mark_bit) {
+    ASSERT(!IsImpossible(mark_bit));
+    return mark_bit.Get() && !mark_bit.Next().Get();
   }

-  // White markbits: 00
-  static inline bool IsWhite(HeapObject* obj) {
-    return !Marking::IsMarked(obj->address()) &&
-        !Marking::IsMarked(obj->address() + kPointerSize);
+  // White markbits: 00 - this is required by the mark bit clearer.
+  static inline bool IsWhite(MarkBit mark_bit) {
+    ASSERT(!IsImpossible(mark_bit));
+    return !mark_bit.Get();
   }

-  // Grey markbits: 01
-  static inline bool IsGrey(HeapObject* obj) {
-    return Marking::IsMarked(obj->address() + kPointerSize);
+  // Grey markbits: 11
+  static inline bool IsGrey(MarkBit mark_bit) {
+    ASSERT(!IsImpossible(mark_bit));
+    return mark_bit.Get() && mark_bit.Next().Get();
   }

-  static inline void BlackToGrey(HeapObject* obj) {
+  static inline void BlackToGrey(HeapObject* obj, MarkBit mark_bit) {
+    ASSERT(Marking::MarkBitFrom(obj) == mark_bit);
     ASSERT(obj->Size() >= 2*kPointerSize);
     ASSERT(!IsStopped());
-    ASSERT(IsBlack(obj));
-    Marking::ClearMark(obj->address());
-    Marking::SetMark(obj->address() + kPointerSize);
-    ASSERT(IsGrey(obj));
+    ASSERT(IsBlack(mark_bit));
+    mark_bit.Next().Set();
+    ASSERT(IsGrey(mark_bit));

     marking_stack_.Push(obj);
     ASSERT(!marking_stack_.overflowed());
   }

-  static inline void WhiteToGrey(HeapObject* obj) {
+  static inline void WhiteToGrey(HeapObject* obj, MarkBit mark_bit) {
+    ASSERT(Marking::MarkBitFrom(obj) == mark_bit);
     ASSERT(obj->Size() >= 2*kPointerSize);
     ASSERT(!IsStopped());
-    ASSERT(IsWhite(obj));
-    Marking::SetMark(obj->address() + kPointerSize);
-    ASSERT(IsGrey(obj));
+    ASSERT(IsWhite(mark_bit));
+    mark_bit.Set();
+    mark_bit.Next().Set();
+    ASSERT(IsGrey(mark_bit));

     marking_stack_.Push(obj);
     ASSERT(!marking_stack_.overflowed());
   }

-  static inline void MarkBlack(HeapObject* obj) {
-    ASSERT(obj->Size() >= 2*kPointerSize);
-    Marking::SetMark(obj->address());
-    Marking::ClearMark(obj->address() + kPointerSize);
-    ASSERT(IsBlack(obj));
+  static inline void MarkBlack(MarkBit mark_bit) {
+    mark_bit.Set();
+    mark_bit.Next().Clear();
+    ASSERT(IsBlack(mark_bit));
   }

-  static inline const char* ColorStr(HeapObject* obj) {
-    if (IsBlack(obj)) return "black";
-    if (IsWhite(obj)) return "white";
-    if (IsGrey(obj)) return "grey";
+  static inline const char* ColorStr(MarkBit mark_bit) {
+    if (IsBlack(mark_bit)) return "black";
+    if (IsWhite(mark_bit)) return "white";
+    if (IsGrey(mark_bit)) return "grey";
     UNREACHABLE();
     return "???";
   }
=======================================
--- /branches/experimental/gc/src/mark-compact.cc       Thu Mar 17 10:41:44 2011
+++ /branches/experimental/gc/src/mark-compact.cc       Mon Mar 21 13:49:34 2011
@@ -98,7 +98,7 @@
     for (Object** current = start; current < end; current++) {
       if ((*current)->IsHeapObject()) {
         HeapObject* object = HeapObject::cast(*current);
-        ASSERT(Marking::IsMarked(object));
+        ASSERT(MarkCompactCollector::IsMarked(object));
       }
     }
   }
@@ -114,7 +114,7 @@
        current < top;
        current += kPointerSize) {
     object = HeapObject::FromAddress(current);
-    if (Marking::IsMarked(object)) {
+    if (MarkCompactCollector::IsMarked(object)) {
       ASSERT(current >= next_object_must_be_here_or_later);
       object->Iterate(&visitor);
       next_object_must_be_here_or_later = current + object->Size();
@@ -238,23 +238,33 @@
 void Marking::TransferMark(Address old_start, Address new_start) {
   if (old_start == new_start) return;

+  MarkBit new_mark_bit = Marking::MarkBitFrom(new_start);
+
   if (!IncrementalMarking::IsStopped()) {
-    if (IncrementalMarking::IsBlack(HeapObject::FromAddress(old_start))) {
-      IncrementalMarking::MarkBlack(HeapObject::FromAddress(new_start));
-      ClearMark(old_start);
- } else if (IncrementalMarking::IsGrey(HeapObject::FromAddress(old_start))) {
-      ClearMark(old_start + kPointerSize);
-      IncrementalMarking::WhiteToGrey(HeapObject::FromAddress(new_start));
+    MarkBit old_mark_bit = Marking::MarkBitFrom(old_start);
+    if (IncrementalMarking::IsBlack(old_mark_bit)) {
+      IncrementalMarking::MarkBlack(new_mark_bit);
+      old_mark_bit.Clear();
+    } else if (IncrementalMarking::IsGrey(old_mark_bit)) {
+      old_mark_bit.Next().Clear();
+      IncrementalMarking::WhiteToGrey(HeapObject::FromAddress(new_start),
+                                      new_mark_bit);
       IncrementalMarking::RestartIfNotMarking();
// TODO(gc): if we shift huge array in the loop we might end up pushing // to much to marking stack. maybe we should check one or two elements
       // on top of it to see whether they are equal to old_start.
     }
   } else {
-    if (Heap::InNewSpace(old_start) || !IsMarked(old_start)) {
+    ASSERT(IncrementalMarking::IsStopped());
+    if (Heap::InNewSpace(old_start)) {
       return;
-    }
-    SetMark(new_start);
+    } else {
+      MarkBit old_mark_bit = Marking::MarkBitFrom(old_start);
+      if (!old_mark_bit.Get()) {
+        return;
+      }
+    }
+    new_mark_bit.Set();
   }
 }

@@ -302,11 +312,11 @@
   }

   if (IncrementalMarking::state() == IncrementalMarking::STOPPED) {
-    Address new_space_top = Heap::new_space()->top();
     Address new_space_bottom = Heap::new_space()->bottom();
-
-    Marking::ClearRange(new_space_bottom,
- static_cast<int>(new_space_top - new_space_bottom));
+    uintptr_t new_space_size =
+ RoundUp(Heap::new_space()->top() - new_space_bottom, 32 * kPointerSize);
+
+    Marking::ClearRange(new_space_bottom, new_space_size);

     ClearMarkbits();
 #ifdef DEBUG
@@ -431,7 +441,8 @@
       SharedFunctionInfo* shared = candidate->unchecked_shared();

       Code* code = shared->unchecked_code();
-      if (!Marking::IsMarked(code->address())) {
+      MarkBit code_mark = Marking::MarkBitFrom(code);
+      if (!code_mark.Get()) {
         shared->set_code(lazy_compile);
         candidate->set_code(lazy_compile);
       } else {
@@ -455,7 +466,8 @@
       SetNextCandidate(candidate, NULL);

       Code* code = candidate->unchecked_code();
-      if (!Marking::IsMarked(code->address())) {
+      MarkBit code_mark = Marking::MarkBitFrom(code);
+      if (!code_mark.Get()) {
         candidate->set_code(lazy_compile);
       }

@@ -650,7 +662,8 @@
       // Please note targets for cleared inline cached do not have to be
       // marked since they are contained in Heap::non_monomorphic_cache().
     } else {
-      MarkCompactCollector::MarkObject(code);
+      MarkBit code_mark = Marking::MarkBitFrom(code);
+      MarkCompactCollector::MarkObject(code, code_mark);
     }
   }

@@ -671,26 +684,30 @@
            (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
             rinfo->IsPatchedDebugBreakSlotSequence()));
HeapObject* code = Code::GetCodeFromTargetAddress(rinfo->call_address());
-    MarkCompactCollector::MarkObject(code);
+    MarkBit code_mark = Marking::MarkBitFrom(code);
+    MarkCompactCollector::MarkObject(code, code_mark);
   }

   // Mark object pointed to by p.
   INLINE(static void MarkObjectByPointer(Object** p)) {
     if (!(*p)->IsHeapObject()) return;
     HeapObject* object = ShortCircuitConsString(p);
-    MarkCompactCollector::MarkObject(object);
+    MarkBit mark = Marking::MarkBitFrom(object);
+    MarkCompactCollector::MarkObject(object, mark);
   }

   // Visit an unmarked object.
   static inline void VisitUnmarkedObject(HeapObject* obj) {
 #ifdef DEBUG
     ASSERT(Heap::Contains(obj));
-    ASSERT(!Marking::IsMarked(obj->address()));
+    ASSERT(!MarkCompactCollector::IsMarked(obj));
 #endif
     Map* map = obj->map();
-    MarkCompactCollector::SetMark(obj);
+    MarkBit mark = Marking::MarkBitFrom(obj);
+    MarkCompactCollector::SetMark(obj, mark);
     // Mark the map pointer and the body.
-    MarkCompactCollector::MarkObject(map);
+    MarkBit map_mark = Marking::MarkBitFrom(map);
+    MarkCompactCollector::MarkObject(map, map_mark);
     IterateBody(map, obj);
   }

@@ -703,9 +720,11 @@

     // Visit the unmarked objects.
     for (Object** p = start; p < end; p++) {
-      if (!(*p)->IsHeapObject()) continue;
-      HeapObject* obj = HeapObject::cast(*p);
-      if (Marking::IsMarked(obj)) continue;
+      Object* o = *p;
+      if (!o->IsHeapObject()) continue;
+      HeapObject* obj = HeapObject::cast(o);
+      MarkBit mark = Marking::MarkBitFrom(obj);
+      if (mark.Get()) continue;
       VisitUnmarkedObject(obj);
     }
     return true;
@@ -766,7 +785,8 @@

     // Code is either on stack, in compilation cache or referenced
     // by optimized version of function.
-    if (Marking::IsMarked(function->unchecked_code())) {
+    MarkBit code_mark = Marking::MarkBitFrom(function->unchecked_code());
+    if (code_mark.Get()) {
       shared_info->set_code_age(0);
       return false;
     }
@@ -782,7 +802,8 @@
   inline static bool IsFlushable(SharedFunctionInfo* shared_info) {
     // Code is either on stack, in compilation cache or referenced
     // by optimized version of function.
-    if (Marking::IsMarked(shared_info->unchecked_code())) {
+ MarkBit code_mark = Marking::MarkBitFrom(shared_info->unchecked_code());
+    if (code_mark.Get()) {
       shared_info->set_code_age(0);
       return false;
     }
@@ -916,8 +937,9 @@
     }

     if (!flush_code_candidate) {
-      MarkCompactCollector::MarkObject(
-          jsfunction->unchecked_shared()->unchecked_code());
+      Code* code = jsfunction->unchecked_shared()->unchecked_code();
+      MarkBit code_mark = Marking::MarkBitFrom(code);
+      MarkCompactCollector::MarkObject(code, code_mark);

if (jsfunction->unchecked_code()->kind() == Code::OPTIMIZED_FUNCTION) { // For optimized functions we should retain both non-optimized version
@@ -933,8 +955,9 @@
              i < count;
              i++) {
JSFunction* inlined = reinterpret_cast<JSFunction*>(literals->get(i));
-          MarkCompactCollector::MarkObject(
-              inlined->unchecked_shared()->unchecked_code());
+ Code* inlined_code = inlined->unchecked_shared()->unchecked_code();
+          MarkBit inlined_code_mark = Marking::MarkBitFrom(inlined_code);
+ MarkCompactCollector::MarkObject(inlined_code, inlined_code_mark);
         }
       }
     }
@@ -970,10 +993,12 @@
       // Visit shared function info to avoid double checking of it's
       // flushability.
       SharedFunctionInfo* shared_info = object->unchecked_shared();
-      if (!Marking::IsMarked(shared_info)) {
+      MarkBit shared_info_mark = Marking::MarkBitFrom(shared_info);
+      if (!shared_info_mark.Get()) {
         Map* shared_info_map = shared_info->map();
-        MarkCompactCollector::SetMark(shared_info);
-        MarkCompactCollector::MarkObject(shared_info_map);
+ MarkBit shared_info_map_mark = Marking::MarkBitFrom(shared_info_map);
+        MarkCompactCollector::SetMark(shared_info, shared_info_mark);
+ MarkCompactCollector::MarkObject(shared_info_map, shared_info_map_mark);
         VisitSharedFunctionInfoAndFlushCodeGeneric(shared_info_map,
                                                    shared_info,
                                                    true);
@@ -1040,7 +1065,9 @@
  public:
   void VisitThread(ThreadLocalTop* top) {
     for (StackFrameIterator it(top); !it.done(); it.Advance()) {
-      MarkCompactCollector::MarkObject(it.frame()->unchecked_code());
+      Code* code = it.frame()->unchecked_code();
+      MarkBit code_bit = Marking::MarkBitFrom(code);
+ MarkCompactCollector::MarkObject(it.frame()->unchecked_code(), code_bit);
     }
   }
 };
@@ -1056,8 +1083,10 @@
     Object* obj = *slot;
     if (obj->IsSharedFunctionInfo()) {
SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(obj);
-      MarkCompactCollector::MarkObject(shared->unchecked_code());
-      MarkCompactCollector::MarkObject(shared);
+      MarkBit shared_mark = Marking::MarkBitFrom(shared);
+      MarkBit code_mark = Marking::MarkBitFrom(shared->unchecked_code());
+ MarkCompactCollector::MarkObject(shared->unchecked_code(), code_mark);
+      MarkCompactCollector::MarkObject(shared, shared_mark);
     }
   }
 };
@@ -1079,11 +1108,15 @@

// Ensure that empty descriptor array is marked. Method MarkDescriptorArray
   // relies on it being marked before any other descriptor array.
-  MarkObject(Heap::raw_unchecked_empty_descriptor_array());
+ HeapObject* descriptor_array = Heap::raw_unchecked_empty_descriptor_array();
+  MarkBit descriptor_array_mark = Marking::MarkBitFrom(descriptor_array);
+  MarkObject(descriptor_array, descriptor_array_mark);

   // Make sure we are not referencing the code from the stack.
   for (StackFrameIterator it; !it.done(); it.Advance()) {
-    MarkObject(it.frame()->unchecked_code());
+    Code* code = it.frame()->unchecked_code();
+    MarkBit code_mark = Marking::MarkBitFrom(code);
+    MarkObject(code, code_mark);
   }

   // Iterate the archived stacks in all threads to check if
@@ -1116,14 +1149,16 @@

     // Replace flat cons strings in place.
     HeapObject* object = ShortCircuitConsString(p);
-    if (Marking::IsMarked(object)) return;
+    MarkBit mark_bit = Marking::MarkBitFrom(object);
+    if (mark_bit.Get()) return;

     Map* map = object->map();
     // Mark the object.
-    MarkCompactCollector::SetMark(object);
+    MarkCompactCollector::SetMark(object, mark_bit);

     // Mark the map pointer and body, and push them on the marking stack.
-    MarkCompactCollector::MarkObject(map);
+    MarkBit map_mark = Marking::MarkBitFrom(map);
+    MarkCompactCollector::MarkObject(map, map_mark);
     StaticMarkingVisitor::IterateBody(map, object);

     // Mark all the objects reachable from the map and body.  May leave
@@ -1141,15 +1176,16 @@
   virtual void VisitPointers(Object** start, Object** end) {
     // Visit all HeapObject pointers in [start, end).
     for (Object** p = start; p < end; p++) {
-      if ((*p)->IsHeapObject() &&
-          !Marking::IsMarked(HeapObject::cast(*p))) {
+      Object* o = *p;
+      if (o->IsHeapObject() &&
+          !Marking::MarkBitFrom(HeapObject::cast(o)).Get()) {
// Check if the symbol being pruned is an external symbol. We need to // delete the associated external data as this symbol is going away.

// Since no objects have yet been moved we can safely access the map of
         // the object.
-        if ((*p)->IsExternalString()) {
-          Heap::FinalizeExternalString(String::cast(*p));
+        if (o->IsExternalString()) {
+          Heap::FinalizeExternalString(String::cast(o));
         }
         // Set the entry to null_value (as deleted).
         *p = Heap::raw_unchecked_null_value();
@@ -1171,7 +1207,7 @@
 class MarkCompactWeakObjectRetainer : public WeakObjectRetainer {
  public:
   virtual Object* RetainAs(Object* object) {
-    if (Marking::IsMarked(HeapObject::cast(object))) {
+    if (Marking::MarkBitFrom(HeapObject::cast(object)).Get()) {
       return object;
     } else {
       return NULL;
@@ -1181,7 +1217,7 @@


 void MarkCompactCollector::ProcessNewlyMarkedObject(HeapObject* object) {
-  ASSERT(Marking::IsMarked(object));
+  ASSERT(IsMarked(object));
   ASSERT(Heap::Contains(object));
   if (object->IsMap()) {
     Map* map = Map::cast(object);
@@ -1219,18 +1255,20 @@

 void MarkCompactCollector::MarkDescriptorArray(
     DescriptorArray* descriptors) {
-  if (Marking::IsMarked(descriptors)) return;
+  MarkBit descriptors_mark = Marking::MarkBitFrom(descriptors);
+  if (descriptors_mark.Get()) return;
   // Empty descriptor array is marked as a root before any maps are marked.
   ASSERT(descriptors != Heap::raw_unchecked_empty_descriptor_array());
-  SetMark(descriptors);
+  SetMark(descriptors, descriptors_mark);

   FixedArray* contents = reinterpret_cast<FixedArray*>(
       descriptors->get(DescriptorArray::kContentArrayIndex));
   ASSERT(contents->IsHeapObject());
-  ASSERT(!Marking::IsMarked(contents));
+  ASSERT(!IsMarked(contents));
   ASSERT(contents->IsFixedArray());
   ASSERT(contents->length() >= 2);
-  SetMark(contents);
+  MarkBit contents_mark = Marking::MarkBitFrom(contents);
+  SetMark(contents, contents_mark);
   // Contents contains (value, details) pairs.  If the details say that
   // the type of descriptor is MAP_TRANSITION, CONSTANT_TRANSITION, or
   // NULL_DESCRIPTOR, we don't mark the value as live.  Only for
@@ -1242,9 +1280,12 @@
     PropertyDetails details(Smi::cast(contents->get(i + 1)));
     if (details.type() < FIRST_PHANTOM_PROPERTY_TYPE) {
       HeapObject* object = reinterpret_cast<HeapObject*>(contents->get(i));
-      if (object->IsHeapObject() && !Marking::IsMarked(object)) {
-        SetMark(object);
-        marking_stack.Push(object);
+      if (object->IsHeapObject()) {
+        MarkBit mark = Marking::MarkBitFrom(HeapObject::cast(object));
+        if (!mark.Get()) {
+          SetMark(HeapObject::cast(object), mark);
+          marking_stack.Push(object);
+        }
       }
     }
   }
@@ -1291,7 +1332,7 @@
for (HeapObject* object = it->next(); object != NULL; object = it->next()) {
     if (object->IsOverflowed()) {
       object->ClearOverflow();
-      ASSERT(Marking::IsMarked(object));
+      ASSERT(MarkCompactCollector::IsMarked(object));
       ASSERT(Heap::Contains(object));
       marking_stack.Push(object);
       if (marking_stack.is_full()) return;
@@ -1303,15 +1344,19 @@


 bool MarkCompactCollector::IsUnmarkedHeapObject(Object** p) {
-  return (*p)->IsHeapObject() &&
-      !Marking::IsMarked(HeapObject::cast(*p));
+  Object* o = *p;
+  if (!o->IsHeapObject()) return false;
+  HeapObject* heap_object = HeapObject::cast(o);
+  MarkBit mark = Marking::MarkBitFrom(heap_object);
+  return !mark.Get();
 }


 void MarkCompactCollector::MarkSymbolTable() {
   SymbolTable* symbol_table = Heap::raw_unchecked_symbol_table();
   // Mark the symbol table itself.
-  SetMark(symbol_table);
+  MarkBit symbol_table_mark = Marking::MarkBitFrom(symbol_table);
+  SetMark(symbol_table, symbol_table_mark);
   // Explicitly mark the prefix.
   MarkingVisitor marker;
   symbol_table->IteratePrefix(&marker);
@@ -1346,23 +1391,29 @@
     bool group_marked = false;
     for (int j = 0; j < objects.length(); j++) {
       Object* object = *objects[j];
-      if (object->IsHeapObject()
-          && Marking::IsMarked(HeapObject::cast(object))) {
-        group_marked = true;
-        break;
+      if (object->IsHeapObject()) {
+        HeapObject* heap_object = HeapObject::cast(object);
+        MarkBit mark = Marking::MarkBitFrom(heap_object);
+        if (mark.Get()) {
+          group_marked = true;
+          break;
+        }
       }
     }

     if (!group_marked) continue;

-    // An object in the group is marked, so mark as gray all white heap
+    // An object in the group is marked, so mark as grey all white heap
     // objects in the group.
     for (int j = 0; j < objects.length(); ++j) {
-      if ((*objects[j])->IsHeapObject()) {
-        MarkObject(HeapObject::cast(*objects[j]));
+      Object* object = *objects[j];
+      if (object->IsHeapObject()) {
+        HeapObject* heap_object = HeapObject::cast(object);
+        MarkBit mark = Marking::MarkBitFrom(heap_object);
+        MarkObject(heap_object, mark);
       }
     }
-    // Once the entire group has been colored gray, set the object group
+    // Once the entire group has been colored grey, set the object group
     // to NULL so it won't be processed again.
     delete object_groups->at(i);
     object_groups->at(i) = NULL;
@@ -1379,13 +1430,12 @@
     HeapObject* object = marking_stack.Pop();
     ASSERT(object->IsHeapObject());
     ASSERT(Heap::Contains(object));
-    ASSERT(Marking::IsMarked(object));
+    ASSERT(IsMarked(object));
     ASSERT(!object->IsOverflowed());

-    // Because the object is marked, we have to recover the original map
-    // pointer and use it to mark the object's body.
     Map* map = object->map();
-    MarkObject(map);
+    MarkBit map_mark = Marking::MarkBitFrom(map);
+    MarkObject(map, map_mark);

     StaticMarkingVisitor::IterateBody(map, object);
   }
@@ -1583,14 +1633,15 @@
   for (HeapObject* obj = map_iterator.Next();
        obj != NULL; obj = map_iterator.Next()) {
     Map* map = reinterpret_cast<Map*>(obj);
-    if (!Marking::IsMarked(map) && map->IsFreeSpace()) continue;
+    MarkBit map_mark = Marking::MarkBitFrom(map);
+    if (!map_mark.Get() && map->IsFreeSpace()) continue;

     ASSERT(SafeIsMap(map));
     // Only JSObject and subtypes have map transitions and back pointers.
     if (map->instance_type() < FIRST_JS_OBJECT_TYPE) continue;
     if (map->instance_type() > JS_FUNCTION_TYPE) continue;

-    if (Marking::IsMarked(map) &&
+    if (map_mark.Get() &&
         map->attached_to_shared_function_info()) {
       // This map is used for inobject slack tracking and has been detached
       // from SharedFunctionInfo during the mark phase.
@@ -1608,17 +1659,17 @@

     // Follow back pointers, setting them to prototype,
     // clearing map transitions when necessary.
-    current = map;
-    bool on_dead_path = !Marking::IsMarked(current);
+    bool on_dead_path = !map_mark.Get();
     Object* next;
     while (SafeIsMap(current)) {
       next = current->prototype();
       // There should never be a dead map above a live map.
-      ASSERT(on_dead_path || Marking::IsMarked(current));
+      MarkBit current_mark = Marking::MarkBitFrom(current);
+      ASSERT(on_dead_path || current_mark.Get());

       // A live map above a dead map indicates a dead transition.
       // This test will always be false on the first iteration.
-      if (on_dead_path && Marking::IsMarked(current)) {
+      if (on_dead_path && current_mark.Get()) {
         on_dead_path = false;
         current->ClearNonLiveTransitions(real_prototype);
       }
@@ -1793,8 +1844,10 @@
for (Address current = from_bottom; current < from_top; current += size) {
     HeapObject* object = HeapObject::FromAddress(current);

-    if (Marking::IsMarked(object)) {
-      Marking::ClearMark(object);
+
+    MarkBit mark_bit = Marking::MarkBitFromNewSpace(object);
+    if (mark_bit.Get()) {
+      mark_bit.Clear();
       MarkCompactCollector::tracer()->decrement_marked_count();

       size = object->Size();
@@ -2219,8 +2272,7 @@
 // spaces will not contain the free space map.
 static void SweepConservatively(PagedSpace* space,
                                 Page* p) {
-  Page::MarkbitsBitmap* markbits = p->markbits();
-  Page::MarkbitsBitmap::CellType* cells = markbits->cells();
+  MarkBit::CellType* cells = p->markbits()->cells();

   p->SetFlag(MemoryChunk::WAS_SWEPT_CONSERVATIVELY);

@@ -2302,8 +2354,7 @@
 // over it.  Map space is swept precisely, because it is not compacted.
 static void SweepPrecisely(PagedSpace* space,
                            Page* p) {
-  Page::MarkbitsBitmap* markbits = p->markbits();
-  Page::MarkbitsBitmap::CellType* cells = markbits->cells();
+  MarkBit::CellType* cells = p->markbits()->cells();

   p->ClearFlag(MemoryChunk::WAS_SWEPT_CONSERVATIVELY);

=======================================
--- /branches/experimental/gc/src/mark-compact.h        Thu Mar 17 10:41:44 2011
+++ /branches/experimental/gc/src/mark-compact.h        Mon Mar 21 13:49:34 2011
@@ -45,59 +45,28 @@

 class Marking {
  public:
-  INLINE(static bool IsMarked(HeapObject* obj)) {
-    return IsMarked(obj->address());
+  static inline MarkBit MarkBitFrom(HeapObject* obj) {
+    return MarkBitFrom(reinterpret_cast<Address>(obj));
   }

-  INLINE(static void SetMark(HeapObject* obj)) {
-    SetMark(obj->address());
+  static inline MarkBit MarkBitFromNewSpace(HeapObject* obj) {
+    ASSERT(Heap::InNewSpace(obj));
+    uint32_t index = Heap::new_space()->AddressToMarkbitIndex(
+        reinterpret_cast<Address>(obj));
+    return new_space_bitmap_->MarkBitFromIndex(index);
   }

-  INLINE(static void ClearMark(HeapObject* obj)) {
-    ClearMark(obj->address());
-  }
-
-  INLINE(static bool TestAndMark(Address addr)) {
+  static inline MarkBit MarkBitFrom(Address addr) {
     if (Heap::InNewSpace(addr)) {
       uint32_t index = Heap::new_space()->AddressToMarkbitIndex(addr);
-      return new_space_bitmap_->TestAndSet(index);
+      return new_space_bitmap_->MarkBitFromIndex(index);
     } else {
       Page *p = Page::FromAddress(addr);
-      return p->markbits()->TestAndSet(p->AddressToMarkbitIndex(addr));
+ return p->markbits()->MarkBitFromIndex(p->AddressToMarkbitIndex(addr));
     }
   }

-  INLINE(static bool IsMarked(Address addr)) {
-    if (Heap::InNewSpace(addr)) {
-      uint32_t index = Heap::new_space()->AddressToMarkbitIndex(addr);
-      return new_space_bitmap_->Get(index);
-    } else {
-      Page *p = Page::FromAddress(addr);
-      return p->markbits()->Get(p->AddressToMarkbitIndex(addr));
-    }
-  }
-
-  INLINE(static void SetMark(Address addr)) {
-    if (Heap::InNewSpace(addr)) {
-      uint32_t index = Heap::new_space()->AddressToMarkbitIndex(addr);
-      new_space_bitmap_->Set(index);
-    } else {
-      Page *p = Page::FromAddress(addr);
-      p->markbits()->Set(p->FastAddressToMarkbitIndex(addr));
-    }
-  }
-
-  INLINE(static void ClearMark(Address addr)) {
-    if (Heap::InNewSpace(addr)) {
-      uint32_t index = Heap::new_space()->AddressToMarkbitIndex(addr);
-      new_space_bitmap_->Clear(index);
-    } else {
-      Page *p = Page::FromAddress(addr);
-      p->markbits()->Clear(p->FastAddressToMarkbitIndex(addr));
-    }
-  }
-
-  INLINE(static void ClearRange(Address addr, int size)) {
+  static void ClearRange(Address addr, int size) {
     if (Heap::InNewSpace(addr)) {
       uint32_t index = Heap::new_space()->AddressToMarkbitIndex(addr);
       new_space_bitmap_->ClearRange(index, size >> kPointerSizeLog2);
@@ -252,6 +221,14 @@
   static const uint32_t kSingleFreeEncoding = 0;
   static const uint32_t kMultiFreeEncoding = 1;

+#ifdef DEBUG
+  static bool IsMarked(Object* obj) {
+    ASSERT(obj->IsHeapObject());
+    HeapObject* heap_object = HeapObject::cast(obj);
+    return Marking::MarkBitFrom(heap_object).Get();
+  }
+#endif
+
  private:
 #ifdef DEBUG
   enum CollectorState {
@@ -312,8 +289,10 @@
   static void AfterMarking();


-  INLINE(static void MarkObject(HeapObject* obj)) {
-    if (!Marking::TestAndMark(obj->address())) {
+  INLINE(static void MarkObject(HeapObject* obj, MarkBit mark_bit)) {
+    ASSERT(Marking::MarkBitFrom(obj) == mark_bit);
+    if (!mark_bit.Get()) {
+      mark_bit.Set();
       tracer_->increment_marked_count();
 #ifdef DEBUG
       UpdateLiveObjectCount(obj);
@@ -322,8 +301,9 @@
     }
   }

-  INLINE(static void SetMark(HeapObject* obj)) {
-    Marking::SetMark(obj);
+  INLINE(static void SetMark(HeapObject* obj, MarkBit mark_bit)) {
+    ASSERT(Marking::MarkBitFrom(obj) == mark_bit);
+    mark_bit.Set();
     tracer_->increment_marked_count();
 #ifdef DEBUG
     UpdateLiveObjectCount(obj);
=======================================
--- /branches/experimental/gc/src/objects.cc    Thu Mar 17 10:41:44 2011
+++ /branches/experimental/gc/src/objects.cc    Mon Mar 21 13:49:34 2011
@@ -5437,7 +5437,8 @@
         details.type() == CONSTANT_TRANSITION) {
       Map* target = reinterpret_cast<Map*>(contents->get(i));
       ASSERT(target->IsHeapObject());
-      if (!Marking::IsMarked(target)) {
+      MarkBit map_mark = Marking::MarkBitFrom(target);
+      if (!map_mark.Get()) {
         ASSERT(target->IsMap());
         contents->set_unchecked(i + 1, NullDescriptorDetails);
         contents->set_null_unchecked(i);
=======================================
--- /branches/experimental/gc/src/runtime-profiler.cc Tue Mar 15 12:46:33 2011 +++ /branches/experimental/gc/src/runtime-profiler.cc Mon Mar 21 13:49:34 2011
@@ -402,7 +402,8 @@
 void RuntimeProfiler::RemoveDeadSamples() {
   for (int i = 0; i < kSamplerWindowSize; i++) {
     Object* function = sampler_window[i];
- if (function != NULL && !Marking::IsMarked(HeapObject::cast(function))) {
+    if (function != NULL &&
+        !Marking::MarkBitFrom(HeapObject::cast(function)).Get()) {
       sampler_window[i] = NULL;
     }
   }
=======================================
--- /branches/experimental/gc/src/spaces.cc     Thu Mar 17 10:41:44 2011
+++ /branches/experimental/gc/src/spaces.cc     Mon Mar 21 13:49:34 2011
@@ -1992,8 +1992,9 @@
   LargePage* current = first_page_;
   while (current != NULL) {
     HeapObject* object = current->GetObject();
-    if (Marking::IsMarked(object)) {
-      Marking::ClearMark(object);
+    MarkBit mark_bit = Marking::MarkBitFrom(object);
+    if (mark_bit.Get()) {
+      mark_bit.Clear();
       MarkCompactCollector::tracer()->decrement_marked_count();
       previous = current;
       current = current->next_page();
=======================================
--- /branches/experimental/gc/src/spaces.h      Thu Mar 17 10:41:44 2011
+++ /branches/experimental/gc/src/spaces.h      Mon Mar 21 13:49:34 2011
@@ -117,11 +117,47 @@
 class OldSpaceFreeList;


+// TODO(gc): Check that this all gets inlined and register allocated on
+// all platforms.
+class MarkBit {
+ public:
+  typedef uint32_t CellType;
+
+  inline MarkBit(CellType* cell, CellType mask)
+      : cell_(cell), mask_(mask) { }
+
+  inline CellType* cell() { return cell_; }
+  inline CellType mask() { return mask_; }
+
+#ifdef DEBUG
+  bool operator==(const MarkBit& other) {
+    return cell_ == other.cell_ && mask_ == other.mask_;
+  }
+#endif
+
+  inline void Set() { *cell_ |= mask_; }
+  inline bool Get() { return (*cell_ & mask_) != 0; }
+  inline void Clear() { *cell_ &= ~mask_; }
+
+  inline MarkBit Next() {
+    CellType new_mask = mask_ << 1;
+    if (new_mask == 0) {
+      return MarkBit(cell_ + 1, 1);
+    } else {
+      return MarkBit(cell_, new_mask);
+    }
+  }
+
+ private:
+  CellType* cell_;
+  CellType mask_;
+};
+
+
 // Bitmap is a sequence of cells each containing fixed number of bits.
 template<typename StorageDescriptor>
 class Bitmap {
  public:
-  typedef uint32_t CellType;
   static const uint32_t kBitsPerCell = 32;
   static const uint32_t kBitsPerCellLog2 = 5;
   static const uint32_t kBitIndexMask = kBitsPerCell - 1;
@@ -135,16 +171,12 @@
   }

   static int SizeFor(int cells_count) {
-    return sizeof(CellType)*cells_count;
+    return sizeof(MarkBit::CellType)*cells_count;
   }

   INLINE(static uint32_t IndexToCell(uint32_t index)) {
     return index >> kBitsPerCellLog2;
   }
-
-  INLINE(static uint32_t IndexToBit(uint32_t index)) {
-    return index & kBitIndexMask;
-  }

   INLINE(static uint32_t CellToIndex(uint32_t index)) {
     return index << kBitsPerCellLog2;
@@ -154,8 +186,8 @@
     return (index + kBitIndexMask) & ~kBitIndexMask;
   }

-  INLINE(CellType* cells()) {
-    return reinterpret_cast<CellType*>(this);
+  INLINE(MarkBit::CellType* cells()) {
+    return reinterpret_cast<MarkBit::CellType*>(this);
   }

   INLINE(Address address()) {
@@ -166,58 +198,24 @@
     return reinterpret_cast<Bitmap*>(addr);
   }

-  INLINE(static Bitmap* FromAddress(uint32_t* addr)) {
-    return reinterpret_cast<Bitmap*>(addr);
-  }
-
-  INLINE(bool TestAndSet(const uint32_t index)) {
-    const uint32_t mask = 1 << (index & kBitIndexMask);
-    if (cells()[index >> kBitsPerCellLog2] & mask) {
-      return true;
-    } else {
-      cells()[index >> kBitsPerCellLog2] |= mask;
-      return false;
-    }
-  }
-
-  INLINE(bool Get(uint32_t index)) {
-    uint32_t mask = 1 << (index & kBitIndexMask);
-    return (this->cells()[index >> kBitsPerCellLog2] & mask) != 0;
-  }
-
-  INLINE(void Set(uint32_t index)) {
-    uint32_t mask = 1 << (index & kBitIndexMask);
-    cells()[index >> kBitsPerCellLog2] |= mask;
-  }
-
-  INLINE(void Clear(uint32_t index)) {
-    uint32_t mask = 1 << (index & kBitIndexMask);
-    cells()[index >> kBitsPerCellLog2] &= ~mask;
+  inline MarkBit MarkBitFromIndex(uint32_t index) {
+    MarkBit::CellType mask = 1 << (index & kBitIndexMask);
+    MarkBit::CellType* cell = this->cells() + (index >> kBitsPerCellLog2);
+    return MarkBit(cell, mask);
   }

   INLINE(void ClearRange(uint32_t start, uint32_t size)) {
     const uint32_t end = start + size;
     const uint32_t start_cell = start >> kBitsPerCellLog2;
     const uint32_t end_cell = end >> kBitsPerCellLog2;
-
-    const uint32_t start_mask = (-1) << (start & kBitIndexMask);
-    const uint32_t end_mask   = (1 << (end & kBitIndexMask)) - 1;
+    ASSERT((start & kBitIndexMask) == 0);
+    ASSERT((end & kBitIndexMask) == 0);

     ASSERT(static_cast<int>(start_cell) < CellsCount());
-    ASSERT(static_cast<int>(end_cell) < CellsCount() ||
-           (end_mask == 0 && static_cast<int>(end_cell) == CellsCount()));
-
-    if (start_cell == end_cell) {
-      cells()[start_cell] &= ~(start_mask & end_mask);
-    } else {
-      cells()[start_cell] &= ~start_mask;
-      if (end_mask != 0) cells()[end_cell] &= ~end_mask;
-
-      for (uint32_t cell = start_cell + 1, last_cell = end_cell - 1;
-           cell <= last_cell;
-           cell++) {
-        cells()[cell] = 0;
-      }
+    ASSERT(static_cast<int>(end_cell) <= CellsCount());
+
+    for (uint32_t cell = start_cell; cell < end_cell; cell++) {
+      cells()[cell] = 0;
     }
   }

@@ -1616,7 +1614,8 @@

   INLINE(uint32_t AddressToMarkbitIndex(Address addr)) {
     ASSERT(Contains(addr));
-    ASSERT(IsAligned(OffsetFrom(addr), kPointerSize));
+    ASSERT(IsAligned(OffsetFrom(addr), kPointerSize) ||
+           IsAligned(OffsetFrom(addr) - 1, kPointerSize));
     return static_cast<uint32_t>(addr - start_) >> kPointerSizeLog2;
   }

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to