Commit 6b5e4439 authored by ulan's avatar ulan Committed by Commit bot

[heap] Fix verification of unsafe object layout changes.

This patch adds HeapObject::set_map_after_allocation method that
initializes the map of the object without object layout checks.

All other map setters now check that transitions unsafe for
concurrent marking properly notify the GC.

BUG=chromium:694255

Review-Url: https://codereview.chromium.org/2885883004
Cr-Commit-Position: refs/heads/master@{#45403}
parent f4da4361
......@@ -193,6 +193,8 @@ class ConcurrentMarkingVisitor final
};
const SlotSnapshot& MakeSlotSnapshot(Map* map, HeapObject* object, int size) {
// TODO(ulan): Iterate only the existing fields and skip slack at the end
// of the object.
SlotSnapshottingVisitor visitor(&slot_snapshot_);
visitor.VisitPointer(object,
reinterpret_cast<Object**>(object->map_slot()));
......
......@@ -235,7 +235,7 @@ AllocationResult Heap::AllocateOneByteInternalizedString(
}
// String maps are all immortal immovable objects.
result->set_map_no_write_barrier(map);
result->set_map_after_allocation(map, SKIP_WRITE_BARRIER);
// Set length and hash fields of the allocated string.
String* answer = String::cast(result);
answer->set_length(str.length());
......@@ -266,7 +266,7 @@ AllocationResult Heap::AllocateTwoByteInternalizedString(Vector<const uc16> str,
if (!allocation.To(&result)) return allocation;
}
result->set_map(map);
result->set_map_after_allocation(map);
// Set length and hash fields of the allocated string.
String* answer = String::cast(result);
answer->set_length(str.length());
......
This diff is collapsed.
......@@ -1466,21 +1466,22 @@ Isolate* HeapObject::GetIsolate() const {
return GetHeap()->isolate();
}
Map* HeapObject::map() const {
return map_word().ToMap();
}
void HeapObject::set_map(Map* value) {
if (value != nullptr) {
#ifdef VERIFY_HEAP
value->GetHeap()->VerifyObjectLayoutChange(this, value);
#endif
}
set_map_word(MapWord::FromMap(value));
if (value != nullptr) {
// TODO(1600) We are passing NULL as a slot because maps can never be on
// evacuation candidate.
value->GetHeap()->incremental_marking()->RecordWrite(this, nullptr, value);
#ifdef VERIFY_HEAP
value->GetHeap()->VerifyObjectLayoutChange(this, value);
#endif
}
}
......@@ -1491,26 +1492,38 @@ Map* HeapObject::synchronized_map() {
void HeapObject::synchronized_set_map(Map* value) {
synchronized_set_map_word(MapWord::FromMap(value));
if (value != nullptr) {
// TODO(1600) We are passing NULL as a slot because maps can never be on
// evacuation candidate.
value->GetHeap()->incremental_marking()->RecordWrite(this, nullptr, value);
#ifdef VERIFY_HEAP
value->GetHeap()->VerifyObjectLayoutChange(this, value);
#endif
}
}
void HeapObject::synchronized_set_map_no_write_barrier(Map* value) {
synchronized_set_map_word(MapWord::FromMap(value));
if (value != nullptr) {
// TODO(1600) We are passing NULL as a slot because maps can never be on
// evacuation candidate.
value->GetHeap()->incremental_marking()->RecordWrite(this, nullptr, value);
}
}
// Unsafe accessor omitting write barrier.
void HeapObject::set_map_no_write_barrier(Map* value) {
if (value != nullptr) {
#ifdef VERIFY_HEAP
value->GetHeap()->VerifyObjectLayoutChange(this, value);
#endif
}
set_map_word(MapWord::FromMap(value));
}
void HeapObject::set_map_after_allocation(Map* value, WriteBarrierMode mode) {
set_map_word(MapWord::FromMap(value));
if (mode != SKIP_WRITE_BARRIER) {
DCHECK(value != nullptr);
// TODO(1600) We are passing NULL as a slot because maps can never be on
// evacuation candidate.
value->GetHeap()->incremental_marking()->RecordWrite(this, nullptr, value);
}
}
HeapObject** HeapObject::map_slot() {
......
......@@ -3338,8 +3338,8 @@ const char* Representation::Mnemonic() const {
}
bool Map::TransitionRemovesTaggedField(Map* target) {
int inobject = GetInObjectProperties();
int target_inobject = target->GetInObjectProperties();
int inobject = NumberOfFields();
int target_inobject = target->NumberOfFields();
for (int i = target_inobject; i < inobject; i++) {
FieldIndex index = FieldIndex::ForPropertyIndex(this, i);
if (!IsUnboxedDoubleField(index)) return true;
......@@ -3348,8 +3348,8 @@ bool Map::TransitionRemovesTaggedField(Map* target) {
}
bool Map::TransitionChangesTaggedFieldToUntaggedField(Map* target) {
int inobject = GetInObjectProperties();
int target_inobject = target->GetInObjectProperties();
int inobject = NumberOfFields();
int target_inobject = target->NumberOfFields();
int limit = Min(inobject, target_inobject);
for (int i = 0; i < limit; i++) {
FieldIndex index = FieldIndex::ForPropertyIndex(target, i);
......
......@@ -1683,9 +1683,13 @@ class HeapObject: public Object {
// Set the map using release store
inline void synchronized_set_map(Map* value);
inline void synchronized_set_map_no_write_barrier(Map* value);
inline void synchronized_set_map_word(MapWord map_word);
// Initialize the map immediately after the object is allocated.
// Do not use this outside Heap.
inline void set_map_after_allocation(
Map* value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
// During garbage collection, the map word of a heap object does not
// necessarily contain a map pointer.
inline MapWord map_word() const;
......
......@@ -130,6 +130,7 @@ namespace {
bool DeleteObjectPropertyFast(Isolate* isolate, Handle<JSReceiver> receiver,
Handle<Object> raw_key) {
DisallowHeapAllocation no_allocation;
// This implements a special case for fast property deletion: when the
// last property in an object is deleted, then instead of normalizing
// the properties, we can undo the last map transition, with a few
......@@ -160,6 +161,7 @@ bool DeleteObjectPropertyFast(Isolate* isolate, Handle<JSReceiver> receiver,
// Zap the property to avoid keeping objects alive. Zapping is not necessary
// for properties stored in the descriptor array.
if (details.location() == kField) {
isolate->heap()->NotifyObjectLayoutChange(*receiver, no_allocation);
Object* filler = isolate->heap()->one_pointer_filler_map();
FieldIndex index = FieldIndex::ForPropertyIndex(map, details.field_index());
JSObject::cast(*receiver)->RawFastPropertyAtPut(index, filler);
......
......@@ -57,7 +57,8 @@ static void SetUpNewSpaceWithPoisonedMementoAtTop() {
// site pointer.
AllocationMemento* memento =
reinterpret_cast<AllocationMemento*>(new_space->top() + kHeapObjectTag);
memento->set_map_no_write_barrier(heap->allocation_memento_map());
memento->set_map_after_allocation(heap->allocation_memento_map(),
SKIP_WRITE_BARRIER);
memento->set_allocation_site(
reinterpret_cast<AllocationSite*>(kHeapObjectTag), SKIP_WRITE_BARRIER);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment