 Chromium Code Reviews
 Chromium Code Reviews Issue 888623002:
  Property reconfiguring implemented. Tests added.  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master
    
  
    Issue 888623002:
  Property reconfiguring implemented. Tests added.  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master| Index: test/cctest/test-migrations.cc | 
| diff --git a/test/cctest/test-migrations.cc b/test/cctest/test-migrations.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..b526d85b3723c8adcb100e07116bac3215c2efa2 | 
| --- /dev/null | 
| +++ b/test/cctest/test-migrations.cc | 
| @@ -0,0 +1,2262 @@ | 
| +// Copyright 2015 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/stub-cache.h" | 
| +#include "src/macro-assembler.h" | 
| +#include "src/smart-pointers.h" | 
| +#include "test/cctest/cctest.h" | 
| + | 
| +using namespace v8::internal; | 
| + | 
| + | 
| +// TODO(ishell): fix this once ReconfigureProperty supports | 
| +// "non equivalent" transitions. | 
| +const bool IS_NON_EQUIVALENT_TRANSITION_SUPPORTED = false; | 
| + | 
| + | 
| +// TODO(ishell): fix this once TransitionToPrototype stops generalizing | 
| +// all field representations (crbug/448711). | 
| +const bool IS_CRBUG_448711_FIXED = false; | 
| + | 
| + | 
| +// TODO(ishell): fix this once TransitionToAccessorProperty is able to always | 
| +// keep map in fast mode. | 
| +const bool IS_ACCESSOR_FIELD_SUPPORTED = false; | 
| + | 
| + | 
| +// | 
| +// Helper functions. | 
| +// | 
| + | 
| +static Handle<String> MakeString(const char* str) { | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Factory* factory = isolate->factory(); | 
| + return factory->InternalizeUtf8String(str); | 
| +} | 
| + | 
| + | 
| +static Handle<String> MakeName(const char* str, int suffix) { | 
| + EmbeddedVector<char, 128> buffer; | 
| + SNPrintF(buffer, "%s%d", str, suffix); | 
| + return MakeString(buffer.start()); | 
| +} | 
| + | 
| + | 
| +static Handle<AccessorPair> CreateAccessorPair(bool with_getter, | 
| + bool with_setter) { | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Factory* factory = isolate->factory(); | 
| + Handle<AccessorPair> pair = factory->NewAccessorPair(); | 
| + if (with_getter) { | 
| + pair->set_getter(*factory->NewFunction(factory->empty_string())); | 
| + } | 
| + if (with_setter) { | 
| + pair->set_setter(*factory->NewFunction(factory->empty_string())); | 
| + } | 
| + return pair; | 
| +} | 
| + | 
| + | 
| +static bool EqualDetails(DescriptorArray* descriptors, int descriptor, | 
| + PropertyType type, PropertyAttributes attributes, | 
| + Representation representation, int field_index = -1) { | 
| + PropertyDetails details = descriptors->GetDetails(descriptor); | 
| + if (details.type() != type) return false; | 
| + if (details.attributes() != attributes) return false; | 
| + if (!details.representation().Equals(representation)) return false; | 
| + if (field_index >= 0 && details.field_index() != field_index) return false; | 
| + return true; | 
| +} | 
| + | 
| + | 
| +class Expectations { | 
| + static const int MAX_PROPERTIES = 64; | 
| + Isolate* isolate_; | 
| + PropertyType types_[MAX_PROPERTIES]; | 
| + PropertyAttributes attributes_[MAX_PROPERTIES]; | 
| + Representation representations_[MAX_PROPERTIES]; | 
| + // HeapType for kField, value for DATA_CONSTANT and getter for | 
| + // ACCESSOR_CONSTANT. | 
| + Handle<Object> values_[MAX_PROPERTIES]; | 
| + // Setter for ACCESSOR_CONSTANT. | 
| + Handle<Object> setter_values_[MAX_PROPERTIES]; | 
| + int number_of_properties_; | 
| + | 
| + public: | 
| + explicit Expectations(Isolate* isolate) | 
| + : isolate_(isolate), number_of_properties_(0) {} | 
| + | 
| + void Init(int index, PropertyType type, PropertyAttributes attributes, | 
| + Representation representation, Handle<Object> value) { | 
| + DCHECK(index < MAX_PROPERTIES); | 
| + types_[index] = type; | 
| + attributes_[index] = attributes; | 
| + representations_[index] = representation; | 
| + values_[index] = value; | 
| + } | 
| + | 
| + Handle<HeapType> GetFieldType(int index) { | 
| + CHECK(index < MAX_PROPERTIES); | 
| + CHECK(types_[index] == DATA || types_[index] == ACCESSOR); | 
| + return Handle<HeapType>::cast(values_[index]); | 
| + } | 
| + | 
| + void SetDataField(int index, PropertyAttributes attrs, | 
| + Representation representation, Handle<HeapType> value) { | 
| + Init(index, DATA, attrs, representation, value); | 
| + } | 
| + | 
| + void SetDataField(int index, Representation representation, | 
| + Handle<HeapType> value) { | 
| + SetDataField(index, attributes_[index], representation, value); | 
| + } | 
| + | 
| + void SetAccessorField(int index, PropertyAttributes attrs) { | 
| + Init(index, ACCESSOR, attrs, Representation::Tagged(), | 
| + HeapType::Any(isolate_)); | 
| + } | 
| + | 
| + void SetAccessorField(int index) { | 
| + SetAccessorField(index, attributes_[index]); | 
| + } | 
| + | 
| + void SetDataConstant(int index, PropertyAttributes attrs, | 
| + Handle<JSFunction> value) { | 
| + Init(index, DATA_CONSTANT, attrs, Representation::HeapObject(), value); | 
| + } | 
| + | 
| + void SetDataConstant(int index, Handle<JSFunction> value) { | 
| + SetDataConstant(index, attributes_[index], value); | 
| + } | 
| + | 
| + void SetAccessorConstant(int index, PropertyAttributes attrs, | 
| + Handle<Object> getter, Handle<Object> setter) { | 
| + Init(index, ACCESSOR_CONSTANT, attrs, Representation::Tagged(), getter); | 
| + setter_values_[index] = setter; | 
| + } | 
| + | 
| + void SetAccessorConstantComponent(int index, PropertyAttributes attrs, | 
| + AccessorComponent component, | 
| + Handle<Object> accessor) { | 
| + CHECK_EQ(ACCESSOR_CONSTANT, types_[index]); | 
| + CHECK(index < number_of_properties_); | 
| + if (component == ACCESSOR_GETTER) { | 
| + values_[index] = accessor; | 
| + } else { | 
| + setter_values_[index] = accessor; | 
| + } | 
| + } | 
| + | 
| + void SetAccessorConstant(int index, PropertyAttributes attrs, | 
| + Handle<AccessorPair> pair) { | 
| + Handle<Object> getter = handle(pair->getter(), isolate_); | 
| + Handle<Object> setter = handle(pair->setter(), isolate_); | 
| + SetAccessorConstant(index, attrs, getter, setter); | 
| + } | 
| + | 
| + void SetAccessorConstant(int index, Handle<Object> getter, | 
| + Handle<Object> setter) { | 
| + SetAccessorConstant(index, attributes_[index], getter, setter); | 
| + } | 
| + | 
| + void SetAccessorConstant(int index, Handle<AccessorPair> pair) { | 
| + Handle<Object> getter = handle(pair->getter(), isolate_); | 
| + Handle<Object> setter = handle(pair->setter(), isolate_); | 
| + SetAccessorConstant(index, getter, setter); | 
| + } | 
| + | 
| + void GeneralizeRepresentation(int index) { | 
| + CHECK(index < number_of_properties_); | 
| + representations_[index] = Representation::Tagged(); | 
| + if (types_[index] == DATA || types_[index] == ACCESSOR) { | 
| + values_[index] = HeapType::Any(isolate_); | 
| + } | 
| + } | 
| + | 
| + | 
| + bool Check(DescriptorArray* descriptors, int descriptor) { | 
| + PropertyType type = types_[descriptor]; | 
| + if (!EqualDetails(descriptors, descriptor, type, attributes_[descriptor], | 
| + representations_[descriptor])) { | 
| + return false; | 
| + } | 
| + Object* expected_value = *values_[descriptor]; | 
| + Object* value = descriptors->GetValue(descriptor); | 
| + switch (type) { | 
| + case DATA: | 
| + case ACCESSOR: | 
| + return HeapType::cast(expected_value)->Equals(HeapType::cast(value)); | 
| + | 
| + case DATA_CONSTANT: | 
| + return value == expected_value; | 
| + | 
| + case ACCESSOR_CONSTANT: { | 
| + if (value == expected_value) return true; | 
| + if (!value->IsAccessorPair()) return false; | 
| + AccessorPair* pair = AccessorPair::cast(value); | 
| + return pair->Equals(expected_value, *setter_values_[descriptor]); | 
| + } | 
| + } | 
| + UNREACHABLE(); | 
| + return false; | 
| + } | 
| + | 
| + bool Check(Map* map, int expected_nof) { | 
| + CHECK(number_of_properties_ <= MAX_PROPERTIES); | 
| + CHECK_EQ(expected_nof, map->NumberOfOwnDescriptors()); | 
| + CHECK(!map->is_dictionary_map()); | 
| + | 
| + DescriptorArray* descriptors = map->instance_descriptors(); | 
| + CHECK(expected_nof <= number_of_properties_); | 
| + for (int i = 0; i < expected_nof; i++) { | 
| + if (!Check(descriptors, i)) { | 
| + Check(descriptors, i); | 
| + return false; | 
| + } | 
| + } | 
| + return true; | 
| + } | 
| + | 
| + bool Check(Map* map) { return Check(map, number_of_properties_); } | 
| + | 
| + | 
| + // | 
| + // Helper methods for initializing expectations and adding properties to | 
| + // given |map|. | 
| + // | 
| + | 
| + Handle<Map> AddDataField(Handle<Map> map, PropertyAttributes attributes, | 
| + Representation representation, | 
| + Handle<HeapType> heap_type) { | 
| + CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); | 
| + int property_index = number_of_properties_++; | 
| + SetDataField(property_index, attributes, representation, heap_type); | 
| + | 
| + Handle<String> name = MakeName("prop", property_index); | 
| + return Map::CopyWithField(map, name, heap_type, attributes, representation, | 
| + INSERT_TRANSITION).ToHandleChecked(); | 
| + } | 
| + | 
| + Handle<Map> AddDataConstant(Handle<Map> map, PropertyAttributes attributes, | 
| + Handle<JSFunction> value) { | 
| + CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); | 
| + int property_index = number_of_properties_++; | 
| + SetDataConstant(property_index, attributes, value); | 
| + | 
| + Handle<String> name = MakeName("prop", property_index); | 
| + return Map::CopyWithConstant(map, name, value, attributes, | 
| + INSERT_TRANSITION).ToHandleChecked(); | 
| + } | 
| + | 
| + Handle<Map> FollowDataTransition(Handle<Map> map, | 
| + PropertyAttributes attributes, | 
| + Representation representation, | 
| + Handle<HeapType> heap_type) { | 
| + CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); | 
| + int property_index = number_of_properties_++; | 
| + SetDataField(property_index, attributes, representation, heap_type); | 
| + | 
| + Handle<String> name = MakeName("prop", property_index); | 
| + int t = map->SearchTransition(kData, *name, attributes); | 
| + CHECK_NE(TransitionArray::kNotFound, t); | 
| + return handle(map->GetTransition(t)); | 
| + } | 
| + | 
| + Handle<Map> AddAccessorConstant(Handle<Map> map, | 
| + PropertyAttributes attributes, | 
| + Handle<AccessorPair> pair) { | 
| + CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); | 
| + int property_index = number_of_properties_++; | 
| + SetAccessorConstant(property_index, attributes, pair); | 
| + | 
| + Handle<String> name = MakeName("prop", property_index); | 
| + | 
| + AccessorConstantDescriptor new_desc(name, pair, attributes); | 
| + return Map::CopyInsertDescriptor(map, &new_desc, INSERT_TRANSITION); | 
| + } | 
| + | 
| + Handle<Map> AddAccessorConstant(Handle<Map> map, | 
| + PropertyAttributes attributes, | 
| + Handle<Object> getter, | 
| + Handle<Object> setter) { | 
| + CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); | 
| + int property_index = number_of_properties_++; | 
| + SetAccessorConstant(property_index, attributes, getter, setter); | 
| + | 
| + Handle<String> name = MakeName("prop", property_index); | 
| + | 
| + CHECK(!getter->IsNull() || !setter->IsNull()); | 
| + Factory* factory = isolate_->factory(); | 
| + | 
| + if (!getter->IsNull()) { | 
| + Handle<AccessorPair> pair = factory->NewAccessorPair(); | 
| + pair->SetComponents(*getter, *factory->null_value()); | 
| + AccessorConstantDescriptor new_desc(name, pair, attributes); | 
| + map = Map::CopyInsertDescriptor(map, &new_desc, INSERT_TRANSITION); | 
| + } | 
| + if (!setter->IsNull()) { | 
| + Handle<AccessorPair> pair = factory->NewAccessorPair(); | 
| + pair->SetComponents(*getter, *setter); | 
| + AccessorConstantDescriptor new_desc(name, pair, attributes); | 
| + map = Map::CopyInsertDescriptor(map, &new_desc, INSERT_TRANSITION); | 
| + } | 
| + return map; | 
| + } | 
| +}; | 
| + | 
| + | 
| +//////////////////////////////////////////////////////////////////////////////// | 
| +// A set of tests for basic transitioning mechanics. | 
| +// | 
| + | 
| +TEST(TransitionToDataFieldProperty) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Factory* factory = isolate->factory(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + | 
| + const int kPropCount = 50; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + Handle<Map> intermediate_maps[kPropCount]; | 
| + Representation representations[] = { | 
| + Representation::Smi(), Representation::Double(), | 
| + Representation::HeapObject(), Representation::Tagged()}; | 
| + // values[i] must fit into representations[i]. | 
| + Handle<Object> values[] = { | 
| + handle(Smi::FromInt(0), isolate), factory->NewHeapNumber(0), | 
| + factory->NewJSObjectFromMap(Map::Create(isolate, 0)), | 
| + factory->undefined_value()}; | 
| + const int kValuesCount = arraysize(values); | 
| + CHECK_EQ(kValuesCount, arraysize(representations)); | 
| + | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + PropertyAttributes attributes = static_cast<PropertyAttributes>(i % 8); | 
| + Representation r = representations[i % kValuesCount]; | 
| + CHECK(values[i % kValuesCount]->FitsRepresentation(r)); | 
| + | 
| + map = expectations.AddDataField(map, attributes, r, any_type); | 
| + intermediate_maps[i] = map; | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK(expectations.Check(*intermediate_maps[i], i + 1)); | 
| + } | 
| + | 
| + // Try to follow same transitions from the |initial_map|. | 
| + Handle<Map> map2 = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + PropertyAttributes attributes = static_cast<PropertyAttributes>(i % 8); | 
| + Handle<String> name = MakeName("prop", i); | 
| + map2 = Map::TransitionToDataProperty( | 
| + map2, name, values[i % kValuesCount], attributes, | 
| + Object::CERTAINLY_NOT_STORE_FROM_KEYED); | 
| + | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(!map2->is_dictionary_map()); | 
| + CHECK_EQ(*intermediate_maps[i], *map2); | 
| + CHECK(expectations.Check(*map2, i + 1)); | 
| + } | 
| +} | 
| + | 
| + | 
| +TEST(TransitionToDataConstantProperty) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Factory* factory = isolate->factory(); | 
| + | 
| + const int kPropCount = 50; | 
| + Expectations expectations(isolate); | 
| + | 
| + Handle<JSFunction> functions[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + functions[i] = factory->NewFunction(factory->empty_string()); | 
| + } | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + Handle<Map> intermediate_maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + PropertyAttributes attributes = static_cast<PropertyAttributes>(i % 8); | 
| + map = expectations.AddDataConstant(map, attributes, functions[i]); | 
| + intermediate_maps[i] = map; | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK(expectations.Check(*intermediate_maps[i], i + 1)); | 
| + } | 
| + | 
| + // Try to follow same transitions from the |initial_map|. | 
| + Handle<Map> map2 = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + PropertyAttributes attributes = static_cast<PropertyAttributes>(i % 8); | 
| + Handle<String> name = MakeName("prop", i); | 
| + map2 = | 
| + Map::TransitionToDataProperty(map2, name, functions[i], attributes, | 
| + Object::CERTAINLY_NOT_STORE_FROM_KEYED); | 
| + | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(!map2->is_dictionary_map()); | 
| + CHECK_EQ(*intermediate_maps[i], *map2); | 
| + CHECK(expectations.Check(*map2, i + 1)); | 
| + } | 
| +} | 
| + | 
| + | 
| +TEST(TransitionToAccessorConstantProperty) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + | 
| + const int kPropCount = 50; | 
| + Expectations expectations(isolate); | 
| + | 
| + Handle<AccessorPair> accessor_pairs[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + // Getter only accessors. | 
| + accessor_pairs[i] = CreateAccessorPair(true, false); | 
| + } | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + Handle<Map> intermediate_maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + PropertyAttributes attributes = static_cast<PropertyAttributes>(i % 8); | 
| + map = expectations.AddAccessorConstant( | 
| + map, attributes, handle(accessor_pairs[i]->getter(), isolate), | 
| + handle(accessor_pairs[i]->setter(), isolate)); | 
| + intermediate_maps[i] = map; | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK(expectations.Check(*intermediate_maps[i], i + 1)); | 
| + } | 
| + | 
| + // Try to follow same transitions from the |initial_map|. | 
| + Handle<Map> map2 = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + PropertyAttributes attributes = static_cast<PropertyAttributes>(i % 8); | 
| + Handle<String> name = MakeName("prop", i); | 
| + Handle<Object> getter(accessor_pairs[i]->getter(), isolate); | 
| + Handle<Object> setter(accessor_pairs[i]->setter(), isolate); | 
| + | 
| + map2 = Map::TransitionToAccessorProperty(map2, name, ACCESSOR_GETTER, | 
| + getter, attributes); | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(!map2->is_dictionary_map()); | 
| + | 
| + map2 = Map::TransitionToAccessorProperty(map2, name, ACCESSOR_SETTER, | 
| + setter, attributes); | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(!map2->is_dictionary_map()); | 
| + CHECK_EQ(*intermediate_maps[i], *map2); | 
| + CHECK(expectations.Check(*map2, i + 1)); | 
| + } | 
| +} | 
| + | 
| + | 
| +//////////////////////////////////////////////////////////////////////////////// | 
| +// A set of tests for representation generalization case. | 
| +// | 
| + | 
| +TEST(GeneralizeRepresentationSmiToDouble) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::Smi(), any_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create new maps by generalizing representation of propX field to double. | 
| + Handle<Map> maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> new_map = Map::ReconfigureProperty( | 
| + map, i, kData, NONE, Representation::Double(), any_type, FORCE_FIELD); | 
| + maps[i] = new_map; | 
| + | 
| + expectations.SetDataField(i, Representation::Double(), any_type); | 
| + | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + CHECK(i == 0 || maps[i - 1]->is_deprecated()); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + } | 
| + | 
| + Handle<Map> active_map = maps[kPropCount - 1]; | 
| + CHECK(!active_map->is_deprecated()); | 
| + | 
| + // Update all deprecated maps and check that they are now the same. | 
| + CHECK_EQ(*active_map, *Map::Update(map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK_EQ(*active_map, *Map::Update(maps[i])); | 
| + } | 
| +} | 
| + | 
| + | 
| +TEST(GeneralizeRepresentationSmiToTagged) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<HeapType> value_type = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::Smi(), any_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create new maps by generalizing representation of propX field to heap | 
| + // object. | 
| + Handle<Map> maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> new_map = Map::ReconfigureProperty(map, i, kData, NONE, | 
| + Representation::HeapObject(), | 
| + value_type, FORCE_FIELD); | 
| + maps[i] = new_map; | 
| + | 
| + expectations.SetDataField(i, Representation::Tagged(), any_type); | 
| + | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + CHECK(i == 0 || maps[i - 1]->is_deprecated()); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + } | 
| + | 
| + Handle<Map> active_map = maps[kPropCount - 1]; | 
| + CHECK(!active_map->is_deprecated()); | 
| + | 
| + // Update all deprecated maps and check that they are now the same. | 
| + CHECK_EQ(*active_map, *Map::Update(map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK_EQ(*active_map, *Map::Update(maps[i])); | 
| + } | 
| +} | 
| + | 
| + | 
| +TEST(GeneralizeRepresentationDoubleToTagged) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<HeapType> value_type = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::Double(), | 
| + any_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create new maps by generalizing representation of propX field to heap | 
| + // object. | 
| + Handle<Map> maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> new_map = Map::ReconfigureProperty(map, i, kData, NONE, | 
| + Representation::HeapObject(), | 
| + value_type, FORCE_FIELD); | 
| + maps[i] = new_map; | 
| + | 
| + expectations.SetDataField(i, Representation::Tagged(), any_type); | 
| + | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + CHECK(i == 0 || maps[i - 1]->is_deprecated()); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + } | 
| + | 
| + Handle<Map> active_map = maps[kPropCount - 1]; | 
| + CHECK(!active_map->is_deprecated()); | 
| + | 
| + // Update all deprecated maps and check that they are now the same. | 
| + CHECK_EQ(*active_map, *Map::Update(map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK_EQ(*active_map, *Map::Update(maps[i])); | 
| + } | 
| +} | 
| + | 
| + | 
| +TEST(GeneralizeRepresentationHeapObjectToTagged) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<HeapType> value_type = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::HeapObject(), | 
| + value_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create new maps by generalizing representation of propX field to smi. | 
| + Handle<Map> maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> new_map = Map::ReconfigureProperty( | 
| + map, i, kData, NONE, Representation::Smi(), any_type, FORCE_FIELD); | 
| + maps[i] = new_map; | 
| + | 
| + expectations.SetDataField(i, Representation::Tagged(), any_type); | 
| + | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + CHECK(i == 0 || maps[i - 1]->is_deprecated()); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + } | 
| + | 
| + Handle<Map> active_map = maps[kPropCount - 1]; | 
| + CHECK(!active_map->is_deprecated()); | 
| + | 
| + // Update all deprecated maps and check that they are now the same. | 
| + CHECK_EQ(*active_map, *Map::Update(map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK_EQ(*active_map, *Map::Update(maps[i])); | 
| + } | 
| +} | 
| 
Toon Verwaest
2015/01/30 13:02:53
Seems like you could merge the few tests above int
 | 
