Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(95)

Unified Diff: test/cctest/test-migrations.cc

Issue 888623002: Property reconfiguring implemented. Tests added. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« src/objects.cc ('K') | « test/cctest/cctest.gyp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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));
+ }
+ }
+}
« src/objects.cc ('K') | « test/cctest/cctest.gyp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698