| Index: test/cctest/test-unboxed-doubles.cc
 | 
| diff --git a/test/cctest/test-unboxed-doubles.cc b/test/cctest/test-unboxed-doubles.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..2abf3c2926c434a5ff9c2a41ebc55c9dd026bf37
 | 
| --- /dev/null
 | 
| +++ b/test/cctest/test-unboxed-doubles.cc
 | 
| @@ -0,0 +1,668 @@
 | 
| +// Copyright 2014 the V8 project authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +#include <stdlib.h>
 | 
| +#include <utility>
 | 
| +
 | 
| +#include "src/v8.h"
 | 
| +
 | 
| +#include "src/compilation-cache.h"
 | 
| +#include "src/execution.h"
 | 
| +#include "src/factory.h"
 | 
| +#include "src/global-handles.h"
 | 
| +#include "src/ic/ic.h"
 | 
| +#include "src/macro-assembler.h"
 | 
| +#include "test/cctest/cctest.h"
 | 
| +
 | 
| +using namespace v8::base;
 | 
| +using namespace v8::internal;
 | 
| +
 | 
| +#if (V8_DOUBLE_FIELDS_UNBOXING)
 | 
| +
 | 
| +
 | 
| +static double GetDoubleFieldValue(JSObject* obj, FieldIndex field_index) {
 | 
| +  if (obj->IsUnboxedDoubleField(field_index)) {
 | 
| +    return obj->RawFastDoublePropertyAt(field_index);
 | 
| +  } else {
 | 
| +    Object* value = obj->RawFastPropertyAt(field_index);
 | 
| +    DCHECK(value->IsMutableHeapNumber());
 | 
| +    return HeapNumber::cast(value)->value();
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +enum PropertyKind {
 | 
| +  PROP_CONSTANT,
 | 
| +  PROP_SMI,
 | 
| +  PROP_DOUBLE,
 | 
| +  PROP_TAGGED,
 | 
| +  PROP_KIND_NUMBER,
 | 
| +};
 | 
| +
 | 
| +static Representation representations[PROP_KIND_NUMBER] = {
 | 
| +    Representation::None(), Representation::Smi(), Representation::Double(),
 | 
| +    Representation::Tagged()};
 | 
| +
 | 
| +
 | 
| +static Handle<DescriptorArray> CreateDescriptorArray(Isolate* isolate,
 | 
| +                                                     PropertyKind* props,
 | 
| +                                                     int kPropsCount) {
 | 
| +  Factory* factory = isolate->factory();
 | 
| +
 | 
| +  Handle<String> func_name = factory->InternalizeUtf8String("func");
 | 
| +  Handle<JSFunction> func = factory->NewFunction(func_name);
 | 
| +
 | 
| +  Handle<DescriptorArray> descriptors =
 | 
| +      DescriptorArray::Allocate(isolate, 0, kPropsCount);
 | 
| +
 | 
| +  int next_field_offset = 0;
 | 
| +  for (int i = 0; i < kPropsCount; i++) {
 | 
| +    EmbeddedVector<char, 64> buffer;
 | 
| +    SNPrintF(buffer, "prop%d", i);
 | 
| +    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
 | 
| +
 | 
| +    PropertyKind kind = props[i];
 | 
| +
 | 
| +    if (kind == PROP_CONSTANT) {
 | 
| +      ConstantDescriptor d(name, func, NONE);
 | 
| +      descriptors->Append(&d);
 | 
| +
 | 
| +    } else {
 | 
| +      FieldDescriptor f(name, next_field_offset, NONE, representations[kind]);
 | 
| +      next_field_offset += f.GetDetails().field_width_in_words();
 | 
| +      descriptors->Append(&f);
 | 
| +    }
 | 
| +  }
 | 
| +  return descriptors;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +TEST(LayoutDescriptorBasicFast) {
 | 
| +  CcTest::InitializeVM();
 | 
| +  v8::HandleScope scope(CcTest::isolate());
 | 
| +
 | 
| +  LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout();
 | 
| +
 | 
| +  CHECK(!layout_desc->IsSlowLayout());
 | 
| +  CHECK(layout_desc->IsFastPointerLayout());
 | 
| +  CHECK_EQ(kSmiValueSize, layout_desc->capacity());
 | 
| +
 | 
| +  for (int i = 0; i < kSmiValueSize + 13; i++) {
 | 
| +    CHECK_EQ(true, layout_desc->IsTagged(i));
 | 
| +  }
 | 
| +  CHECK_EQ(true, layout_desc->IsTagged(-1));
 | 
| +  CHECK_EQ(true, layout_desc->IsTagged(-12347));
 | 
| +  CHECK_EQ(true, layout_desc->IsTagged(15635));
 | 
| +  CHECK(layout_desc->IsFastPointerLayout());
 | 
| +
 | 
| +  for (int i = 0; i < kSmiValueSize; i++) {
 | 
| +    layout_desc = layout_desc->SetTaggedForTesting(i, false);
 | 
| +    CHECK_EQ(false, layout_desc->IsTagged(i));
 | 
| +    layout_desc = layout_desc->SetTaggedForTesting(i, true);
 | 
| +    CHECK_EQ(true, layout_desc->IsTagged(i));
 | 
| +  }
 | 
| +  CHECK(layout_desc->IsFastPointerLayout());
 | 
| +}
 | 
| +
 | 
| +
 | 
| +TEST(LayoutDescriptorBasicSlow) {
 | 
| +  CcTest::InitializeVM();
 | 
| +  Isolate* isolate = CcTest::i_isolate();
 | 
| +  v8::HandleScope scope(CcTest::isolate());
 | 
| +
 | 
| +  Handle<LayoutDescriptor> layout_descriptor;
 | 
| +  const int kPropsCount = kSmiValueSize * 3;
 | 
| +  PropertyKind props[kPropsCount];
 | 
| +  for (int i = 0; i < kPropsCount; i++) {
 | 
| +    // All properties tagged.
 | 
| +    props[i] = PROP_TAGGED;
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    Handle<DescriptorArray> descriptors =
 | 
| +        CreateDescriptorArray(isolate, props, kPropsCount);
 | 
| +
 | 
| +    Handle<Map> map = Map::Create(isolate, kPropsCount);
 | 
| +
 | 
| +    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
 | 
| +    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
 | 
| +    CHECK_EQ(kSmiValueSize, layout_descriptor->capacity());
 | 
| +    map->InitializeDescriptors(*descriptors, *layout_descriptor);
 | 
| +    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
 | 
| +  }
 | 
| +
 | 
| +  props[0] = PROP_DOUBLE;
 | 
| +  props[kPropsCount - 1] = PROP_DOUBLE;
 | 
| +
 | 
| +  Handle<DescriptorArray> descriptors =
 | 
| +      CreateDescriptorArray(isolate, props, kPropsCount);
 | 
| +
 | 
| +  {
 | 
| +    int inobject_properties = kPropsCount - 1;
 | 
| +    Handle<Map> map = Map::Create(isolate, inobject_properties);
 | 
| +
 | 
| +    // Should be fast as the only double property is the first one.
 | 
| +    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
 | 
| +    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
 | 
| +    CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +    CHECK(!layout_descriptor->IsFastPointerLayout());
 | 
| +
 | 
| +    CHECK_EQ(false, layout_descriptor->IsTagged(0));
 | 
| +    for (int i = 1; i < kPropsCount; i++) {
 | 
| +      CHECK_EQ(true, layout_descriptor->IsTagged(i));
 | 
| +    }
 | 
| +    map->InitializeDescriptors(*descriptors, *layout_descriptor);
 | 
| +    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    int inobject_properties = kPropsCount;
 | 
| +    Handle<Map> map = Map::Create(isolate, inobject_properties);
 | 
| +
 | 
| +    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
 | 
| +    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
 | 
| +    CHECK(layout_descriptor->IsSlowLayout());
 | 
| +    CHECK(!layout_descriptor->IsFastPointerLayout());
 | 
| +    CHECK(layout_descriptor->capacity() > kSmiValueSize);
 | 
| +
 | 
| +    CHECK_EQ(false, layout_descriptor->IsTagged(0));
 | 
| +    CHECK_EQ(false, layout_descriptor->IsTagged(kPropsCount - 1));
 | 
| +    for (int i = 1; i < kPropsCount - 1; i++) {
 | 
| +      CHECK_EQ(true, layout_descriptor->IsTagged(i));
 | 
| +    }
 | 
| +
 | 
| +    map->InitializeDescriptors(*descriptors, *layout_descriptor);
 | 
| +    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
 | 
| +
 | 
| +    // Here we have truly slow layout descriptor, so play with the bits.
 | 
| +    CHECK_EQ(true, layout_descriptor->IsTagged(-1));
 | 
| +    CHECK_EQ(true, layout_descriptor->IsTagged(-12347));
 | 
| +    CHECK_EQ(true, layout_descriptor->IsTagged(15635));
 | 
| +
 | 
| +    LayoutDescriptor* layout_desc = *layout_descriptor;
 | 
| +    // Play with the bits but leave it in consistent state with map at the end.
 | 
| +    for (int i = 1; i < kPropsCount - 1; i++) {
 | 
| +      layout_desc = layout_desc->SetTaggedForTesting(i, false);
 | 
| +      CHECK_EQ(false, layout_desc->IsTagged(i));
 | 
| +      layout_desc = layout_desc->SetTaggedForTesting(i, true);
 | 
| +      CHECK_EQ(true, layout_desc->IsTagged(i));
 | 
| +    }
 | 
| +    CHECK(layout_desc->IsSlowLayout());
 | 
| +    CHECK(!layout_desc->IsFastPointerLayout());
 | 
| +
 | 
| +    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +TEST(LayoutDescriptorCreateNewFast) {
 | 
| +  CcTest::InitializeVM();
 | 
| +  Isolate* isolate = CcTest::i_isolate();
 | 
| +  v8::HandleScope scope(CcTest::isolate());
 | 
| +
 | 
| +  Handle<LayoutDescriptor> layout_descriptor;
 | 
| +  PropertyKind props[] = {
 | 
| +      PROP_CONSTANT,
 | 
| +      PROP_TAGGED,  // field #0
 | 
| +      PROP_CONSTANT,
 | 
| +      PROP_DOUBLE,  // field #1
 | 
| +      PROP_CONSTANT,
 | 
| +      PROP_TAGGED,  // field #2
 | 
| +      PROP_CONSTANT,
 | 
| +  };
 | 
| +  const int kPropsCount = arraysize(props);
 | 
| +
 | 
| +  Handle<DescriptorArray> descriptors =
 | 
| +      CreateDescriptorArray(isolate, props, kPropsCount);
 | 
| +
 | 
| +  {
 | 
| +    Handle<Map> map = Map::Create(isolate, 0);
 | 
| +    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
 | 
| +    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
 | 
| +    map->InitializeDescriptors(*descriptors, *layout_descriptor);
 | 
| +    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    Handle<Map> map = Map::Create(isolate, 1);
 | 
| +    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
 | 
| +    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
 | 
| +    map->InitializeDescriptors(*descriptors, *layout_descriptor);
 | 
| +    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    Handle<Map> map = Map::Create(isolate, 2);
 | 
| +    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
 | 
| +    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
 | 
| +    CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +    CHECK_EQ(true, layout_descriptor->IsTagged(0));
 | 
| +    CHECK_EQ(false, layout_descriptor->IsTagged(1));
 | 
| +    CHECK_EQ(true, layout_descriptor->IsTagged(2));
 | 
| +    CHECK_EQ(true, layout_descriptor->IsTagged(125));
 | 
| +    map->InitializeDescriptors(*descriptors, *layout_descriptor);
 | 
| +    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +TEST(LayoutDescriptorCreateNewSlow) {
 | 
| +  CcTest::InitializeVM();
 | 
| +  Isolate* isolate = CcTest::i_isolate();
 | 
| +  v8::HandleScope scope(CcTest::isolate());
 | 
| +
 | 
| +  Handle<LayoutDescriptor> layout_descriptor;
 | 
| +  const int kPropsCount = kSmiValueSize * 3;
 | 
| +  PropertyKind props[kPropsCount];
 | 
| +  for (int i = 0; i < kPropsCount; i++) {
 | 
| +    props[i] = static_cast<PropertyKind>(i % PROP_KIND_NUMBER);
 | 
| +  }
 | 
| +
 | 
| +  Handle<DescriptorArray> descriptors =
 | 
| +      CreateDescriptorArray(isolate, props, kPropsCount);
 | 
| +
 | 
| +  {
 | 
| +    Handle<Map> map = Map::Create(isolate, 0);
 | 
| +    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
 | 
| +    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
 | 
| +    map->InitializeDescriptors(*descriptors, *layout_descriptor);
 | 
| +    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    Handle<Map> map = Map::Create(isolate, 1);
 | 
| +    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
 | 
| +    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
 | 
| +    map->InitializeDescriptors(*descriptors, *layout_descriptor);
 | 
| +    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    Handle<Map> map = Map::Create(isolate, 2);
 | 
| +    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
 | 
| +    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
 | 
| +    CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +    CHECK_EQ(true, layout_descriptor->IsTagged(0));
 | 
| +    CHECK_EQ(false, layout_descriptor->IsTagged(1));
 | 
| +    CHECK_EQ(true, layout_descriptor->IsTagged(2));
 | 
| +    CHECK_EQ(true, layout_descriptor->IsTagged(125));
 | 
| +    map->InitializeDescriptors(*descriptors, *layout_descriptor);
 | 
| +    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    int inobject_properties = kPropsCount / 2;
 | 
| +    Handle<Map> map = Map::Create(isolate, inobject_properties);
 | 
| +    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
 | 
| +    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
 | 
| +    CHECK(layout_descriptor->IsSlowLayout());
 | 
| +    for (int i = 0; i < inobject_properties; i++) {
 | 
| +      // PROP_DOUBLE has index 1 among FIELD properties.
 | 
| +      const bool tagged = (i % (PROP_KIND_NUMBER - 1)) != 1;
 | 
| +      CHECK_EQ(tagged, layout_descriptor->IsTagged(i));
 | 
| +    }
 | 
| +    // Every property after inobject_properties must be tagged.
 | 
| +    for (int i = inobject_properties; i < kPropsCount; i++) {
 | 
| +      CHECK_EQ(true, layout_descriptor->IsTagged(i));
 | 
| +    }
 | 
| +    map->InitializeDescriptors(*descriptors, *layout_descriptor);
 | 
| +    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
 | 
| +
 | 
| +    // Now test LayoutDescriptor::cast_gc_safe().
 | 
| +    Handle<LayoutDescriptor> layout_descriptor_copy =
 | 
| +        LayoutDescriptor::New(map, descriptors, kPropsCount);
 | 
| +
 | 
| +    LayoutDescriptor* layout_desc = *layout_descriptor;
 | 
| +    CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
 | 
| +    CHECK_EQ(layout_desc, LayoutDescriptor::cast_gc_safe(layout_desc));
 | 
| +    CHECK(layout_descriptor->IsFixedTypedArrayBase());
 | 
| +    // Now make it look like a forwarding pointer to layout_descriptor_copy.
 | 
| +    MapWord map_word = layout_desc->map_word();
 | 
| +    CHECK(!map_word.IsForwardingAddress());
 | 
| +    layout_desc->set_map_word(
 | 
| +        MapWord::FromForwardingAddress(*layout_descriptor_copy));
 | 
| +    CHECK(layout_desc->map_word().IsForwardingAddress());
 | 
| +    CHECK_EQ(*layout_descriptor_copy,
 | 
| +             LayoutDescriptor::cast_gc_safe(layout_desc));
 | 
| +
 | 
| +    // Restore it back.
 | 
| +    layout_desc->set_map_word(map_word);
 | 
| +    CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +static Handle<LayoutDescriptor> TestLayoutDescriptorAppend(
 | 
| +    Isolate* isolate, int inobject_properties, PropertyKind* props,
 | 
| +    int kPropsCount) {
 | 
| +  Factory* factory = isolate->factory();
 | 
| +
 | 
| +  Handle<String> func_name = factory->InternalizeUtf8String("func");
 | 
| +  Handle<JSFunction> func = factory->NewFunction(func_name);
 | 
| +
 | 
| +  Handle<DescriptorArray> descriptors =
 | 
| +      DescriptorArray::Allocate(isolate, 0, kPropsCount);
 | 
| +
 | 
| +  Handle<Map> map = Map::Create(isolate, inobject_properties);
 | 
| +  map->InitializeDescriptors(*descriptors,
 | 
| +                             LayoutDescriptor::FastPointerLayout());
 | 
| +
 | 
| +  int next_field_offset = 0;
 | 
| +  for (int i = 0; i < kPropsCount; i++) {
 | 
| +    EmbeddedVector<char, 64> buffer;
 | 
| +    SNPrintF(buffer, "prop%d", i);
 | 
| +    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
 | 
| +
 | 
| +    Handle<LayoutDescriptor> layout_descriptor;
 | 
| +    PropertyKind kind = props[i];
 | 
| +    if (kind == PROP_CONSTANT) {
 | 
| +      ConstantDescriptor d(name, func, NONE);
 | 
| +      layout_descriptor = LayoutDescriptor::Append(map, d.GetDetails());
 | 
| +      descriptors->Append(&d);
 | 
| +
 | 
| +    } else {
 | 
| +      FieldDescriptor f(name, next_field_offset, NONE, representations[kind]);
 | 
| +      int field_width_in_words = f.GetDetails().field_width_in_words();
 | 
| +      next_field_offset += field_width_in_words;
 | 
| +      layout_descriptor = LayoutDescriptor::Append(map, f.GetDetails());
 | 
| +      descriptors->Append(&f);
 | 
| +
 | 
| +      int field_index = f.GetDetails().field_index();
 | 
| +      bool is_inobject = field_index < map->inobject_properties();
 | 
| +      for (int bit = 0; bit < field_width_in_words; bit++) {
 | 
| +        CHECK_EQ(is_inobject && (kind == PROP_DOUBLE),
 | 
| +                 !layout_descriptor->IsTagged(field_index + bit));
 | 
| +      }
 | 
| +      CHECK(layout_descriptor->IsTagged(next_field_offset));
 | 
| +    }
 | 
| +    map->InitializeDescriptors(*descriptors, *layout_descriptor);
 | 
| +  }
 | 
| +  Handle<LayoutDescriptor> layout_descriptor(map->layout_descriptor(), isolate);
 | 
| +  DCHECK(layout_descriptor->IsConsistentWithMap(*map));
 | 
| +  return layout_descriptor;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +TEST(LayoutDescriptorAppend) {
 | 
| +  CcTest::InitializeVM();
 | 
| +  Isolate* isolate = CcTest::i_isolate();
 | 
| +  v8::HandleScope scope(CcTest::isolate());
 | 
| +
 | 
| +  Handle<LayoutDescriptor> layout_descriptor;
 | 
| +  const int kPropsCount = kSmiValueSize * 3;
 | 
| +  PropertyKind props[kPropsCount];
 | 
| +  for (int i = 0; i < kPropsCount; i++) {
 | 
| +    props[i] = static_cast<PropertyKind>(i % PROP_KIND_NUMBER);
 | 
| +  }
 | 
| +
 | 
| +  layout_descriptor =
 | 
| +      TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
 | 
| +  CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor =
 | 
| +      TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
 | 
| +  CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor =
 | 
| +      TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
 | 
| +  CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
 | 
| +                                                 props, kPropsCount);
 | 
| +  CHECK(layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor =
 | 
| +      TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
 | 
| +  CHECK(layout_descriptor->IsSlowLayout());
 | 
| +}
 | 
| +
 | 
| +
 | 
| +TEST(LayoutDescriptorAppendAllDoubles) {
 | 
| +  CcTest::InitializeVM();
 | 
| +  Isolate* isolate = CcTest::i_isolate();
 | 
| +  v8::HandleScope scope(CcTest::isolate());
 | 
| +
 | 
| +  Handle<LayoutDescriptor> layout_descriptor;
 | 
| +  const int kPropsCount = kSmiValueSize * 3;
 | 
| +  PropertyKind props[kPropsCount];
 | 
| +  for (int i = 0; i < kPropsCount; i++) {
 | 
| +    props[i] = PROP_DOUBLE;
 | 
| +  }
 | 
| +
 | 
| +  layout_descriptor =
 | 
| +      TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
 | 
| +  CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor =
 | 
| +      TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
 | 
| +  CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor =
 | 
| +      TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
 | 
| +  CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize + 1,
 | 
| +                                                 props, kPropsCount);
 | 
| +  CHECK(layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
 | 
| +                                                 props, kPropsCount);
 | 
| +  CHECK(layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor =
 | 
| +      TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
 | 
| +  CHECK(layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  {
 | 
| +    // Ensure layout descriptor switches into slow mode at the right moment.
 | 
| +    layout_descriptor =
 | 
| +        TestLayoutDescriptorAppend(isolate, kPropsCount, props, kSmiValueSize);
 | 
| +    CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +    layout_descriptor = TestLayoutDescriptorAppend(isolate, kPropsCount, props,
 | 
| +                                                   kSmiValueSize + 1);
 | 
| +    CHECK(layout_descriptor->IsSlowLayout());
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +static Handle<LayoutDescriptor> TestLayoutDescriptorAppendIfFastOrUseFull(
 | 
| +    Isolate* isolate, int inobject_properties,
 | 
| +    Handle<DescriptorArray> descriptors, int number_of_descriptors) {
 | 
| +  Handle<Map> map = Map::Create(isolate, inobject_properties);
 | 
| +
 | 
| +  Handle<LayoutDescriptor> full_layout_descriptor = LayoutDescriptor::New(
 | 
| +      map, descriptors, descriptors->number_of_descriptors());
 | 
| +
 | 
| +  int nof = 0;
 | 
| +  bool switched_to_slow_mode = false;
 | 
| +
 | 
| +  for (int i = 0; i < number_of_descriptors; i++) {
 | 
| +    PropertyDetails details = descriptors->GetDetails(i);
 | 
| +
 | 
| +    // This method calls LayoutDescriptor::AppendIfFastOrUseFull() internally
 | 
| +    // and does all the required map-descriptors related book keeping.
 | 
| +    map = Map::CopyInstallDescriptorsForTesting(map, i, descriptors,
 | 
| +                                                full_layout_descriptor);
 | 
| +
 | 
| +    LayoutDescriptor* layout_desc = map->layout_descriptor();
 | 
| +
 | 
| +    if (layout_desc->IsSlowLayout()) {
 | 
| +      switched_to_slow_mode = true;
 | 
| +      CHECK_EQ(*full_layout_descriptor, layout_desc);
 | 
| +    } else {
 | 
| +      CHECK(!switched_to_slow_mode);
 | 
| +      if (details.type() == FIELD) {
 | 
| +        nof++;
 | 
| +        int field_index = details.field_index();
 | 
| +        int field_width_in_words = details.field_width_in_words();
 | 
| +
 | 
| +        bool is_inobject = field_index < map->inobject_properties();
 | 
| +        for (int bit = 0; bit < field_width_in_words; bit++) {
 | 
| +          CHECK_EQ(is_inobject && details.representation().IsDouble(),
 | 
| +                   !layout_desc->IsTagged(field_index + bit));
 | 
| +        }
 | 
| +        CHECK(layout_desc->IsTagged(field_index + field_width_in_words));
 | 
| +      }
 | 
| +    }
 | 
| +    DCHECK(map->layout_descriptor()->IsConsistentWithMap(*map));
 | 
| +  }
 | 
| +
 | 
| +  Handle<LayoutDescriptor> layout_descriptor = map->GetLayoutDescriptor();
 | 
| +  DCHECK(layout_descriptor->IsConsistentWithMap(*map));
 | 
| +  return layout_descriptor;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +TEST(LayoutDescriptorAppendIfFastOrUseFull) {
 | 
| +  CcTest::InitializeVM();
 | 
| +  Isolate* isolate = CcTest::i_isolate();
 | 
| +  v8::HandleScope scope(CcTest::isolate());
 | 
| +
 | 
| +  Handle<LayoutDescriptor> layout_descriptor;
 | 
| +  const int kPropsCount = kSmiValueSize * 3;
 | 
| +  PropertyKind props[kPropsCount];
 | 
| +  for (int i = 0; i < kPropsCount; i++) {
 | 
| +    props[i] = static_cast<PropertyKind>(i % PROP_KIND_NUMBER);
 | 
| +  }
 | 
| +  Handle<DescriptorArray> descriptors =
 | 
| +      CreateDescriptorArray(isolate, props, kPropsCount);
 | 
| +
 | 
| +  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
 | 
| +      isolate, 0, descriptors, kPropsCount);
 | 
| +  CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
 | 
| +      isolate, 13, descriptors, kPropsCount);
 | 
| +  CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
 | 
| +      isolate, kSmiValueSize, descriptors, kPropsCount);
 | 
| +  CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
 | 
| +      isolate, kSmiValueSize * 2, descriptors, kPropsCount);
 | 
| +  CHECK(layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
 | 
| +      isolate, kPropsCount, descriptors, kPropsCount);
 | 
| +  CHECK(layout_descriptor->IsSlowLayout());
 | 
| +}
 | 
| +
 | 
| +
 | 
| +TEST(LayoutDescriptorAppendIfFastOrUseFullAllDoubles) {
 | 
| +  CcTest::InitializeVM();
 | 
| +  Isolate* isolate = CcTest::i_isolate();
 | 
| +  v8::HandleScope scope(CcTest::isolate());
 | 
| +
 | 
| +  Handle<LayoutDescriptor> layout_descriptor;
 | 
| +  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);
 | 
| +
 | 
| +  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
 | 
| +      isolate, 0, descriptors, kPropsCount);
 | 
| +  CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
 | 
| +      isolate, 13, descriptors, kPropsCount);
 | 
| +  CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
 | 
| +      isolate, kSmiValueSize, descriptors, kPropsCount);
 | 
| +  CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
 | 
| +      isolate, kSmiValueSize + 1, descriptors, kPropsCount);
 | 
| +  CHECK(layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
 | 
| +      isolate, kSmiValueSize * 2, descriptors, kPropsCount);
 | 
| +  CHECK(layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
 | 
| +      isolate, kPropsCount, descriptors, kPropsCount);
 | 
| +  CHECK(layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +  {
 | 
| +    // Ensure layout descriptor switches into slow mode at the right moment.
 | 
| +    layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
 | 
| +        isolate, kPropsCount, descriptors, kSmiValueSize);
 | 
| +    CHECK(!layout_descriptor->IsSlowLayout());
 | 
| +
 | 
| +    layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
 | 
| +        isolate, kPropsCount, descriptors, kSmiValueSize + 1);
 | 
| +    CHECK(layout_descriptor->IsSlowLayout());
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +TEST(StoreBufferScanOnScavenge) {
 | 
| +  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
 | 
| +  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
 | 
| +
 | 
| +  CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
 | 
| +
 | 
| +  // 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);
 | 
| +  obj->FastPropertyAtPut(field_index,
 | 
| +                         *factory->NewHeapNumber(boom_value, MUTABLE));
 | 
| +
 | 
| +  // Enforce scan on scavenge for the obj's page.
 | 
| +  MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
 | 
| +  chunk->set_scan_on_scavenge(true);
 | 
| +
 | 
| +  // Trigger GCs and force evacuation. Should not crash there.
 | 
| +  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
 | 
| +
 | 
| +  CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
 | 
| +}
 | 
| +
 | 
| +#endif
 | 
| 
 |