From 4590e4f4d617797939655efe986c134925a1a372 Mon Sep 17 00:00:00 2001 From: yangguo Date: Thu, 27 Nov 2014 01:22:10 -0800 Subject: [PATCH] Ensure double alignment when deserializing. R=rmcilroy@chromium.org BUG=chromium:436510 LOG=N TEST=compile with V8_OOL_CONSTANT_POOL=1, run d8 with --verify-heap --test Review URL: https://codereview.chromium.org/759823006 Cr-Commit-Position: refs/heads/master@{#25534} --- src/heap/heap.cc | 5 +++++ src/heap/heap.h | 2 ++ src/objects-debug.cc | 4 ++++ src/objects-inl.h | 11 +++++++++++ src/objects.h | 2 ++ src/serialize.cc | 42 ++++++++++++++++++++++++++++++++++-------- src/serialize.h | 21 +++++++++++++-------- 7 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/heap/heap.cc b/src/heap/heap.cc index e387193..22ba7a9 100644 --- a/src/heap/heap.cc +++ b/src/heap/heap.cc @@ -1829,6 +1829,11 @@ static HeapObject* EnsureDoubleAligned(Heap* heap, HeapObject* object, } +HeapObject* Heap::DoubleAlignForDeserialization(HeapObject* object, int size) { + return EnsureDoubleAligned(this, object, size); +} + + enum LoggingAndProfiling { LOGGING_AND_PROFILING_ENABLED, LOGGING_AND_PROFILING_DISABLED diff --git a/src/heap/heap.h b/src/heap/heap.h index eeb8322..b84ccaa 100644 --- a/src/heap/heap.h +++ b/src/heap/heap.h @@ -1726,6 +1726,8 @@ class Heap { return (pretenure == TENURED) ? preferred_old_space : NEW_SPACE; } + HeapObject* DoubleAlignForDeserialization(HeapObject* object, int size); + // Allocate an uninitialized object. The memory is non-executable if the // hardware and OS allow. This is the single choke-point for allocations // performed by the runtime and should not be bypassed (to extend this to diff --git a/src/objects-debug.cc b/src/objects-debug.cc index 0e67099..e49b47c 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -47,6 +47,10 @@ void HeapObject::HeapObjectVerify() { return; } + // TODO(yangguo): Use this check once crbug/436911 has been fixed. + // DCHECK(!NeedsToEnsureDoubleAlignment() || + // IsAligned(OffsetFrom(address()), kDoubleAlignment)); + switch (instance_type) { case SYMBOL_TYPE: Symbol::cast(this)->SymbolVerify(); diff --git a/src/objects-inl.h b/src/objects-inl.h index 03aea64..b05de47 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -2758,6 +2758,17 @@ WriteBarrierMode HeapObject::GetWriteBarrierMode( } +bool HeapObject::NeedsToEnsureDoubleAlignment() { +#ifndef V8_HOST_ARCH_64_BIT + return (IsFixedFloat64Array() || IsFixedDoubleArray() || + IsConstantPoolArray()) && + FixedArrayBase::cast(this)->length() != 0; +#else + return false; +#endif // V8_HOST_ARCH_64_BIT +} + + void FixedArray::set(int index, Object* value, WriteBarrierMode mode) { diff --git a/src/objects.h b/src/objects.h index 746f88d..8d6169e 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1443,6 +1443,8 @@ class HeapObject: public Object { static void VerifyHeapPointer(Object* p); #endif + inline bool NeedsToEnsureDoubleAlignment(); + // Layout description. // First field in a heap object is map. static const int kMapOffset = Object::kHeaderSize; diff --git a/src/serialize.cc b/src/serialize.cc index c2dd338..db90792 100644 --- a/src/serialize.cc +++ b/src/serialize.cc @@ -807,11 +807,27 @@ Object* Deserializer::ProcessBackRefInSerializedCode(Object* obj) { // The reason for this strange interface is that otherwise the object is // written very late, which means the FreeSpace map is not set up by the // time we need to use it to mark the space at the end of a page free. -void Deserializer::ReadObject(int space_number, - Object** write_back) { - int size = source_->GetInt() << kObjectAlignmentBits; - Address address = Allocate(space_number, size); - HeapObject* obj = HeapObject::FromAddress(address); +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); + address = obj->address(); + } + isolate_->heap()->OnAllocationEvent(obj, size); Object** current = reinterpret_cast(address); Object** limit = current + (size >> kPointerSizeLog2); @@ -1549,9 +1565,19 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code, void Serializer::ObjectSerializer::SerializePrologue(AllocationSpace space, int size, Map* map) { + int reserved_size = size; + sink_->Put(kNewObject + reference_representation_ + space, "ObjectSerialization"); - sink_->PutInt(size >> kObjectAlignmentBits, "Size in words"); + // Objects on the large object space are always double-aligned. + if (space != LO_SPACE && object_->NeedsToEnsureDoubleAlignment()) { + sink_->PutInt(kDoubleAlignmentSentinel, "double align next object"); + // Add wriggle room for double alignment padding. + reserved_size += kPointerSize; + } + int encoded_size = size >> kObjectAlignmentBits; + DCHECK_NE(kDoubleAlignmentSentinel, encoded_size); + sink_->PutInt(encoded_size, "Size in words"); if (serializer_->code_address_map_) { const char* code_name = @@ -1572,7 +1598,7 @@ void Serializer::ObjectSerializer::SerializePrologue(AllocationSpace space, } back_reference = serializer_->AllocateLargeObject(size); } else { - back_reference = serializer_->Allocate(space, size); + back_reference = serializer_->Allocate(space, reserved_size); } serializer_->back_reference_map()->Add(object_, back_reference); @@ -1918,7 +1944,7 @@ BackReference Serializer::AllocateLargeObject(int size) { BackReference Serializer::Allocate(AllocationSpace space, int size) { - CHECK(space >= 0 && space < kNumberOfPreallocatedSpaces); + DCHECK(space >= 0 && space < kNumberOfPreallocatedSpaces); DCHECK(size > 0 && size <= static_cast(max_chunk_size(space))); uint32_t new_chunk_size = pending_chunk_[space] + size; if (new_chunk_size > max_chunk_size(space)) { diff --git a/src/serialize.h b/src/serialize.h index 1c78113..36854b1 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -301,20 +301,20 @@ class SerializerDeserializer: public ObjectVisitor { protected: // Where the pointed-to object can be found: enum Where { - kNewObject = 0, // Object is next in snapshot. - // 1-7 One per space. + kNewObject = 0, // Object is next in snapshot. + // 1-7 One per space. kRootArray = 0x9, // Object is found in root array. kPartialSnapshotCache = 0xa, // Object is in the cache. kExternalReference = 0xb, // Pointer to an external reference. kSkip = 0xc, // Skip n bytes. kBuiltin = 0xd, // Builtin code object. kAttachedReference = 0xe, // Object is described in an attached list. - kNop = 0xf, // Does nothing, used to pad. - kBackref = 0x10, // Object is described relative to end. - // 0x11-0x17 One per space. - kBackrefWithSkip = 0x18, // Object is described relative to end. - // 0x19-0x1f One per space. - // 0x20-0x3f Used by misc. tags below. + // 0xf Used by misc. See below. + kBackref = 0x10, // Object is described relative to end. + // 0x11-0x17 One per space. + kBackrefWithSkip = 0x18, // Object is described relative to end. + // 0x19-0x1f One per space. + // 0x20-0x3f Used by misc. See below. kPointedToMask = 0x3f }; @@ -375,11 +375,16 @@ class SerializerDeserializer: public ObjectVisitor { return byte_code & 0x1f; } + static const int kNop = 0xf; // Do nothing, used for padding. + static const int kAnyOldSpace = -1; // A bitmask for getting the space out of an instruction. static const int kSpaceMask = 7; STATIC_ASSERT(kNumberOfSpaces <= kSpaceMask + 1); + + // Sentinel after a new object to indicate that double alignment is needed. + static const int kDoubleAlignmentSentinel = 0; }; -- 2.7.4