From c81e9f5970ee07b05d8fddf0782d0a841d508a9e Mon Sep 17 00:00:00 2001 From: ishell Date: Mon, 1 Dec 2014 06:19:11 -0800 Subject: [PATCH] Do not call Heap::IterateAndMarkPointersToFromSpace() for unboxed double fields. BUG=chromium:437143 LOG=N Review URL: https://codereview.chromium.org/768113002 Cr-Commit-Position: refs/heads/master@{#25585} --- src/heap/heap.cc | 25 +++++++++++- test/cctest/test-unboxed-doubles.cc | 60 +++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/src/heap/heap.cc b/src/heap/heap.cc index 8415de1901..b1738ee725 100644 --- a/src/heap/heap.cc +++ b/src/heap/heap.cc @@ -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(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 } } diff --git a/test/cctest/test-unboxed-doubles.cc b/test/cctest/test-unboxed-doubles.cc index 8b2c47357f..1482a7bf0d 100644 --- a/test/cctest/test-unboxed-doubles.cc +++ b/test/cctest/test-unboxed-doubles.cc @@ -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 obj_name = factory->InternalizeUtf8String("o"); + + Handle obj_value = + Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked(); + CHECK(obj_value->IsJSObject()); + Handle obj = Handle::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 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
(*temp) + kPointerSize; + double boom_value = bit_cast(fake_object); + + FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0); + Handle 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();