| + | 
| + | 
| +TEST(GeneralizeRepresentationHeapObjectToHeapObject) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> value_type = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::HeapObject(), | 
| + value_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create some value types. | 
| + static const int kAdditionalValueTypesCount = 4; | 
| + Handle<HeapType> value_types[kAdditionalValueTypesCount]; | 
| + for (int i = 0; i < kAdditionalValueTypesCount; i++) { | 
| + Handle<Map> value_map = Map::Create(isolate, 0); | 
| + CHECK(value_map->is_stable()); | 
| + value_types[i] = HeapType::Class(value_map, isolate); | 
| + } | 
| + | 
| + Zone zone; | 
| + | 
| + // Create new maps by generalizing representation of propX field to various | 
| + // HeapObject types with stable maps. | 
| + for (int val_index = 0; val_index < kAdditionalValueTypesCount; val_index++) { | 
| + Handle<Map> maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> field_owner(map->FindFieldOwner(i), isolate); | 
| + CompilationInfo info(isolate, &zone); | 
| + CHECK(!info.HasAbortedDueToDependencyChange()); | 
| + | 
| + Map::AddDependentCompilationInfo(field_owner, | 
| + DependentCode::kFieldTypeGroup, &info); | 
| + | 
| + Handle<Map> new_map = Map::ReconfigureProperty( | 
| + map, i, kData, NONE, Representation::HeapObject(), | 
| + value_types[val_index], FORCE_FIELD); | 
| + maps[i] = new_map; | 
| + | 
| + expectations.SetDataField( | 
| + i, Representation::HeapObject(), | 
| + HeapType::Union(value_types[val_index], expectations.GetFieldType(i), | 
| + isolate)); | 
| + | 
| + // Maps should stay the same but field type modification should trigger | 
| + // respective dependents to deoptimize. | 
| + CHECK_EQ(*map, *new_map); | 
| + CHECK(info.HasAbortedDueToDependencyChange()); | 
| + info.RollbackDependencies(); // Properly cleanup compilation info. | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + } | 
| + | 
| + Handle<Map> active_map = maps[kPropCount - 1]; | 
| + CHECK(!active_map->is_deprecated()); | 
| + | 
| + // Update all deprecated maps and check that they are now the same. | 
| + CHECK_EQ(*active_map, *Map::Update(map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK_EQ(*active_map, *Map::Update(maps[i])); | 
| + } | 
| + } | 
| +} | 
| + | 
| + | 
| +TEST(GeneralizeRepresentationNoneToSmi) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> none_type = HeapType::None(isolate); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = | 
| + expectations.AddDataField(map, NONE, Representation::None(), none_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create new maps by generalizing representation of propX field to smi. | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> new_map = Map::ReconfigureProperty( | 
| + map, i, kData, NONE, Representation::Smi(), any_type, FORCE_FIELD); | 
| + | 
| + expectations.SetDataField(i, Representation::Smi(), any_type); | 
| + | 
| + CHECK_EQ(*map, *new_map); // None -> Smi change is trivial. | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + } | 
| + | 
| + CHECK_EQ(*map, *Map::Update(map)); | 
| +} | 
| + | 
| + | 
| +TEST(GeneralizeRepresentationNoneToDouble) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> none_type = HeapType::None(isolate); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = | 
| + expectations.AddDataField(map, NONE, Representation::None(), none_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create new maps by generalizing representation of propX field to heap | 
| + // object. | 
| + Handle<Map> maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> new_map = Map::ReconfigureProperty( | 
| + map, i, kData, NONE, Representation::Double(), any_type, FORCE_FIELD); | 
| + maps[i] = new_map; | 
| + | 
| + expectations.SetDataField(i, Representation::Double(), any_type); | 
| + | 
| + CHECK(map->is_deprecated()); // None -> Double change is NOT trivial. | 
| + CHECK_NE(*map, *new_map); | 
| + CHECK(i == 0 || maps[i - 1]->is_deprecated()); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + } | 
| + | 
| + Handle<Map> active_map = maps[kPropCount - 1]; | 
| + CHECK(!active_map->is_deprecated()); | 
| + | 
| + // Update all deprecated maps and check that they are now the same. | 
| + CHECK_EQ(*active_map, *Map::Update(map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK_EQ(*active_map, *Map::Update(maps[i])); | 
| + } | 
| +} | 
| + | 
| + | 
| +TEST(GeneralizeRepresentationNoneToHeapObject) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> none_type = HeapType::None(isolate); | 
| + Handle<HeapType> value_type = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = | 
| + expectations.AddDataField(map, NONE, Representation::None(), none_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create new maps by generalizing representation of propX field to heap | 
| + // object. | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> new_map = Map::ReconfigureProperty(map, i, kData, NONE, | 
| + Representation::HeapObject(), | 
| + value_type, FORCE_FIELD); | 
| + | 
| + expectations.SetDataField(i, Representation::HeapObject(), value_type); | 
| + | 
| + CHECK_EQ(*map, *new_map); // None -> HeapObject change is trivial. | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + } | 
| + | 
| + CHECK_EQ(*map, *Map::Update(map)); | 
| +} | 
| + | 
| + | 
| +TEST(GeneralizeRepresentationNoneToTagged) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> none_type = HeapType::None(isolate); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = | 
| + expectations.AddDataField(map, NONE, Representation::None(), none_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create new maps by generalizing representation of propX field to heap | 
| + // object. | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> new_map = Map::ReconfigureProperty( | 
| + map, i, kData, NONE, Representation::Tagged(), any_type, FORCE_FIELD); | 
| + | 
| + expectations.SetDataField(i, Representation::Tagged(), any_type); | 
| + | 
| + CHECK_EQ(*map, *new_map); // None -> Tagged change is trivial. | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + } | 
| + | 
| + CHECK_EQ(*map, *Map::Update(map)); | 
| +} | 
| + | 
| + | 
| +//////////////////////////////////////////////////////////////////////////////// | 
| +// A set of tests for representation generalization case with kAccessor | 
| +// properties. | 
| +// | 
| + | 
| +TEST(GeneralizeRepresentationWithAccessorProperties) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<AccessorPair> pair = CreateAccessorPair(true, true); | 
| + | 
| + const int kPropCount = 5; | 
| + const int kAccessorProp = kPropCount / 2; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + if (i == kAccessorProp) { | 
| + map = expectations.AddAccessorConstant(map, NONE, pair); | 
| + } else { | 
| + map = | 
| + expectations.AddDataField(map, NONE, Representation::Smi(), any_type); | 
| + } | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create new maps by generalizing representation of propX field to double. | 
| + Handle<Map> maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + if (i == kAccessorProp) { | 
| + // Skip accessor property reconfiguration. | 
| + maps[i] = maps[i - 1]; | 
| + continue; | 
| + } | 
| + Handle<Map> new_map = Map::ReconfigureProperty( | 
| + map, i, kData, NONE, Representation::Double(), any_type, FORCE_FIELD); | 
| + maps[i] = new_map; | 
| + | 
| + expectations.SetDataField(i, Representation::Double(), any_type); | 
| + | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + CHECK(i == 0 || maps[i - 1]->is_deprecated()); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + } | 
| + | 
| + Handle<Map> active_map = maps[kPropCount - 1]; | 
| + CHECK(!active_map->is_deprecated()); | 
| + | 
| + // Update all deprecated maps and check that they are now the same. | 
| + CHECK_EQ(*active_map, *Map::Update(map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK_EQ(*active_map, *Map::Update(maps[i])); | 
| + } | 
| +} | 
| + | 
| + | 
| +//////////////////////////////////////////////////////////////////////////////// | 
| +// A set of tests for property location change case. | 
| +// | 
| + | 
| +TEST(ReconfigureDataConstantToDataField) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Factory* factory = isolate->factory(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<JSFunction> js_func = factory->NewFunction(factory->empty_string()); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataConstant(map, NONE, js_func); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create new maps by forcing propX to become a field. | 
| + Handle<Map> maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> new_map = Map::ReconfigureProperty(map, i, kData, NONE, | 
| + Representation::HeapObject(), | 
| + any_type, FORCE_FIELD); | 
| + maps[i] = new_map; | 
| + | 
| + expectations.SetDataField(i, Representation::HeapObject(), any_type); | 
| + | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + CHECK(i == 0 || maps[i - 1]->is_deprecated()); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + } | 
| + | 
| + Handle<Map> active_map = maps[kPropCount - 1]; | 
| + CHECK(!active_map->is_deprecated()); | 
| + | 
| + // Update all deprecated maps and check that they are now the same. | 
| + CHECK_EQ(*active_map, *Map::Update(map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK_EQ(*active_map, *Map::Update(maps[i])); | 
| + } | 
| +} | 
| + | 
| + | 
| +TEST(ReconfigureAccessorConstantToAccessorField) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Factory* factory = isolate->factory(); | 
| + Handle<JSFunction> getter = factory->NewFunction(factory->empty_string()); | 
| + Handle<JSFunction> setter = factory->NewFunction(factory->empty_string()); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + Handle<AccessorPair> accessor_pairs[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + // Getter only accessors. | 
| + accessor_pairs[i] = CreateAccessorPair(true, false); | 
| + } | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + Handle<Map> intermediate_maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddAccessorConstant( | 
| + map, NONE, handle(accessor_pairs[i]->getter(), isolate), | 
| + handle(accessor_pairs[i]->setter(), isolate)); | 
| + intermediate_maps[i] = map; | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK(expectations.Check(*intermediate_maps[i], i + 1)); | 
| + } | 
| + | 
| + // Try to follow same transitions from the |initial_map|. | 
| + Handle<Map> map2 = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<String> name = MakeName("prop", i); | 
| + map2 = Map::TransitionToAccessorProperty(map2, name, ACCESSOR_GETTER, | 
| + getter, NONE); | 
| + if (IS_ACCESSOR_FIELD_SUPPORTED) { | 
| + CHECK(!map2->is_dictionary_map()); | 
| + } else { | 
| + CHECK(map2->is_dictionary_map()); | 
| + } | 
| + | 
| + map2 = Map::TransitionToAccessorProperty(map2, name, ACCESSOR_SETTER, | 
| + setter, NONE); | 
| + if (IS_ACCESSOR_FIELD_SUPPORTED) { | 
| + CHECK(!map2->is_dictionary_map()); | 
| + CHECK(expectations.Check(*map2, i + 1)); | 
| + } else { | 
| + CHECK(map2->is_dictionary_map()); | 
| + } | 
| + } | 
| + | 
| + if (!IS_ACCESSOR_FIELD_SUPPORTED) { | 
| + CHECK(map2->is_dictionary_map()); | 
| + } | 
| +} | 
| + | 
| + | 
| +//////////////////////////////////////////////////////////////////////////////// | 
| +// A set of tests for attribute reconfiguration case. | 
| +// | 
| + | 
| +TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationSmiToDouble) { | 
| 
Toon Verwaest
2015/01/30 13:02:53
Same here?
 | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::Smi(), any_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + | 
| + // Create another branch in transition tree (property at index |kSplitProp| | 
| + // has different attributes), initialize expectations. | 
| + const int kSplitProp = kPropCount / 2; | 
| + Expectations expectations2(isolate); | 
| + | 
| + Handle<Map> map2 = initial_map; | 
| + for (int i = 0; i < kSplitProp; i++) { | 
| + map2 = expectations2.FollowDataTransition(map2, NONE, Representation::Smi(), | 
| + any_type); | 
| + } | 
| + map2 = expectations2.AddDataField(map2, READ_ONLY, Representation::Double(), | 
| + any_type); | 
| + | 
| + for (int i = kSplitProp + 1; i < kPropCount; i++) { | 
| + map2 = expectations2.AddDataField(map2, NONE, Representation::Double(), | 
| + any_type); | 
| + } | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(map2->is_stable()); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + | 
| + // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which | 
| + // should generalize representations in |map1|. | 
| + Handle<Map> new_map = | 
| + Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE); | 
| + | 
| + // |map2| should be left unchanged. | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK_NE(*map2, *new_map); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + // |map| should be deprecated and |new_map| should match new expectations. | 
| + for (int i = kSplitProp; i < kPropCount; i++) { | 
| + expectations.SetDataField(i, Representation::Double(), any_type); | 
| + } | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + | 
| + // Update deprecated |map|, it should become |new_map|. | 
| + CHECK_EQ(*new_map, *Map::Update(map)); | 
| +} | 
| + | 
| + | 
| +TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationSmiToTagged) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<HeapType> value_type = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::Smi(), any_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create another branch in transition tree (property at index |kSplitProp| | 
| + // has different attributes), initialize expectations. | 
| + const int kSplitProp = kPropCount / 2; | 
| + Expectations expectations2(isolate); | 
| + | 
| + Handle<Map> map2 = initial_map; | 
| + for (int i = 0; i < kSplitProp; i++) { | 
| + map2 = expectations2.FollowDataTransition(map2, NONE, Representation::Smi(), | 
| + any_type); | 
| + } | 
| + map2 = expectations2.AddDataField(map2, READ_ONLY, | 
| + Representation::HeapObject(), value_type); | 
| + | 
| + for (int i = kSplitProp + 1; i < kPropCount; i++) { | 
| + map2 = expectations2.AddDataField(map2, NONE, Representation::HeapObject(), | 
| + value_type); | 
| + } | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(map2->is_stable()); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + | 
| + // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which | 
| + // should generalize representations in |map1|. | 
| + Handle<Map> new_map = | 
| + Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE); | 
| + | 
| + // |map2| should be left unchanged. | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK_NE(*map2, *new_map); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + // |map| should be deprecated and |new_map| should match new expectations. | 
| + for (int i = kSplitProp; i < kPropCount; i++) { | 
| + expectations.SetDataField(i, Representation::Tagged(), any_type); | 
| + } | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + | 
| + // Update deprecated |map|, it should become |new_map|. | 
| + CHECK_EQ(*new_map, *Map::Update(map)); | 
| +} | 
| + | 
| + | 
| +TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationDoubleToTagged) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<HeapType> value_type = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::Double(), | 
| + any_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + | 
| + // Create another branch in transition tree (property at index |kSplitProp| | 
| + // has different attributes), initialize expectations. | 
| + const int kSplitProp = kPropCount / 2; | 
| + Expectations expectations2(isolate); | 
| + | 
| + Handle<Map> map2 = initial_map; | 
| + for (int i = 0; i < kSplitProp; i++) { | 
| + map2 = expectations2.FollowDataTransition( | 
| + map2, NONE, Representation::Double(), any_type); | 
| + } | 
| + map2 = expectations2.AddDataField(map2, READ_ONLY, | 
| + Representation::HeapObject(), value_type); | 
| + | 
| + for (int i = kSplitProp + 1; i < kPropCount; i++) { | 
| + map2 = expectations2.AddDataField(map2, NONE, Representation::HeapObject(), | 
| + value_type); | 
| + } | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(map2->is_stable()); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + | 
| + // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which | 
| + // should generalize representations in |map1|. | 
| + Handle<Map> new_map = | 
| + Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE); | 
| + | 
| + // |map2| should be left unchanged. | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK_NE(*map2, *new_map); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + // |map| should be deprecated and |new_map| should match new expectations. | 
| + for (int i = kSplitProp; i < kPropCount; i++) { | 
| + expectations.SetDataField(i, Representation::Tagged(), any_type); | 
| + } | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + | 
| + // Update deprecated |map|, it should become |new_map|. | 
| + CHECK_EQ(*new_map, *Map::Update(map)); | 
| +} | 
| + | 
| + | 
| +TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationHeapObjectToTagged) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<HeapType> value_type = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::HeapObject(), | 
| + value_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + | 
| + // Create another branch in transition tree (property at index |kSplitProp| | 
| + // has different attributes), initialize expectations. | 
| + const int kSplitProp = kPropCount / 2; | 
| + Expectations expectations2(isolate); | 
| + | 
| + Handle<Map> map2 = initial_map; | 
| + for (int i = 0; i < kSplitProp; i++) { | 
| + map2 = expectations2.FollowDataTransition( | 
| + map2, NONE, Representation::HeapObject(), value_type); | 
| + } | 
| + map2 = expectations2.AddDataField(map2, READ_ONLY, Representation::Smi(), | 
| + any_type); | 
| + | 
| + for (int i = kSplitProp + 1; i < kPropCount; i++) { | 
| + map2 = | 
| + expectations2.AddDataField(map2, NONE, Representation::Smi(), any_type); | 
| + } | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(map2->is_stable()); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + | 
| + // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which | 
| + // should generalize representations in |map1|. | 
| + Handle<Map> new_map = | 
| + Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE); | 
| + | 
| + // |map2| should be left unchanged. | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK_NE(*map2, *new_map); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + // |map| should be deprecated and |new_map| should match new expectations. | 
| + for (int i = kSplitProp; i < kPropCount; i++) { | 
| + expectations.SetDataField(i, Representation::Tagged(), any_type); | 
| + } | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + | 
| + // Update deprecated |map|, it should become |new_map|. | 
| + CHECK_EQ(*new_map, *Map::Update(map)); | 
| +} | 
| + | 
| + | 
| +TEST(ReconfigureDataFieldAttribute_SameDataConstantAfterTargetMap) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Factory* factory = isolate->factory(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<JSFunction> js_func = factory->NewFunction(factory->empty_string()); | 
| + Handle<HeapType> value_type = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 7; | 
| + const int kConstantPropIndex = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + if (i == kConstantPropIndex) { | 
| + map = expectations.AddDataConstant(map, NONE, js_func); | 
| + | 
| + } else { | 
| + map = | 
| + expectations.AddDataField(map, NONE, Representation::Smi(), any_type); | 
| + } | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create another branch in transition tree (property at index |kSplitProp| | 
| + // has different attributes), initialize expectations. | 
| + const int kSplitProp = 2; | 
| + Expectations expectations2(isolate); | 
| + | 
| + Handle<Map> map2 = initial_map; | 
| + for (int i = 0; i < kSplitProp; i++) { | 
| + map2 = expectations2.FollowDataTransition(map2, NONE, Representation::Smi(), | 
| + any_type); | 
| + } | 
| + map2 = expectations2.AddDataField(map2, READ_ONLY, | 
| + Representation::HeapObject(), value_type); | 
| + | 
| + for (int i = kSplitProp + 1; i < kPropCount; i++) { | 
| + if (i == kConstantPropIndex) { | 
| + map2 = expectations2.AddDataConstant(map2, NONE, js_func); | 
| + | 
| + } else { | 
| + map2 = expectations2.AddDataField(map2, NONE, Representation::Smi(), | 
| + any_type); | 
| + } | 
| + } | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(map2->is_stable()); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + | 
| + // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which | 
| + // should generalize representations in |map1|. | 
| + Handle<Map> new_map = | 
| + Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE); | 
| + | 
| + // |map2| should be left unchanged. | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK_NE(*map2, *new_map); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + // |map| should be deprecated and |new_map| should match new expectations. | 
| + expectations.SetDataField(kSplitProp, Representation::Tagged(), any_type); | 
| + | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + | 
| + // Update deprecated |map|, it should become |new_map|. | 
| + CHECK_EQ(*new_map, *Map::Update(map)); | 
| +} | 
| + | 
| + | 
| +TEST(ReconfigureDataFieldAttribute_DataConstantToDataFieldAfterTargetMap) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Factory* factory = isolate->factory(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<JSFunction> js_func = factory->NewFunction(factory->empty_string()); | 
| + Handle<JSFunction> js_func2 = factory->NewFunction(factory->empty_string()); | 
| + Handle<HeapType> value_type = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 7; | 
| + const int kConstantPropIndex = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + if (i == kConstantPropIndex) { | 
| + map = expectations.AddDataConstant(map, NONE, js_func); | 
| + | 
| + } else { | 
| + map = | 
| + expectations.AddDataField(map, NONE, Representation::Smi(), any_type); | 
| + } | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create another branch in transition tree (property at index |kSplitProp| | 
| + // has different attributes), initialize expectations. | 
| + const int kSplitProp = 2; | 
| + Expectations expectations2(isolate); | 
| + | 
| + Handle<Map> map2 = initial_map; | 
| + for (int i = 0; i < kSplitProp; i++) { | 
| + map2 = expectations2.FollowDataTransition(map2, NONE, Representation::Smi(), | 
| + any_type); | 
| + } | 
| + map2 = expectations2.AddDataField(map2, READ_ONLY, | 
| + Representation::HeapObject(), value_type); | 
| + | 
| + for (int i = kSplitProp + 1; i < kPropCount; i++) { | 
| + if (i == kConstantPropIndex) { | 
| + map2 = expectations2.AddDataConstant(map2, NONE, js_func2); | 
| + | 
| + } else { | 
| + map2 = expectations2.AddDataField(map2, NONE, Representation::Smi(), | 
| + any_type); | 
| + } | 
| + } | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(map2->is_stable()); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + | 
| + // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which | 
| + // should generalize representations in |map1|. | 
| + Handle<Map> new_map = | 
| + Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE); | 
| + | 
| + // |map2| should be left unchanged. | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK_NE(*map2, *new_map); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + // |map| should be deprecated and |new_map| should match new expectations. | 
| + expectations.SetDataField(kSplitProp, Representation::Tagged(), any_type); | 
| + expectations.SetDataField(kConstantPropIndex, Representation::HeapObject(), | 
| + any_type); | 
| + | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + | 
| + // Update deprecated |map|, it should become |new_map|. | 
| + CHECK_EQ(*new_map, *Map::Update(map)); | 
| +} | 
| + | 
| + | 
| +TEST(ReconfigureDataFieldAttribute_SameAccessorConstantAfterTargetMap) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<AccessorPair> pair = CreateAccessorPair(true, true); | 
| + Handle<HeapType> value_type = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 7; | 
| + const int kConstantPropIndex = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + if (i == kConstantPropIndex) { | 
| + map = expectations.AddAccessorConstant(map, NONE, pair); | 
| + | 
| + } else { | 
| + map = | 
| + expectations.AddDataField(map, NONE, Representation::Smi(), any_type); | 
| + } | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create another branch in transition tree (property at index |kSplitProp| | 
| + // has different attributes), initialize expectations. | 
| + const int kSplitProp = 2; | 
| + Expectations expectations2(isolate); | 
| + | 
| + Handle<Map> map2 = initial_map; | 
| + for (int i = 0; i < kSplitProp; i++) { | 
| + map2 = expectations2.FollowDataTransition(map2, NONE, Representation::Smi(), | 
| + any_type); | 
| + } | 
| + map2 = expectations2.AddDataField(map2, READ_ONLY, | 
| + Representation::HeapObject(), value_type); | 
| + | 
| + for (int i = kSplitProp + 1; i < kPropCount; i++) { | 
| + if (i == kConstantPropIndex) { | 
| + map2 = expectations2.AddAccessorConstant(map2, NONE, pair); | 
| + | 
| + } else { | 
| + map2 = expectations2.AddDataField(map2, NONE, Representation::Smi(), | 
| + any_type); | 
| + } | 
| + } | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(map2->is_stable()); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + | 
| + // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which | 
| + // should generalize representations in |map1|. | 
| + Handle<Map> new_map = | 
| + Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE); | 
| + | 
| + // |map2| should be left unchanged. | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK_NE(*map2, *new_map); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + // |map| should be deprecated and |new_map| should match new expectations. | 
| + expectations.SetDataField(kSplitProp, Representation::Tagged(), any_type); | 
| + | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + | 
| + // Update deprecated |map|, it should become |new_map|. | 
| + CHECK_EQ(*new_map, *Map::Update(map)); | 
| +} | 
| + | 
| + | 
| +TEST(ReconfigureDataFieldAttribute_AccConstantToAccFieldAfterTargetMap) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<AccessorPair> pair = CreateAccessorPair(true, true); | 
| + Handle<AccessorPair> pair2 = CreateAccessorPair(true, true); | 
| + Handle<HeapType> value_type = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 7; | 
| + const int kConstantPropIndex = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + if (i == kConstantPropIndex) { | 
| + map = expectations.AddAccessorConstant(map, NONE, pair); | 
| + | 
| + } else { | 
| + map = | 
| + expectations.AddDataField(map, NONE, Representation::Smi(), any_type); | 
| + } | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create another branch in transition tree (property at index |kSplitProp| | 
| + // has different attributes), initialize expectations. | 
| + const int kSplitProp = 2; | 
| + Expectations expectations2(isolate); | 
| + | 
| + Handle<Map> map2 = initial_map; | 
| + for (int i = 0; i < kSplitProp; i++) { | 
| + map2 = expectations2.FollowDataTransition(map2, NONE, Representation::Smi(), | 
| + any_type); | 
| + } | 
| + map2 = expectations2.AddDataField(map2, READ_ONLY, | 
| + Representation::HeapObject(), value_type); | 
| + | 
| + for (int i = kSplitProp + 1; i < kPropCount; i++) { | 
| + if (i == kConstantPropIndex) { | 
| + map2 = expectations2.AddAccessorConstant(map2, NONE, pair2); | 
| + | 
| + } else { | 
| + map2 = expectations2.AddDataField(map2, NONE, Representation::Smi(), | 
| + any_type); | 
| + } | 
| + } | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(map2->is_stable()); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + | 
| + // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which | 
| + // should generalize representations in |map1|. | 
| + Handle<Map> new_map = | 
| + Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE); | 
| + | 
| + // |map2| should be left unchanged. | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK_NE(*map2, *new_map); | 
| + CHECK(expectations2.Check(*map2)); | 
| + | 
| + // |map| should be deprecated and |new_map| should match new expectations. | 
| + if (IS_ACCESSOR_FIELD_SUPPORTED) { | 
| + expectations.SetDataField(kSplitProp, Representation::Tagged(), any_type); | 
| + expectations.SetAccessorField(kConstantPropIndex); | 
| + | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + | 
| + // Update deprecated |map|, it should become |new_map|. | 
| + CHECK_EQ(*new_map, *Map::Update(map)); | 
| + } else { | 
| + // Currently we have a copy-generalize all representations case. | 
| + CHECK(new_map->GetBackPointer()->IsUndefined()); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + if (i == kConstantPropIndex) { | 
| + expectations.SetAccessorConstant(i, pair2); | 
| + | 
| + } else { | 
| + expectations.SetDataField(i, Representation::Tagged(), any_type); | 
| + } | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + } | 
| +} | 
| + | 
| + | 
| +//////////////////////////////////////////////////////////////////////////////// | 
| +// A set of tests checking split map deprecation. | 
| +// | 
| + | 
| +TEST(ReconfigurePropertySplitMapTransitionsOverflow) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::Smi(), any_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + | 
| + // Generalize representation of property at index |kSplitProp|. | 
| + const int kSplitProp = kPropCount / 2; | 
| + Handle<Map> split_map; | 
| + Handle<Map> map2 = initial_map; | 
| + { | 
| + for (int i = 0; i < kSplitProp + 1; i++) { | 
| + if (i == kSplitProp) { | 
| + split_map = map2; | 
| + } | 
| + | 
| + Handle<String> name = MakeName("prop", i); | 
| + int t = map2->SearchTransition(kData, *name, NONE); | 
| + CHECK_NE(TransitionArray::kNotFound, t); | 
| + map2 = handle(map2->GetTransition(t)); | 
| + } | 
| + | 
| + map2 = Map::ReconfigureProperty(map2, kSplitProp, kData, NONE, | 
| + Representation::Double(), any_type, | 
| + FORCE_FIELD); | 
| + expectations.SetDataField(kSplitProp, Representation::Double(), any_type); | 
| + | 
| + CHECK(expectations.Check(*split_map, kSplitProp)); | 
| + CHECK(expectations.Check(*map2, kSplitProp + 1)); | 
| + } | 
| + | 
| + // At this point |map| should be deprecated and disconnected from the | 
| + // transition tree. | 
| + CHECK(map->is_deprecated()); | 
| + CHECK(!split_map->is_deprecated()); | 
| + CHECK(!map2->is_deprecated()); | 
| + | 
| + // Fill in transition tree of |map2| so that it can't have more transitions. | 
| + for (int i = 0; i < TransitionArray::kMaxNumberOfTransitions; i++) { | 
| + CHECK(map2->CanHaveMoreTransitions()); | 
| + Handle<String> name = MakeName("foo", i); | 
| + Map::CopyWithField(map2, name, any_type, NONE, Representation::Smi(), | 
| + INSERT_TRANSITION).ToHandleChecked(); | 
| + } | 
| + CHECK(!map2->CanHaveMoreTransitions()); | 
| + | 
| + // Try to update |map|, since there is no place for propX transition at |map2| | 
| + // |map| should become "copy-generalized". | 
| + Handle<Map> updated_map = Map::Update(map); | 
| + CHECK(updated_map->GetBackPointer()->IsUndefined()); | 
| + | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + expectations.SetDataField(i, Representation::Tagged(), any_type); | 
| + } | 
| + CHECK(expectations.Check(*updated_map)); | 
| +} | 
| + | 
| + | 
| +//////////////////////////////////////////////////////////////////////////////// | 
| +// A set of tests involving special transitions. | 
| +// | 
| + | 
| +TEST(ElementsKindTransitionFromMapOwningDescriptor) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> value_type1 = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + Handle<HeapType> value_type2 = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::HeapObject(), | 
| + value_type1); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + CHECK(map->owns_descriptors()); | 
| + | 
| + // Create an elements kind transition, it should always match |expectations|. | 
| + Handle<Map> map2 = | 
| + Map::CopyAsElementsKind(map, DICTIONARY_ELEMENTS, INSERT_TRANSITION); | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(map2->is_stable()); | 
| + CHECK(expectations.Check(*map2)); | 
| + | 
| + // |map1| should still match expectations. | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create new maps by generalizing representation of propX field to various | 
| + // HeapObject types with stable maps. | 
| + Handle<Map> maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> new_map = Map::ReconfigureProperty(map, i, kData, NONE, | 
| + Representation::HeapObject(), | 
| + value_type2, FORCE_FIELD); | 
| + maps[i] = new_map; | 
| + | 
| + expectations.SetDataField( | 
| + i, Representation::HeapObject(), | 
| + HeapType::Union(value_type2, expectations.GetFieldType(i), isolate)); | 
| + | 
| + // Maps should stay the same but field type modification should trigger | 
| + // respective dependents to deoptimize. | 
| + CHECK_EQ(*map, *new_map); | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + | 
| + if (IS_NON_EQUIVALENT_TRANSITION_SUPPORTED) { | 
| + Handle<Map> new_map2 = Map::Update(map2); | 
| + CHECK(!new_map2->is_deprecated()); | 
| + CHECK(!new_map2->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map2)); | 
| + } | 
| + } | 
| + | 
| + Handle<Map> active_map = maps[kPropCount - 1]; | 
| + CHECK(!active_map->is_deprecated()); | 
| + | 
| + // Update all deprecated maps and check that they are now the same. | 
| + CHECK_EQ(*active_map, *Map::Update(map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK_EQ(*active_map, *Map::Update(maps[i])); | 
| + } | 
| +} | 
| + | 
| + | 
| +TEST(ElementsKindTransitionFromMapNotOwningDescriptor) { | 
| + if (!IS_CRBUG_448711_FIXED) return; | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<HeapType> value_type1 = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + Handle<HeapType> value_type2 = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::HeapObject(), | 
| + value_type1); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Add one more transition to |map| in order to prevent descriptors ownership. | 
| + CHECK(map->owns_descriptors()); | 
| + Map::CopyWithField(map, MakeString("foo"), any_type, NONE, | 
| + Representation::Smi(), | 
| + INSERT_TRANSITION).ToHandleChecked(); | 
| + CHECK(!map->owns_descriptors()); | 
| + | 
| + // Create an elements kind transition, it should always match |expectations|. | 
| + Handle<Map> map2 = | 
| + Map::CopyAsElementsKind(map, DICTIONARY_ELEMENTS, INSERT_TRANSITION); | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(map2->is_stable()); | 
| + CHECK(expectations.Check(*map2)); | 
| + | 
| + // |map1| should still match expectations. | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create new maps by generalizing representation of propX field to various | 
| + // HeapObject types with stable maps. | 
| + Handle<Map> maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> new_map = Map::ReconfigureProperty(map, i, kData, NONE, | 
| + Representation::HeapObject(), | 
| + value_type2, FORCE_FIELD); | 
| + maps[i] = new_map; | 
| + | 
| + expectations.SetDataField( | 
| + i, Representation::HeapObject(), | 
| + HeapType::Union(value_type2, expectations.GetFieldType(i), isolate)); | 
| + | 
| + // Maps should stay the same but field type modification should trigger | 
| + // respective dependents to deoptimize. | 
| + CHECK_EQ(*map, *new_map); | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + | 
| + if (IS_NON_EQUIVALENT_TRANSITION_SUPPORTED) { | 
| + Handle<Map> new_map2 = Map::Update(map2); | 
| + CHECK(!new_map2->is_deprecated()); | 
| + CHECK(!new_map2->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map2)); | 
| + } | 
| + } | 
| + | 
| + Handle<Map> active_map = maps[kPropCount - 1]; | 
| + CHECK(!active_map->is_deprecated()); | 
| + | 
| + // Update all deprecated maps and check that they are now the same. | 
| + CHECK_EQ(*active_map, *Map::Update(map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK_EQ(*active_map, *Map::Update(maps[i])); | 
| + } | 
| +} | 
| + | 
| + | 
| +TEST(ForObservedTransitionFromMapOwningDescriptor) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> value_type1 = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + Handle<HeapType> value_type2 = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::HeapObject(), | 
| + value_type1); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + CHECK(map->owns_descriptors()); | 
| + | 
| + // Create "for-observed" transition, it should always match |expectations|. | 
| + Handle<Map> map2 = Map::CopyForObserved(map); | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(map2->is_stable()); | 
| + CHECK(expectations.Check(*map2)); | 
| + | 
| + // |map1| should still match expectations. | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create new maps by generalizing representation of propX field to various | 
| + // HeapObject types with stable maps. | 
| + Handle<Map> maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> new_map = Map::ReconfigureProperty(map, i, kData, NONE, | 
| + Representation::HeapObject(), | 
| + value_type2, FORCE_FIELD); | 
| + maps[i] = new_map; | 
| + | 
| + expectations.SetDataField( | 
| + i, Representation::HeapObject(), | 
| + HeapType::Union(value_type2, expectations.GetFieldType(i), isolate)); | 
| + | 
| + // Maps should stay the same but field type modification should trigger | 
| + // respective dependents to deoptimize. | 
| + CHECK_EQ(*map, *new_map); | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + | 
| + if (IS_NON_EQUIVALENT_TRANSITION_SUPPORTED) { | 
| + Handle<Map> new_map2 = Map::Update(map2); | 
| + CHECK(!new_map2->is_deprecated()); | 
| + CHECK(!new_map2->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map2)); | 
| + } | 
| + } | 
| + | 
| + Handle<Map> active_map = maps[kPropCount - 1]; | 
| + CHECK(!active_map->is_deprecated()); | 
| + | 
| + // Update all deprecated maps and check that they are now the same. | 
| + CHECK_EQ(*active_map, *Map::Update(map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK_EQ(*active_map, *Map::Update(maps[i])); | 
| + } | 
| +} | 
| + | 
| + | 
| +TEST(ForObservedTransitionFromMapNotOwningDescriptor) { | 
| + if (!IS_CRBUG_448711_FIXED) return; | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<HeapType> value_type1 = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + Handle<HeapType> value_type2 = | 
| + HeapType::Class(Map::Create(isolate, 0), isolate); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::HeapObject(), | 
| + value_type1); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Add one more transition to |map| in order to prevent descriptors ownership. | 
| + CHECK(map->owns_descriptors()); | 
| + Map::CopyWithField(map, MakeString("foo"), any_type, NONE, | 
| + Representation::Smi(), | 
| + INSERT_TRANSITION).ToHandleChecked(); | 
| + CHECK(!map->owns_descriptors()); | 
| + | 
| + // Create "for-observed" transition, it should always match |expectations|. | 
| + Handle<Map> map2 = Map::CopyForObserved(map); | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(map2->is_stable()); | 
| + CHECK(expectations.Check(*map2)); | 
| + | 
| + // |map1| should still match expectations. | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create new maps by generalizing representation of propX field to various | 
| + // HeapObject types with stable maps. | 
| + Handle<Map> maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> new_map = Map::ReconfigureProperty(map, i, kData, NONE, | 
| + Representation::HeapObject(), | 
| + value_type2, FORCE_FIELD); | 
| + maps[i] = new_map; | 
| + | 
| + expectations.SetDataField( | 
| + i, Representation::HeapObject(), | 
| + HeapType::Union(value_type2, expectations.GetFieldType(i), isolate)); | 
| + | 
| + // Maps should stay the same but field type modification should trigger | 
| + // respective dependents to deoptimize. | 
| + CHECK_EQ(*map, *new_map); | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + | 
| + if (IS_NON_EQUIVALENT_TRANSITION_SUPPORTED) { | 
| + Handle<Map> new_map2 = Map::Update(map2); | 
| + CHECK(!new_map2->is_deprecated()); | 
| + CHECK(!new_map2->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map2)); | 
| + } | 
| + } | 
| + | 
| + Handle<Map> active_map = maps[kPropCount - 1]; | 
| + CHECK(!active_map->is_deprecated()); | 
| + | 
| + // Update all deprecated maps and check that they are now the same. | 
| + CHECK_EQ(*active_map, *Map::Update(map)); | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + CHECK_EQ(*active_map, *Map::Update(maps[i])); | 
| + } | 
| +} | 
| + | 
| + | 
| +TEST(PrototypeTransitionFromMapOwningDescriptor) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Factory* factory = isolate->factory(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<JSObject> prototype = | 
| + factory->NewJSObjectFromMap(Map::Create(isolate, 0)); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::Smi(), any_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + CHECK(map->owns_descriptors()); | 
| + | 
| + // Create prototype transition, it should always match |expectations|. | 
| + Handle<Map> map2 = | 
| + Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE); | 
| + | 
| + CHECK(!map2->is_deprecated()); | 
| + CHECK(map2->is_stable()); | 
| + if (IS_CRBUG_448711_FIXED) { | 
| + CHECK(expectations.Check(*map2)); | 
| + } | 
| + | 
| + // |map1| should still match expectations. | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + CHECK_EQ(*map2, | 
| + *Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE)); | 
| + | 
| + // Create new maps by generalizing representation of propX field to double. | 
| + Handle<Map> maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> new_map = Map::ReconfigureProperty( | 
| + map, i, kData, NONE, Representation::Double(), any_type, FORCE_FIELD); | 
| + maps[i] = new_map; | 
| + | 
| + expectations.SetDataField(i, Representation::Double(), any_type); | 
| + | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + CHECK(i == 0 || maps[i - 1]->is_deprecated()); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + | 
| + if (IS_NON_EQUIVALENT_TRANSITION_SUPPORTED) { | 
| + Handle<Map> new_map2 = Map::Update(map2); | 
| + CHECK(!new_map2->is_deprecated()); | 
| + CHECK(!new_map2->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map2)); | 
| + } | 
| + } | 
| +} | 
| + | 
| + | 
| +TEST(GeneralizeRepresentationWithPrototypeTransition) { | 
| + CcTest::InitializeVM(); | 
| + v8::HandleScope scope(CcTest::isolate()); | 
| + Isolate* isolate = CcTest::i_isolate(); | 
| + Factory* factory = isolate->factory(); | 
| + Handle<HeapType> any_type = HeapType::Any(isolate); | 
| + Handle<JSObject> prototype = | 
| + factory->NewJSObjectFromMap(Map::Create(isolate, 0)); | 
| + Handle<JSFunction> js_func = factory->NewFunction(factory->empty_string()); | 
| + | 
| + const int kPropCount = 5; | 
| + Expectations expectations(isolate); | 
| + | 
| + // Create a map, add required properties to it and initialize expectations. | 
| + Handle<Map> initial_map = Map::Create(isolate, 0); | 
| + Handle<Map> map = initial_map; | 
| + map = expectations.AddDataConstant(map, NONE, js_func); | 
| + map = Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE); | 
| + if (!IS_CRBUG_448711_FIXED) { | 
| + expectations.GeneralizeRepresentation(0); | 
| + } | 
| + for (int i = 1; i < kPropCount; i++) { | 
| + map = expectations.AddDataField(map, NONE, Representation::Smi(), any_type); | 
| + } | 
| + CHECK(!map->is_deprecated()); | 
| + CHECK(map->is_stable()); | 
| + CHECK(expectations.Check(*map)); | 
| + | 
| + // Create new maps by generalizing representation of propX field to double. | 
| + Handle<Map> maps[kPropCount]; | 
| + for (int i = 0; i < kPropCount; i++) { | 
| + Handle<Map> new_map = Map::ReconfigureProperty( | 
| + map, i, kData, NONE, Representation::Double(), any_type, FORCE_FIELD); | 
| + maps[i] = new_map; | 
| + | 
| + if (!IS_NON_EQUIVALENT_TRANSITION_SUPPORTED) { | 
| + // If we reconfigure the property that was added before prototype | 
| + // transition, we would get Gen | 
| + CHECK(i != 0 || new_map->GetBackPointer()->IsUndefined()); | 
| + } | 
| + | 
| + if (IS_NON_EQUIVALENT_TRANSITION_SUPPORTED && IS_CRBUG_448711_FIXED) { | 
| + expectations.SetDataField(i, Representation::Double(), any_type); | 
| + | 
| + CHECK(map->is_deprecated()); | 
| + CHECK_NE(*map, *new_map); | 
| + CHECK(i == 0 || maps[i - 1]->is_deprecated()); | 
| + | 
| + CHECK(!new_map->is_deprecated()); | 
| + CHECK(!new_map->is_dictionary_map()); | 
| + CHECK(expectations.Check(*new_map)); | 
| + } | 
| + } | 
| +} |