Serializer: support all alignment kinds.
authoryangguo <yangguo@chromium.org>
Tue, 16 Jun 2015 09:45:57 +0000 (02:45 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 16 Jun 2015 09:46:12 +0000 (09:46 +0000)
We use an alignment prefix for unusual alignment kinds (not kWordAligned).
This will cause new objects to be aligned in ReadObject, and back references
to be aligned to skip padding.

The motivation to change the undefined next sentinel in WeakCell is this:
When the deserializer aligns an object, it requires filler maps to already
exist to create filler objects as padding. However, deserializing the
filler map leads to deserializing NaN, which as heap number is aligned:
filler map > meta map > weak cell cache > undefined > NaN
If we use the-hole instead of undefined as sentinel, it works.

R=jochen@chromium.org,bbudge@chromium.org
BUG=v8:4178
LOG=N

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

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

src/code-stubs-hydrogen.cc
src/heap/heap.cc
src/heap/mark-compact.cc
src/heap/objects-visiting-inl.h
src/snapshot/serialize.cc
src/snapshot/serialize.h

index 45303bd1460c8420ecae38921319e1f68292c591..4573da151279d68dab655dbf0cbd587a40c7c892 100644 (file)
@@ -641,7 +641,7 @@ HValue* CodeStubGraphBuilder<CreateWeakCellStub>::BuildCodeStub() {
   HInstruction* value = GetParameter(CreateWeakCellDescriptor::kValueIndex);
   Add<HStoreNamedField>(object, HObjectAccess::ForWeakCellValue(), value);
   Add<HStoreNamedField>(object, HObjectAccess::ForWeakCellNext(),
-                        graph()->GetConstantUndefined());
+                        graph()->GetConstantHole());
 
   HInstruction* feedback_vector =
       GetParameter(CreateWeakCellDescriptor::kVectorIndex);
index 80eb5620a811dace8718ba2c876ada7b9cd7377f..39099fca1a69be01824c8aa961992875edfa6142 100644 (file)
@@ -3102,7 +3102,7 @@ AllocationResult Heap::AllocateWeakCell(HeapObject* value) {
   }
   result->set_map_no_write_barrier(weak_cell_map());
   WeakCell::cast(result)->initialize(value);
-  WeakCell::cast(result)->set_next(undefined_value(), SKIP_WRITE_BARRIER);
+  WeakCell::cast(result)->set_next(the_hole_value(), SKIP_WRITE_BARRIER);
   return result;
 }
 
@@ -3706,19 +3706,18 @@ AllocationResult Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
 void Heap::CreateFillerObjectAt(Address addr, int size) {
   if (size == 0) return;
   HeapObject* filler = HeapObject::FromAddress(addr);
-  // At this point, we may be deserializing the heap from a snapshot, and
-  // none of the maps have been created yet and are NULL.
   if (size == kPointerSize) {
     filler->set_map_no_write_barrier(raw_unchecked_one_pointer_filler_map());
-    DCHECK(filler->map() == NULL || filler->map() == one_pointer_filler_map());
   } else if (size == 2 * kPointerSize) {
     filler->set_map_no_write_barrier(raw_unchecked_two_pointer_filler_map());
-    DCHECK(filler->map() == NULL || filler->map() == two_pointer_filler_map());
   } else {
     filler->set_map_no_write_barrier(raw_unchecked_free_space_map());
-    DCHECK(filler->map() == NULL || filler->map() == free_space_map());
     FreeSpace::cast(filler)->nobarrier_set_size(size);
   }
+  // At this point, we may be deserializing the heap from a snapshot, and
+  // none of the maps have been created yet and are NULL.
+  DCHECK(filler->map() == NULL && !deserialization_complete_ ||
+         filler->map()->IsMap());
 }
 
 
