Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index ae8409e13f2bac649e97a83596bf854735ce324c..886d26a22d0d5bfd4b0ea752612d23387ba6d419 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -1922,6 +1922,50 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) { |
} |
+// Returns true if during migration from |old_map| to |new_map| "tagged" |
+// inobject fields are going to be replaced with unboxed double fields. |
+static bool ShouldClearSlotsRecorded(Map* old_map, Map* new_map, |
+ int new_number_of_fields) { |
+ DisallowHeapAllocation no_gc; |
+ int inobject = new_map->inobject_properties(); |
+ DCHECK(inobject <= old_map->inobject_properties()); |
+ |
+ int limit = Min(inobject, new_number_of_fields); |
+ for (int i = 0; i < limit; i++) { |
+ FieldIndex index = FieldIndex::ForPropertyIndex(new_map, i); |
+ if (new_map->IsUnboxedDoubleField(index) && |
+ !old_map->IsUnboxedDoubleField(index)) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+ |
+static void RemoveOldToOldSlotsRecorded(Heap* heap, JSObject* object, |
+ FieldIndex index) { |
+ DisallowHeapAllocation no_gc; |
+ |
+ Object* old_value = object->RawFastPropertyAt(index); |
+ if (old_value->IsHeapObject()) { |
+ HeapObject* ho = HeapObject::cast(old_value); |
+ if (heap->InNewSpace(ho)) { |
+ // At this point there must be no old-to-new slots recorded for this |
+ // object. |
+ SLOW_DCHECK( |
+ !heap->store_buffer()->CellIsInStoreBuffer(reinterpret_cast<Address>( |
+ HeapObject::RawField(object, index.offset())))); |
+ } else { |
+ Page* p = Page::FromAddress(reinterpret_cast<Address>(ho)); |
+ if (p->IsEvacuationCandidate()) { |
+ Object** slot = HeapObject::RawField(object, index.offset()); |
+ SlotsBuffer::RemoveSlot(p->slots_buffer(), slot); |
+ } |
+ } |
+ } |
+} |
+ |
+ |
// To migrate a fast instance to a fast map: |
// - First check whether the instance needs to be rewritten. If not, simply |
// change the map. |
@@ -2075,16 +2119,32 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { |
// From here on we cannot fail and we shouldn't GC anymore. |
DisallowHeapAllocation no_allocation; |
+ Heap* heap = isolate->heap(); |
+ |
+ // If we are going to put an unboxed double to the field that used to |
+ // contain HeapObject we should ensure that this slot is removed from |
+ // both StoreBuffer and respective SlotsBuffer. |
+ bool clear_slots_recorded = |
+ FLAG_unbox_double_fields && !heap->InNewSpace(object->address()) && |
+ ShouldClearSlotsRecorded(*old_map, *new_map, number_of_fields); |
+ if (clear_slots_recorded) { |
+ Address obj_address = object->address(); |
+ Address start_address = obj_address + JSObject::kHeaderSize; |
+ Address end_address = obj_address + old_map->instance_size(); |
+ heap->store_buffer()->RemoveSlots(start_address, end_address); |
+ } |
+ |
// Copy (real) inobject properties. If necessary, stop at number_of_fields to |
// avoid overwriting |one_pointer_filler_map|. |
int limit = Min(inobject, number_of_fields); |
for (int i = 0; i < limit; i++) { |
FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i); |
Object* value = array->get(external + i); |
- // Can't use JSObject::FastPropertyAtPut() because proper map was not set |
- // yet. |
if (new_map->IsUnboxedDoubleField(index)) { |
DCHECK(value->IsMutableHeapNumber()); |
+ if (clear_slots_recorded && !old_map->IsUnboxedDoubleField(index)) { |
+ RemoveOldToOldSlotsRecorded(heap, *object, index); |
+ } |
object->RawFastDoublePropertyAtPut(index, |
HeapNumber::cast(value)->value()); |
} else { |
@@ -2092,8 +2152,6 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { |
} |
} |
- Heap* heap = isolate->heap(); |
- |
// If there are properties in the new backing store, trim it to the correct |
// size and install the backing store into the object. |
if (external > 0) { |