Do not call Heap::IterateAndMarkPointersToFromSpace() for unboxed double fields.
authorishell <ishell@chromium.org>
Mon, 1 Dec 2014 14:19:11 +0000 (06:19 -0800)
committerCommit bot <commit-bot@chromium.org>
Mon, 1 Dec 2014 14:19:29 +0000 (14:19 +0000)
BUG=chromium:437143
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#25585}

src/heap/heap.cc
test/cctest/test-unboxed-doubles.cc

index 8415de1..b1738ee 100644 (file)
@@ -1800,8 +1800,29 @@ Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
         // for pointers to from semispace instead of looking for pointers
         // to new space.
         DCHECK(!target->IsMap());
-        IterateAndMarkPointersToFromSpace(
-            target->address(), target->address() + size, &ScavengeObject);
+        Address start_address = target->address();
+        Address end_address = start_address + size;
+#if V8_DOUBLE_FIELDS_UNBOXING
+        InobjectPropertiesHelper helper(target->map());
+        bool has_only_tagged_fields = helper.all_fields_tagged();
+
+        if (!has_only_tagged_fields) {
+          for (Address slot = start_address; slot < end_address;
+               slot += kPointerSize) {
+            if (helper.IsTagged(static_cast<int>(slot - start_address))) {
+              // TODO(ishell): call this once for contiguous region
+              // of tagged fields.
+              IterateAndMarkPointersToFromSpace(slot, slot + kPointerSize,
+                                                &ScavengeObject);
+            }
+          }
+        } else {
+#endif
+          IterateAndMarkPointersToFromSpace(start_address, end_address,
+                                            &ScavengeObject);
+#if V8_DOUBLE_FIELDS_UNBOXING
+        }
+#endif
       }
     }
 
index 8b2c473..1482a7b 100644 (file)
@@ -648,6 +648,66 @@ TEST(Regress436816) {
 }
 
 
+TEST(DoScavenge) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  v8::HandleScope scope(CcTest::isolate());
+
+  CompileRun(
+      "function A() {"
+      "  this.x = 42.5;"
+      "  this.o = {};"
+      "};"
+      "var o = new A();");
+
+  Handle<String> obj_name = factory->InternalizeUtf8String("o");
+
+  Handle<Object> obj_value =
+      Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked();
+  CHECK(obj_value->IsJSObject());
+  Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
+
+  {
+    // Ensure the object is properly set up.
+    Map* map = obj->map();
+    DescriptorArray* descriptors = map->instance_descriptors();
+    CHECK(map->NumberOfOwnDescriptors() == 2);
+    CHECK(descriptors->GetDetails(0).representation().IsDouble());
+    CHECK(descriptors->GetDetails(1).representation().IsHeapObject());
+    FieldIndex field_index = FieldIndex::ForDescriptor(map, 0);
+    CHECK(field_index.is_inobject() && field_index.is_double());
+    CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
+    CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
+  }
+  CHECK(isolate->heap()->new_space()->Contains(*obj));
+
+  // Trigger GCs so that the newly allocated object moves to old gen.
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
+
+  // Create temp object in the new space.
+  Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED);
+  CHECK(isolate->heap()->new_space()->Contains(*temp));
+
+  // Construct a double value that looks like a pointer to the new space object
+  // and store it into the obj.
+  Address fake_object = reinterpret_cast<Address>(*temp) + kPointerSize;
+  double boom_value = bit_cast<double>(fake_object);
+
+  FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0);
+  Handle<HeapNumber> boom_number = factory->NewHeapNumber(boom_value, MUTABLE);
+  obj->FastPropertyAtPut(field_index, *boom_number);
+
+  // Now the object moves to old gen and it has a double field that looks like
+  // a pointer to a from semi-space.
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
+
+  CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
+
+  CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
+}
+
+
 TEST(StoreBufferScanOnScavenge) {
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();