index b56af23c4931dbf50e19ede19870a6817ed48732..90fc13616c65f750b974ce58ff821742603486f8 100644 (file)
@@ -2637,7 +2637,7 @@ void MarkCompactCollector::AbortWeakCollections() {
 
 
 void MarkCompactCollector::ProcessAndClearWeakCells() {
-  HeapObject* undefined = heap()->undefined_value();
+  HeapObject* the_hole = heap()->the_hole_value();
   Object* weak_cell_obj = heap()->encountered_weak_cells();
   while (weak_cell_obj != Smi::FromInt(0)) {
     WeakCell* weak_cell = reinterpret_cast<WeakCell*>(weak_cell_obj);
@@ -2672,19 +2672,19 @@ void MarkCompactCollector::ProcessAndClearWeakCells() {
       RecordSlot(slot, slot, *slot);
     }
     weak_cell_obj = weak_cell->next();
-    weak_cell->set_next(undefined, SKIP_WRITE_BARRIER);
+    weak_cell->set_next(the_hole, SKIP_WRITE_BARRIER);
   }
   heap()->set_encountered_weak_cells(Smi::FromInt(0));
 }
 
 
 void MarkCompactCollector::AbortWeakCells() {
-  Object* undefined = heap()->undefined_value();
+  Object* the_hole = heap()->the_hole_value();
   Object* weak_cell_obj = heap()->encountered_weak_cells();
   while (weak_cell_obj != Smi::FromInt(0)) {
     WeakCell* weak_cell = reinterpret_cast<WeakCell*>(weak_cell_obj);
     weak_cell_obj = weak_cell->next();
-    weak_cell->set_next(undefined, SKIP_WRITE_BARRIER);
+    weak_cell->set_next(the_hole, SKIP_WRITE_BARRIER);
   }
   heap()->set_encountered_weak_cells(Smi::FromInt(0));
 }
index 9cd08c0bff23a672c97ce94b03f47d5d3af25c1e..433fc6deab3e0efc7cb921501d7757d1c42a2688 100644 (file)
@@ -329,11 +329,11 @@ void StaticMarkingVisitor<StaticVisitor>::VisitWeakCell(Map* map,
                                                         HeapObject* object) {
   Heap* heap = map->GetHeap();
   WeakCell* weak_cell = reinterpret_cast<WeakCell*>(object);
-  Object* undefined = heap->undefined_value();
+  Object* the_hole = heap->the_hole_value();
   // Enqueue weak cell in linked list of encountered weak collections.
   // We can ignore weak cells with cleared values because they will always
   // contain smi zero.
-  if (weak_cell->next() == undefined && !weak_cell->cleared()) {
+  if (weak_cell->next() == the_hole && !weak_cell->cleared()) {
     weak_cell->set_next(heap->encountered_weak_cells(),
                         UPDATE_WEAK_WRITE_BARRIER);
     heap->set_encountered_weak_cells(weak_cell);
index 8b382c09fb1a3c047a1c22f02dd2dc3ad9703b42..026d60221dcc8fe0e22f134e3c9a861dca8279f9 100644 (file)
@@ -753,6 +753,8 @@ HeapObject* Deserializer::PostProcessNewObject(HeapObject* obj, int space) {
       new_code_objects_.Add(Code::cast(obj));
     }
   }
+  // Check alignment.
+  DCHECK_EQ(0, Heap::GetFillToAlign(obj->address(), obj->RequiredAlignment()));
   return obj;
 }
 
@@ -769,8 +771,14 @@ HeapObject* Deserializer::GetBackReferencedObject(int space) {
     uint32_t chunk_index = back_reference.chunk_index();
     DCHECK_LE(chunk_index, current_chunk_[space]);
     uint32_t chunk_offset = back_reference.chunk_offset();
-    obj = HeapObject::FromAddress(reservations_[space][chunk_index].start +
-                                  chunk_offset);
+    Address address = reservations_[space][chunk_index].start + chunk_offset;
+    if (next_alignment_ != kWordAligned) {
+      int padding = Heap::GetFillToAlign(address, next_alignment_);
+      next_alignment_ = kWordAligned;
+      DCHECK(padding == 0 || HeapObject::FromAddress(address)->IsFiller());
+      address += padding;
+    }
+    obj = HeapObject::FromAddress(address);
   }
   if (deserializing_user_code() && obj->IsInternalizedString()) {
     obj = String::cast(obj)->GetForwardedInternalizedString();
@@ -788,22 +796,25 @@ HeapObject* Deserializer::GetBackReferencedObject(int space) {
 void Deserializer::ReadObject(int space_number, Object** write_back) {
   Address address;
   HeapObject* obj;
-  int next_int = source_.GetInt();
-
-  bool double_align = false;
-#ifndef V8_HOST_ARCH_64_BIT
-  double_align = next_int == kDoubleAlignmentSentinel;
-  if (double_align) next_int = source_.GetInt();
-#endif
-
-  DCHECK_NE(kDoubleAlignmentSentinel, next_int);
-  int size = next_int << kObjectAlignmentBits;
-  int reserved_size = size + (double_align ? kPointerSize : 0);
-  address = Allocate(space_number, reserved_size);
-  obj = HeapObject::FromAddress(address);
-  if (double_align) {
-    obj = isolate_->heap()->DoubleAlignForDeserialization(obj, reserved_size);
+  int size = source_.GetInt() << kObjectAlignmentBits;
+
+  if (next_alignment_ != kWordAligned) {
+    int reserved = size + Heap::GetMaximumFillToAlign(next_alignment_);
+    address = Allocate(space_number, reserved);
+    obj = HeapObject::FromAddress(address);
+    // If one of the following assertions fails, then we are deserializing an
+    // aligned object when the filler maps have not been deserialized yet.
+    // We require filler maps as padding to align the object.
+    Heap* heap = isolate_->heap();
+    DCHECK(heap->free_space_map()->IsMap());
+    DCHECK(heap->one_pointer_filler_map()->IsMap());
+    DCHECK(heap->two_pointer_filler_map()->IsMap());
+    obj = heap->AlignWithFiller(obj, size, reserved, next_alignment_);
     address = obj->address();
+    next_alignment_ = kWordAligned;
+  } else {
+    address = Allocate(space_number, size);
+    obj = HeapObject::FromAddress(address);
   }
 
   isolate_->heap()->OnAllocationEvent(obj, size);
@@ -998,14 +1009,17 @@ bool Deserializer::ReadData(Object** current, Object** limit, int source_space,
   FOUR_CASES(byte_code + 8)               \
   FOUR_CASES(byte_code + 12)
 
+#define SINGLE_CASE(where, how, within, space) \
+  CASE_STATEMENT(where, how, within, space)    \
+  CASE_BODY(where, how, within, space)
+
       // Deserialize a new object and write a pointer to it to the current
       // object.
       ALL_SPACES(kNewObject, kPlain, kStartOfObject)
       // Support for direct instruction pointers in functions.  It's an inner
       // pointer because it points at the entry point, not at the start of the
       // code object.
-      CASE_STATEMENT(kNewObject, kPlain, kInnerPointer, CODE_SPACE)
-      CASE_BODY(kNewObject, kPlain, kInnerPointer, CODE_SPACE)
+      SINGLE_CASE(kNewObject, kPlain, kInnerPointer, CODE_SPACE)
       // Deserialize a new code object and write a pointer to its first
       // instruction to the current code object.
       ALL_SPACES(kNewObject, kFromCode, kInnerPointer)
@@ -1036,45 +1050,33 @@ bool Deserializer::ReadData(Object** current, Object** limit, int source_space,
       ALL_SPACES(kBackrefWithSkip, kPlain, kInnerPointer)
       // Find an object in the roots array and write a pointer to it to the
       // current object.
-      CASE_STATEMENT(kRootArray, kPlain, kStartOfObject, 0)
-      CASE_BODY(kRootArray, kPlain, kStartOfObject, 0)
+      SINGLE_CASE(kRootArray, kPlain, kStartOfObject, 0)
 #if defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64) || \
     defined(V8_TARGET_ARCH_PPC) || V8_EMBEDDED_CONSTANT_POOL
       // Find an object in the roots array and write a pointer to it to in code.
-      CASE_STATEMENT(kRootArray, kFromCode, kStartOfObject, 0)
-      CASE_BODY(kRootArray, kFromCode, kStartOfObject, 0)
+      SINGLE_CASE(kRootArray, kFromCode, kStartOfObject, 0)
 #endif
       // Find an object in the partial snapshots cache and write a pointer to it
       // to the current object.
-      CASE_STATEMENT(kPartialSnapshotCache, kPlain, kStartOfObject, 0)
-      CASE_BODY(kPartialSnapshotCache, kPlain, kStartOfObject, 0)
+      SINGLE_CASE(kPartialSnapshotCache, kPlain, kStartOfObject, 0)
       // Find an code entry in the partial snapshots cache and
       // write a pointer to it to the current object.
-      CASE_STATEMENT(kPartialSnapshotCache, kPlain, kInnerPointer, 0)
-      CASE_BODY(kPartialSnapshotCache, kPlain, kInnerPointer, 0)
+      SINGLE_CASE(kPartialSnapshotCache, kPlain, kInnerPointer, 0)
       // Find an external reference and write a pointer to it to the current
       // object.
-      CASE_STATEMENT(kExternalReference, kPlain, kStartOfObject, 0)
-      CASE_BODY(kExternalReference, kPlain, kStartOfObject, 0)
+      SINGLE_CASE(kExternalReference, kPlain, kStartOfObject, 0)
       // Find an external reference and write a pointer to it in the current
       // code object.
-      CASE_STATEMENT(kExternalReference, kFromCode, kStartOfObject, 0)
-      CASE_BODY(kExternalReference, kFromCode, kStartOfObject, 0)
+      SINGLE_CASE(kExternalReference, kFromCode, kStartOfObject, 0)
       // Find an object in the attached references and write a pointer to it to
       // the current object.
-      CASE_STATEMENT(kAttachedReference, kPlain, kStartOfObject, 0)
-      CASE_BODY(kAttachedReference, kPlain, kStartOfObject, 0)
-      CASE_STATEMENT(kAttachedReference, kPlain, kInnerPointer, 0)
-      CASE_BODY(kAttachedReference, kPlain, kInnerPointer, 0)
-      CASE_STATEMENT(kAttachedReference, kFromCode, kInnerPointer, 0)
-      CASE_BODY(kAttachedReference, kFromCode, kInnerPointer, 0)
+      SINGLE_CASE(kAttachedReference, kPlain, kStartOfObject, 0)
+      SINGLE_CASE(kAttachedReference, kPlain, kInnerPointer, 0)
+      SINGLE_CASE(kAttachedReference, kFromCode, kInnerPointer, 0)
       // Find a builtin and write a pointer to it to the current object.
-      CASE_STATEMENT(kBuiltin, kPlain, kStartOfObject, 0)
-      CASE_BODY(kBuiltin, kPlain, kStartOfObject, 0)
-      CASE_STATEMENT(kBuiltin, kPlain, kInnerPointer, 0)
-      CASE_BODY(kBuiltin, kPlain, kInnerPointer, 0)
-      CASE_STATEMENT(kBuiltin, kFromCode, kInnerPointer, 0)
-      CASE_BODY(kBuiltin, kFromCode, kInnerPointer, 0)
+      SINGLE_CASE(kBuiltin, kPlain, kStartOfObject, 0)
+      SINGLE_CASE(kBuiltin, kPlain, kInnerPointer, 0)
+      SINGLE_CASE(kBuiltin, kFromCode, kInnerPointer, 0)
 
 #undef CASE_STATEMENT
 #undef CASE_BODY
@@ -1169,6 +1171,15 @@ bool Deserializer::ReadData(Object** current, Object** limit, int source_space,
         break;
       }
 
+      case kAlignmentPrefix:
+      case kAlignmentPrefix + 1:
+      case kAlignmentPrefix + 2: {
+        DCHECK_EQ(kWordAligned, next_alignment_);
+        next_alignment_ =
+            static_cast<AllocationAlignment>(data - (kAlignmentPrefix - 1));
+        break;
+      }
+
       STATIC_ASSERT(kNumberOfRootArrayConstants == Heap::kOldSpaceRoots);
       STATIC_ASSERT(kNumberOfRootArrayConstants == 32);
       SIXTEEN_CASES(kRootArrayConstantsWithSkip)
@@ -1235,6 +1246,7 @@ bool Deserializer::ReadData(Object** current, Object** limit, int source_space,
 
 #undef SIXTEEN_CASES
 #undef FOUR_CASES
+#undef SINGLE_CASE
 
       default:
         CHECK(false);
@@ -1562,6 +1574,7 @@ bool Serializer::SerializeKnownObject(HeapObject* obj, HowToCode how_to_code,
         PrintF("\n");
       }
 
+      PutAlignmentPrefix(obj);
       AllocationSpace space = back_reference.space();
       if (skip == 0) {
         sink_->Put(kBackref + how_to_code + where_to_point + space, "BackRef");
@@ -1655,6 +1668,18 @@ void Serializer::PutBackReference(HeapObject* object, BackReference reference) {
 }
 
 
+int Serializer::PutAlignmentPrefix(HeapObject* object) {
+  AllocationAlignment alignment = object->RequiredAlignment();
+  if (alignment != kWordAligned) {
+    DCHECK(1 <= alignment && alignment <= 3);
+    byte prefix = (kAlignmentPrefix - 1) + alignment;
+    sink_->Put(prefix, "Alignment");
+    return Heap::GetMaximumFillToAlign(alignment);
+  }
+  return 0;
+}
+
+
 void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
                                         WhereToPoint where_to_point, int skip) {
   if (obj->IsMap()) {
@@ -1736,21 +1761,10 @@ void Serializer::ObjectSerializer::SerializePrologue(AllocationSpace space,
     }
     back_reference = serializer_->AllocateLargeObject(size);
   } else {
-    bool needs_double_align = false;
-    // TODO(bbudge): Generalize to other alignment constraints.
-    if (object_->RequiredAlignment() == kDoubleAligned) {
-      // Add wriggle room for double alignment padding.
-      back_reference = serializer_->Allocate(space, size + kPointerSize);
-      needs_double_align = true;
-    } else {
-      back_reference = serializer_->Allocate(space, size);
-    }
+    int fill = serializer_->PutAlignmentPrefix(object_);
+    back_reference = serializer_->Allocate(space, size + fill);
     sink_->Put(kNewObject + reference_representation_ + space, "NewObject");
-    if (needs_double_align)
-      sink_->PutInt(kDoubleAlignmentSentinel, "DoubleAlignSentinel");
-    int encoded_size = size >> kObjectAlignmentBits;
-    DCHECK_NE(kDoubleAlignmentSentinel, encoded_size);
-    sink_->PutInt(encoded_size, "ObjectSizeInWords");
+    sink_->PutInt(size >> kObjectAlignmentBits, "ObjectSizeInWords");
   }
 
 #ifdef OBJECT_PRINT
index 089c323b7de7db8588fc666e43e27a1528cdf4d9..2a426a94f587de9e239fc87950afaec447e12f86 100644 (file)
@@ -324,12 +324,14 @@ class SerializerDeserializer: public ObjectVisitor {
     // 0x07        Unused (including 0x27, 0x47, 0x67).
     // 0x08..0x0c  Reference to previous object from space.
     kBackref = 0x08,
+    // 0x0d        Unused (including 0x2d, 0x4d, 0x6d).
     // 0x0e        Unused (including 0x2e, 0x4e, 0x6e).
     // 0x0f        Unused (including 0x2f, 0x4f, 0x6f).
     // 0x10..0x14  Reference to previous object from space after skip.
     kBackrefWithSkip = 0x10,
+    // 0x15        Unused (including 0x35, 0x55, 0x75).
     // 0x16        Unused (including 0x36, 0x56, 0x76).
-    // 0x17        Unused (including 0x37, 0x57, 0x77).
+    // 0x17        Misc (including 0x37, 0x57, 0x77).
     // 0x18        Root array item.
     kRootArray = 0x18,
     // 0x19        Object in the partial snapshot cache.
@@ -384,14 +386,18 @@ class SerializerDeserializer: public ObjectVisitor {
   // is an indication that the snapshot and the VM do not fit together.
   // Examine the build process for architecture, version or configuration
   // mismatches.
-  static const int kSynchronize = 0x5d;
+  static const int kSynchronize = 0x17;
   // Used for the source code of the natives, which is in the executable, but
   // is referred to from external strings in the snapshot.
-  static const int kNativesStringResource = 0x5e;
+  static const int kNativesStringResource = 0x37;
   // Raw data of variable length.
-  static const int kVariableRawData = 0x7d;
+  static const int kVariableRawData = 0x57;
   // Repeats of variable length.
-  static const int kVariableRepeat = 0x7e;
+  static const int kVariableRepeat = 0x77;
+  // Alignment prefixes 0x7d..0x7f
+  static const int kAlignmentPrefix = 0x7d;
+
+  // 0x5d..0x5f unused
 
   // ---------- byte code range 0x80..0xff ----------
   // First 32 root array items.
@@ -515,7 +521,8 @@ class Deserializer: public SerializerDeserializer {
         magic_number_(data->GetMagicNumber()),
         external_reference_table_(NULL),
         deserialized_large_objects_(0),
-        deserializing_user_code_(false) {
+        deserializing_user_code_(false),
+        next_alignment_(kWordAligned) {
     DecodeReservation(data->Reservations());
   }
 
@@ -602,6 +609,8 @@ class Deserializer: public SerializerDeserializer {
 
   bool deserializing_user_code_;
 
+  AllocationAlignment next_alignment_;
+
   DISALLOW_COPY_AND_ASSIGN(Deserializer);
 };
 
@@ -706,6 +715,9 @@ class Serializer : public SerializerDeserializer {
 
   void PutBackReference(HeapObject* object, BackReference reference);
 
+  // Emit alignment prefix if necessary, return required padding space in bytes.
+  int PutAlignmentPrefix(HeapObject* object);
+
   // Returns true if the object was successfully serialized.
   bool SerializeKnownObject(HeapObject* obj, HowToCode how_to_code,
                             WhereToPoint where_to_point, int skip);