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

Unified Diff: test/cctest/test-elements-kind.cc

Issue 1368403003: [cctest] adding tests for elements kind map migrations (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: adding file to gyp Created 5 years, 3 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
« no previous file with comments | « test/cctest/cctest.gyp ('k') | test/cctest/test-field-type-tracking.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/cctest/test-elements-kind.cc
diff --git a/test/cctest/test-elements-kind.cc b/test/cctest/test-elements-kind.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f5630ab54e6321ae90457d5a919844872e990898
--- /dev/null
+++ b/test/cctest/test-elements-kind.cc
@@ -0,0 +1,475 @@
+// 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 "test/cctest/test-api.h"
+
+#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/objects.h"
+
+using namespace v8::internal;
+
+
+//
+// Helper functions.
+//
+
+namespace {
+
+Handle<String> MakeString(const char* str) {
+ Isolate* isolate = CcTest::i_isolate();
+ Factory* factory = isolate->factory();
+ return factory->InternalizeUtf8String(str);
+}
+
+
+Handle<String> MakeName(const char* str, int suffix) {
+ EmbeddedVector<char, 128> buffer;
+ SNPrintF(buffer, "%s%d", str, suffix);
+ return MakeString(buffer.start());
+}
+
+
+template <typename T, typename M>
+bool EQUALS(Handle<T> left, Handle<M> right) {
+ if (*left == *right) return true;
+ return JSObject::Equals(Handle<Object>::cast(left),
+ Handle<Object>::cast(right))
+ .FromJust();
+}
+
+
+template <typename T, typename M>
+bool EQUALS(Handle<T> left, M right) {
+ return EQUALS(left, handle(right));
+}
+
+
+template <typename T, typename M>
+bool EQUALS(T left, Handle<M> right) {
+ return EQUALS(handle(left), right);
+}
+
+} // namespace
+
+
+//
+// Tests
+//
+
+TEST(JSObjectAddingProperties) {
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ Factory* factory = isolate->factory();
+ v8::HandleScope scope(CcTest::isolate());
+
+ Handle<FixedArray> empty_fixed_array(factory->empty_fixed_array());
+ Handle<JSFunction> function = factory->NewFunction(factory->empty_string());
+ Handle<Object> value(Smi::FromInt(42), isolate);
+
+ Handle<JSObject> object = factory->NewJSObject(function);
+ Handle<Map> previous_map(object->map());
+ CHECK_EQ(previous_map->elements_kind(), FAST_HOLEY_ELEMENTS);
+ CHECK(EQUALS(object->properties(), empty_fixed_array));
+ CHECK(EQUALS(object->elements(), empty_fixed_array));
+
+ // for the default constructor function no in-object properties are reserved
+ // hence adding a single property will initialize the property-array
+ Handle<String> name = MakeName("property", 0);
+ JSObject::DefinePropertyOrElementIgnoreAttributes(object, name, value, NONE)
+ .Check();
+ CHECK_NE(object->map(), *previous_map);
+ CHECK_EQ(object->map()->elements_kind(), FAST_HOLEY_ELEMENTS);
+ CHECK_LE(1, object->properties()->length());
+ CHECK(EQUALS(object->elements(), empty_fixed_array));
+}
+
+
+TEST(JSObjectInObjectAddingProperties) {
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ Factory* factory = isolate->factory();
+ v8::HandleScope scope(CcTest::isolate());
+
+ Handle<FixedArray> empty_fixed_array(factory->empty_fixed_array());
+ Handle<JSFunction> function = factory->NewFunction(factory->empty_string());
+ int nof_inobject_properties = 10;
+ // force in object properties by changing the expected_nof_properties
+ function->shared()->set_expected_nof_properties(nof_inobject_properties);
+ Handle<Object> value(Smi::FromInt(42), isolate);
+
+ Handle<JSObject> object = factory->NewJSObject(function);
+ Handle<Map> previous_map(object->map());
+ CHECK_EQ(previous_map->elements_kind(), FAST_HOLEY_ELEMENTS);
+ CHECK(EQUALS(object->properties(), empty_fixed_array));
+ CHECK(EQUALS(object->elements(), empty_fixed_array));
+
+ // we have reserved space for in-object properties, hence adding up to
+ // |nof_inobject_properties| will not create a property store
+ for (int i = 0; i < nof_inobject_properties; i++) {
+ Handle<String> name = MakeName("property", i);
+ JSObject::DefinePropertyOrElementIgnoreAttributes(object, name, value, NONE)
+ .Check();
+ }
+ CHECK_NE(object->map(), *previous_map);
+ CHECK_EQ(object->map()->elements_kind(), FAST_HOLEY_ELEMENTS);
+ CHECK(EQUALS(object->properties(), empty_fixed_array));
+ CHECK(EQUALS(object->elements(), empty_fixed_array));
+
+ // adding one more property will not fit in the in-object properties, thus
+ // creating a property store
+ int index = nof_inobject_properties + 1;
+ Handle<String> name = MakeName("property", index);
+ JSObject::DefinePropertyOrElementIgnoreAttributes(object, name, value, NONE)
+ .Check();
+ CHECK_NE(object->map(), *previous_map);
+ CHECK_EQ(object->map()->elements_kind(), FAST_HOLEY_ELEMENTS);
+ // there must be at least 1 element in the properies store
+ CHECK_LE(1, object->properties()->length());
+ CHECK(EQUALS(object->elements(), empty_fixed_array));
+}
+
+
+TEST(JSObjectAddingElements) {
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ Factory* factory = isolate->factory();
+ v8::HandleScope scope(CcTest::isolate());
+
+ Handle<String> name;
+ Handle<FixedArray> empty_fixed_array(factory->empty_fixed_array());
+ Handle<JSFunction> function = factory->NewFunction(factory->empty_string());
+ Handle<Object> value(Smi::FromInt(42), isolate);
+
+ Handle<JSObject> object = factory->NewJSObject(function);
+ Handle<Map> previous_map(object->map());
+ CHECK_EQ(previous_map->elements_kind(), FAST_HOLEY_ELEMENTS);
+ CHECK(EQUALS(object->properties(), empty_fixed_array));
+ CHECK(EQUALS(object->elements(), empty_fixed_array));
+
+ // Adding an indexed element initializes the elements array
+ name = MakeString("0");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(object, name, value, NONE)
+ .Check();
+ // no change in elements_kind => no map transition
+ CHECK_EQ(object->map(), *previous_map);
+ CHECK_EQ(object->map()->elements_kind(), FAST_HOLEY_ELEMENTS);
+ CHECK(EQUALS(object->properties(), empty_fixed_array));
+ CHECK_LE(1, object->elements()->length());
+
+ // Adding more consecutive elements without a change in the backing store
+ int non_dict_backing_store_limit = 100;
+ for (int i = 1; i < non_dict_backing_store_limit; i++) {
+ name = MakeName("", i);
+ JSObject::DefinePropertyOrElementIgnoreAttributes(object, name, value, NONE)
+ .Check();
+ }
+ // no change in elements_kind => no map transition
+ CHECK_EQ(object->map(), *previous_map);
+ CHECK_EQ(object->map()->elements_kind(), FAST_HOLEY_ELEMENTS);
+ CHECK(EQUALS(object->properties(), empty_fixed_array));
+ CHECK_LE(non_dict_backing_store_limit, object->elements()->length());
+
+ // Adding an element at an very large index causes a change to
+ // DICTIONARY_ELEMENTS
+ name = MakeString("100000000");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(object, name, value, NONE)
+ .Check();
+ // change in elements_kind => map transition
+ CHECK_NE(object->map(), *previous_map);
+ CHECK_EQ(object->map()->elements_kind(), DICTIONARY_ELEMENTS);
+ CHECK(EQUALS(object->properties(), empty_fixed_array));
+ CHECK_LE(non_dict_backing_store_limit, object->elements()->length());
+}
+
+
+TEST(JSArrayAddingProperties) {
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ Factory* factory = isolate->factory();
+ v8::HandleScope scope(CcTest::isolate());
+
+ Handle<FixedArray> empty_fixed_array(factory->empty_fixed_array());
+ Handle<Object> value(Smi::FromInt(42), isolate);
+
+ Handle<JSArray> array =
+ factory->NewJSArray(ElementsKind::FAST_SMI_ELEMENTS, 0, 0);
+ Handle<Map> previous_map(array->map());
+ CHECK_EQ(previous_map->elements_kind(), FAST_SMI_ELEMENTS);
+ CHECK(EQUALS(array->properties(), empty_fixed_array));
+ CHECK(EQUALS(array->elements(), empty_fixed_array));
+ CHECK_EQ(Smi::cast(array->length())->value(), 0);
+
+ // for the default constructor function no in-object properties are reserved
+ // hence adding a single property will initialize the property-array
+ Handle<String> name = MakeName("property", 0);
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value, NONE)
+ .Check();
+ // No change in elements_kind but added property => new map
+ CHECK_NE(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), FAST_SMI_ELEMENTS);
+ CHECK_LE(1, array->properties()->length());
+ CHECK(EQUALS(array->elements(), empty_fixed_array));
+ CHECK_EQ(Smi::cast(array->length())->value(), 0);
+}
+
+
+TEST(JSArrayAddingElements) {
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ Factory* factory = isolate->factory();
+ v8::HandleScope scope(CcTest::isolate());
+
+ Handle<String> name;
+ Handle<FixedArray> empty_fixed_array(factory->empty_fixed_array());
+ Handle<Object> value(Smi::FromInt(42), isolate);
+
+ Handle<JSArray> array =
+ factory->NewJSArray(ElementsKind::FAST_SMI_ELEMENTS, 0, 0);
+ Handle<Map> previous_map(array->map());
+ CHECK_EQ(previous_map->elements_kind(), FAST_SMI_ELEMENTS);
+ CHECK(EQUALS(array->properties(), empty_fixed_array));
+ CHECK(EQUALS(array->elements(), empty_fixed_array));
+ CHECK_EQ(Smi::cast(array->length())->value(), 0);
+
+ // Adding an indexed element initializes the elements array
+ name = MakeString("0");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value, NONE)
+ .Check();
+ // no change in elements_kind => no map transition
+ CHECK_EQ(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), FAST_SMI_ELEMENTS);
+ CHECK(EQUALS(array->properties(), empty_fixed_array));
+ CHECK_LE(1, array->elements()->length());
+ CHECK_EQ(1, Smi::cast(array->length())->value());
+
+ // Adding more consecutive elements without a change in the backing store
+ int non_dict_backing_store_limit = 100;
+ for (int i = 1; i < non_dict_backing_store_limit; i++) {
+ name = MakeName("", i);
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value, NONE)
+ .Check();
+ }
+ // no change in elements_kind => no map transition
+ CHECK_EQ(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), FAST_SMI_ELEMENTS);
+ CHECK(EQUALS(array->properties(), empty_fixed_array));
+ CHECK_LE(non_dict_backing_store_limit, array->elements()->length());
+ CHECK_EQ(non_dict_backing_store_limit, Smi::cast(array->length())->value());
+
+ // Adding an element at an very large index causes a change to
+ // DICTIONARY_ELEMENTS
+ int index = 100000000;
+ name = MakeName("", index);
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value, NONE)
+ .Check();
+ // change in elements_kind => map transition
+ CHECK_NE(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), DICTIONARY_ELEMENTS);
+ CHECK(EQUALS(array->properties(), empty_fixed_array));
+ CHECK_LE(non_dict_backing_store_limit, array->elements()->length());
+ CHECK_LE(array->elements()->length(), index);
+ CHECK_EQ(index + 1, Smi::cast(array->length())->value());
+}
+
+
+TEST(JSArrayAddingElementsGeneralizingiFastSmiElements) {
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ Factory* factory = isolate->factory();
+ v8::HandleScope scope(CcTest::isolate());
+
+ Handle<String> name;
+ Handle<Object> value_smi(Smi::FromInt(42), isolate);
+ Handle<Object> value_string(MakeString("value"));
+ Handle<Object> value_double = factory->NewNumber(3.1415);
+
+ Handle<JSArray> array =
+ factory->NewJSArray(ElementsKind::FAST_SMI_ELEMENTS, 0, 0);
+ Handle<Map> previous_map(array->map());
+ CHECK_EQ(previous_map->elements_kind(), FAST_SMI_ELEMENTS);
+ CHECK_EQ(Smi::cast(array->length())->value(), 0);
+
+ // `array[0] = smi_value` doesn't change the elements_kind
+ name = MakeString("0");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value_smi,
+ NONE)
+ .Check();
+ // no change in elements_kind => no map transition
+ CHECK_EQ(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), FAST_SMI_ELEMENTS);
+ CHECK_EQ(1, Smi::cast(array->length())->value());
+
+ // `delete array[0]` does not alter length, but changes the elments_kind
+ name = MakeString("0");
+ JSReceiver::DeletePropertyOrElement(array, name).Check();
+ CHECK_NE(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), FAST_HOLEY_SMI_ELEMENTS);
+ CHECK_EQ(1, Smi::cast(array->length())->value());
+ previous_map = handle(array->map());
+
+ // add a couple of elements again
+ name = MakeString("0");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value_smi,
+ NONE)
+ .Check();
+ name = MakeString("1");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value_smi,
+ NONE)
+ .Check();
+ CHECK_EQ(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), FAST_HOLEY_SMI_ELEMENTS);
+ CHECK_EQ(2, Smi::cast(array->length())->value());
+
+ // Adding a string to the array changes from FAST_HOLEY_SMI to FAST_HOLEY
+ name = MakeString("0");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value_string,
+ NONE)
+ .Check();
+ CHECK_NE(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), FAST_HOLEY_ELEMENTS);
+ CHECK_EQ(2, Smi::cast(array->length())->value());
+ previous_map = handle(array->map());
+
+ // We don't transition back to FAST_SMI even if we remove the string
+ name = MakeString("0");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value_smi,
+ NONE)
+ .Check();
+ CHECK_EQ(array->map(), *previous_map);
+
+ // Adding a double doesn't change the map either
+ name = MakeString("0");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value_double,
+ NONE)
+ .Check();
+ CHECK_EQ(array->map(), *previous_map);
+}
+
+
+TEST(JSArrayAddingElementsGeneralizingFastElements) {
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ Factory* factory = isolate->factory();
+ v8::HandleScope scope(CcTest::isolate());
+
+ Handle<String> name;
+ Handle<Object> value_smi(Smi::FromInt(42), isolate);
+ Handle<Object> value_string(MakeString("value"));
+
+ Handle<JSArray> array =
+ factory->NewJSArray(ElementsKind::FAST_ELEMENTS, 0, 0);
+ Handle<Map> previous_map(array->map());
+ CHECK_EQ(previous_map->elements_kind(), FAST_ELEMENTS);
+ CHECK_EQ(Smi::cast(array->length())->value(), 0);
+
+ // `array[0] = smi_value` doesn't change the elements_kind
+ name = MakeString("0");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value_smi,
+ NONE)
+ .Check();
+ // no change in elements_kind => no map transition
+ CHECK_EQ(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), FAST_ELEMENTS);
+ CHECK_EQ(1, Smi::cast(array->length())->value());
+
+ // `delete array[0]` does not alter length, but changes the elments_kind
+ name = MakeString("0");
+ JSReceiver::DeletePropertyOrElement(array, name).Check();
+ CHECK_NE(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), FAST_HOLEY_ELEMENTS);
+ CHECK_EQ(1, Smi::cast(array->length())->value());
+ previous_map = handle(array->map());
+
+ // add a couple of elements, elements_kind stays HOLEY
+ name = MakeString("0");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value_string,
+ NONE)
+ .Check();
+ name = MakeString("1");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value_smi,
+ NONE)
+ .Check();
+ CHECK_EQ(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), FAST_HOLEY_ELEMENTS);
+ CHECK_EQ(2, Smi::cast(array->length())->value());
+}
+
+
+TEST(JSArrayAddingElementsGeneralizingiFastDoubleElements) {
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ Factory* factory = isolate->factory();
+ v8::HandleScope scope(CcTest::isolate());
+
+ Handle<String> name;
+ Handle<Object> value_smi(Smi::FromInt(42), isolate);
+ Handle<Object> value_string(MakeString("value"));
+ Handle<Object> value_double = factory->NewNumber(3.1415);
+
+ Handle<JSArray> array =
+ factory->NewJSArray(ElementsKind::FAST_SMI_ELEMENTS, 0, 0);
+ Handle<Map> previous_map(array->map());
+
+ // `array[0] = value_double` changes |elements_kind| to FAST_DOUBLE_ELEMENTS
+ name = MakeString("0");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value_double,
+ NONE)
+ .Check();
+ CHECK_NE(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), FAST_DOUBLE_ELEMENTS);
+ CHECK_EQ(1, Smi::cast(array->length())->value());
+ previous_map = handle(array->map());
+
+ // `array[1] = value_smi` doesn't alter the |elements_kind|
+ name = MakeString("1");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value_smi,
+ NONE)
+ .Check();
+ CHECK_EQ(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), FAST_DOUBLE_ELEMENTS);
+ CHECK_EQ(2, Smi::cast(array->length())->value());
+
+ // `delete array[0]` does not alter length, but changes the elments_kind
+ name = MakeString("0");
+ JSReceiver::DeletePropertyOrElement(array, name).Check();
+ CHECK_NE(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), FAST_HOLEY_DOUBLE_ELEMENTS);
+ CHECK_EQ(2, Smi::cast(array->length())->value());
+ previous_map = handle(array->map());
+
+ // filling the hole `array[0] = value_smi` again doesn't transition back
+ name = MakeString("0");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value_double,
+ NONE)
+ .Check();
+ CHECK_EQ(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), FAST_HOLEY_DOUBLE_ELEMENTS);
+ CHECK_EQ(2, Smi::cast(array->length())->value());
+
+ // Adding a string to the array changes to elements_kind FAST_ELEMENTS
+ name = MakeString("1");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value_string,
+ NONE)
+ .Check();
+ CHECK_NE(array->map(), *previous_map);
+ CHECK_EQ(array->map()->elements_kind(), FAST_HOLEY_ELEMENTS);
+ CHECK_EQ(2, Smi::cast(array->length())->value());
+ previous_map = handle(array->map());
+
+ // Adding a double doesn't change the map
+ name = MakeString("0");
+ JSObject::DefinePropertyOrElementIgnoreAttributes(array, name, value_double,
+ NONE)
+ .Check();
+ CHECK_EQ(array->map(), *previous_map);
+}
« no previous file with comments | « test/cctest/cctest.gyp ('k') | test/cctest/test-field-type-tracking.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698