Serializer: support all alignment kinds.

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

Committed: https://crrev.com/2146ab75387d47eef6582bd8c2d0cfc6c42b68b6
Cr-Commit-Position: refs/heads/master@{#29044}

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

Cr-Commit-Position: refs/heads/master@{#29047}
This commit is contained in:
yangguo 2015-06-16 04:04:13 -07:00 committed by Commit bot
parent e2ce468165
commit 63f4c75162
6 changed files with 100 additions and 75 deletions

View 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);

View 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());
}

View 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));
}

View 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);

View 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();
int size = source_.GetInt() << kObjectAlignmentBits;
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);
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

View 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);