| Index: test/cctest/test-unboxed-doubles.cc | 
| diff --git a/test/cctest/test-unboxed-doubles.cc b/test/cctest/test-unboxed-doubles.cc | 
| index ca78455531bd2aad25469d32c3957836f0fc4b82..a783ce626f465e5eedcc33fd7bd7e3c1677a84e3 100644 | 
| --- a/test/cctest/test-unboxed-doubles.cc | 
| +++ b/test/cctest/test-unboxed-doubles.cc | 
| @@ -1223,4 +1223,89 @@ TEST(StoreBufferScanOnScavenge) { | 
| CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index)); | 
| } | 
|  | 
| + | 
| +static int LenFromSize(int size) { | 
| +  return (size - FixedArray::kHeaderSize) / kPointerSize; | 
| +} | 
| + | 
| + | 
| +TEST(WriteBarriersInCopyJSObject) { | 
| +  FLAG_max_semi_space_size = 1;  // Ensure new space is not growing. | 
| +  CcTest::InitializeVM(); | 
| +  Isolate* isolate = CcTest::i_isolate(); | 
| +  TestHeap* heap = CcTest::test_heap(); | 
| + | 
| +  v8::HandleScope scope(CcTest::isolate()); | 
| + | 
| +  // The plan: create JSObject which contains unboxed double value that looks | 
| +  // like a reference to an object in new space. | 
| +  // Then clone this object (forcing it to go into old space) and check | 
| +  // that the value of the unboxed double property of the cloned object has | 
| +  // was not corrupted by GC. | 
| + | 
| +  // Step 1: prepare a map for the object. We add unboxed double property to it. | 
| +  // Create a map with single inobject property. | 
| +  Handle<Map> my_map = Map::Create(isolate, 1); | 
| +  Handle<String> name = isolate->factory()->InternalizeUtf8String("foo"); | 
| +  my_map = Map::CopyWithField(my_map, name, HeapType::Any(isolate), NONE, | 
| +                              Representation::Double(), | 
| +                              INSERT_TRANSITION).ToHandleChecked(); | 
| +  my_map->set_pre_allocated_property_fields(1); | 
| +  int n_properties = my_map->InitialPropertiesLength(); | 
| +  CHECK_GE(n_properties, 0); | 
| + | 
| +  int object_size = my_map->instance_size(); | 
| + | 
| +  // Step 2: allocate a lot of objects so to almost fill new space: we need | 
| +  // just enough room to allocate JSObject and thus fill the newspace. | 
| + | 
| +  int allocation_amount = | 
| +      Min(FixedArray::kMaxSize, Page::kMaxRegularHeapObjectSize + kPointerSize); | 
| +  int allocation_len = LenFromSize(allocation_amount); | 
| +  NewSpace* new_space = heap->new_space(); | 
| +  Address* top_addr = new_space->allocation_top_address(); | 
| +  Address* limit_addr = new_space->allocation_limit_address(); | 
| +  while ((*limit_addr - *top_addr) > allocation_amount) { | 
| +    CHECK(!heap->always_allocate()); | 
| +    Object* array = heap->AllocateFixedArray(allocation_len).ToObjectChecked(); | 
| +    CHECK(new_space->Contains(array)); | 
| +  } | 
| + | 
| +  // Step 3: now allocate fixed array and JSObject to fill the whole new space. | 
| +  int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size); | 
| +  int fixed_array_len = LenFromSize(to_fill); | 
| +  CHECK(fixed_array_len < FixedArray::kMaxLength); | 
| + | 
| +  CHECK(!heap->always_allocate()); | 
| +  Object* array = heap->AllocateFixedArray(fixed_array_len).ToObjectChecked(); | 
| +  CHECK(new_space->Contains(array)); | 
| + | 
| +  Object* object = heap->AllocateJSObjectFromMap(*my_map).ToObjectChecked(); | 
| +  CHECK(new_space->Contains(object)); | 
| +  JSObject* jsobject = JSObject::cast(object); | 
| +  CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length()); | 
| +  CHECK_EQ(0, jsobject->properties()->length()); | 
| + | 
| +  // 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>(array) + kPointerSize; | 
| +  double boom_value = bit_cast<double>(fake_object); | 
| +  FieldIndex index = FieldIndex::ForDescriptor(*my_map, 0); | 
| +  jsobject->RawFastDoublePropertyAtPut(index, boom_value); | 
| + | 
| +  CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr)); | 
| + | 
| +  // Step 4: clone jsobject, but force always allocate first to create a clone | 
| +  // in old pointer space. | 
| +  AlwaysAllocateScope aa_scope(isolate); | 
| +  Object* clone_obj = heap->CopyJSObject(jsobject).ToObjectChecked(); | 
| +  Handle<JSObject> clone(JSObject::cast(clone_obj)); | 
| +  CHECK(heap->old_pointer_space()->Contains(clone->address())); | 
| + | 
| +  CcTest::heap()->CollectGarbage(NEW_SPACE, "boom"); | 
| + | 
| +  // The value in cloned object should not be corrupted by GC. | 
| +  CHECK_EQ(boom_value, clone->RawFastDoublePropertyAt(index)); | 
| +} | 
| + | 
| #endif | 
|  |