Reviewers: Toon Verwaest,

Message:
PTAL

Description:
Fast-to-slow migration should wipe out unboxed double fields if they still
reside in the object after migration.

BUG=chromium:436816
LOG=N

Please review this at https://codereview.chromium.org/765473004/

Base URL: https://chromium.googlesource.com/v8/v8.git@master

Affected files (+60, -2 lines):
  M src/objects.h
  M src/objects.cc
  M src/objects-inl.h
  M test/cctest/test-unboxed-doubles.cc


Index: src/objects-inl.h
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 03aea64736d818f456c748f76a31d583593dc664..90a39df3ac588a673d218137b3c76b70c78c6fbf 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2124,6 +2124,12 @@ void JSObject::RawFastDoublePropertyAtPut(FieldIndex index, double value) {
 }


+void JSObject::WipeOutFastPropertyAt(FieldIndex index) {
+  DCHECK(index.is_inobject());
+  WRITE_FIELD(this, index.offset(), Smi::FromInt(0));
+}
+
+
 void JSObject::FastPropertyAtPut(FieldIndex index, Object* value) {
   if (IsUnboxedDoubleField(index)) {
     DCHECK(value->IsMutableHeapNumber());
@@ -5331,7 +5337,7 @@ void Map::AppendDescriptor(Descriptor* desc) {

 Object* Map::GetBackPointer() {
   Object* object = READ_FIELD(this, kTransitionsOrBackPointerOffset);
-  if (object->IsDescriptorArray()) {
+  if (object->IsTransitionArray()) {
     return TransitionArray::cast(object)->back_pointer_storage();
   } else {
     DCHECK(object->IsMap() || object->IsUndefined());
Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index bd0c2fd4bef0b7f764edd3a178ba024a8dc553c0..d115e31ffb95bd2d6586aa8b7f76491d701bc302 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -4353,6 +4353,8 @@ void JSObject::MigrateFastToSlow(Handle<JSObject> object,
   Handle<NameDictionary> dictionary =
       NameDictionary::New(isolate, property_count);

+  int new_instance_size = new_map->instance_size();
+
   Handle<DescriptorArray> descs(map->instance_descriptors());
   for (int i = 0; i < real_size; i++) {
     PropertyDetails details = descs->GetDetails(i);
@@ -4371,6 +4373,11 @@ void JSObject::MigrateFastToSlow(Handle<JSObject> object,
         if (object->IsUnboxedDoubleField(index)) {
           double old_value = object->RawFastDoublePropertyAt(index);
           value = isolate->factory()->NewHeapNumber(old_value);
+          if (index.offset() < new_instance_size) {
+ // Ensure that unused in-object space of slow-mode object does not
+            // contain random garbage.
+            object->WipeOutFastPropertyAt(index);
+          }
         } else {
           value = handle(object->RawFastPropertyAt(index), isolate);
           if (details.representation().IsDouble()) {
@@ -4400,7 +4407,6 @@ void JSObject::MigrateFastToSlow(Handle<JSObject> object,
   DisallowHeapAllocation no_allocation;

   // Resize the object in the heap if necessary.
-  int new_instance_size = new_map->instance_size();
   int instance_size_delta = map->instance_size() - new_instance_size;
   DCHECK(instance_size_delta >= 0);

Index: src/objects.h
diff --git a/src/objects.h b/src/objects.h
index 746f88d1c4c0c10083e63263a005f79ec4378b9d..e564e3522533fabd06c4e80da9b1ed2725e8fe5c 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -2074,6 +2074,7 @@ class JSObject: public JSReceiver {
   inline void FastPropertyAtPut(FieldIndex index, Object* value);
   inline void RawFastPropertyAtPut(FieldIndex index, Object* value);
   inline void RawFastDoublePropertyAtPut(FieldIndex index, double value);
+  inline void WipeOutFastPropertyAt(FieldIndex index);
   void WriteToField(int descriptor, Object* value);

   // Access to in object properties.
Index: test/cctest/test-unboxed-doubles.cc
diff --git a/test/cctest/test-unboxed-doubles.cc b/test/cctest/test-unboxed-doubles.cc index db1aaaf5c6744fda11d1a1ed7e5cb8622988dcc1..178bc23d10deb4861b4a3254b456cdd5ac7fe26e 100644
--- a/test/cctest/test-unboxed-doubles.cc
+++ b/test/cctest/test-unboxed-doubles.cc
@@ -603,6 +603,51 @@ TEST(LayoutDescriptorAppendIfFastOrUseFullAllDoubles) {
 }


+TEST(Regress436820) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  v8::HandleScope scope(CcTest::isolate());
+
+  const int kPropsCount = kSmiValueSize * 3;
+  PropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_DOUBLE;
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  Handle<Map> map = Map::Create(isolate, kPropsCount);
+  Handle<LayoutDescriptor> layout_descriptor =
+      LayoutDescriptor::New(map, descriptors, kPropsCount);
+  map->InitializeDescriptors(*descriptors, *layout_descriptor);
+
+  Handle<JSObject> object = factory->NewJSObjectFromMap(map, TENURED);
+
+  Address fake_address = reinterpret_cast<Address>(~kHeapObjectTagMask);
+  HeapObject* fake_object = HeapObject::FromAddress(fake_address);
+  CHECK(fake_object->IsHeapObject());
+
+  double boom_value = bit_cast<double>(fake_object);
+  for (int i = 0; i < kPropsCount; i++) {
+    FieldIndex index = FieldIndex::ForDescriptor(*map, i);
+    CHECK(map->IsUnboxedDoubleField(index));
+    object->RawFastDoublePropertyAtPut(index, boom_value);
+  }
+  CHECK(object->HasFastProperties());
+  CHECK(!object->map()->HasFastPointerLayout());
+
+  Handle<Map> normalized_map =
+      Map::Normalize(map, KEEP_INOBJECT_PROPERTIES, "testing");
+  JSObject::MigrateToMap(object, normalized_map);
+  CHECK(!object->HasFastProperties());
+  CHECK(object->map()->HasFastPointerLayout());
+
+  // Trigger GCs and heap verification.
+  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+}
+
+
 TEST(StoreBufferScanOnScavenge) {
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to