// Copyright 2017 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 #include #include #include "src/objects-inl.h" #include "src/objects.h" #include "src/v8.h" #include "test/cctest/cctest.h" namespace v8 { namespace internal { int AddToSetAndGetHash(Isolate* isolate, Handle obj, bool has_fast_properties) { CHECK_EQ(has_fast_properties, obj->HasFastProperties()); CHECK_EQ(ReadOnlyRoots(isolate).undefined_value(), obj->GetHash()); Handle set = isolate->factory()->NewOrderedHashSet(); OrderedHashSet::Add(isolate, set, obj); CHECK_EQ(has_fast_properties, obj->HasFastProperties()); return Smi::ToInt(obj->GetHash()); } void CheckFastObject(Handle obj, int hash) { CHECK(obj->HasFastProperties()); CHECK(obj->raw_properties_or_hash()->IsPropertyArray()); CHECK_EQ(Smi::FromInt(hash), obj->GetHash()); CHECK_EQ(hash, obj->property_array()->Hash()); } void CheckDictionaryObject(Handle obj, int hash) { CHECK(!obj->HasFastProperties()); CHECK(obj->raw_properties_or_hash()->IsDictionary()); CHECK_EQ(Smi::FromInt(hash), obj->GetHash()); CHECK_EQ(hash, obj->property_dictionary()->Hash()); } TEST(AddHashCodeToFastObjectWithoutProperties) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); Handle obj = isolate->factory()->NewJSObject(isolate->object_function()); CHECK(obj->HasFastProperties()); int hash = AddToSetAndGetHash(isolate, obj, true); CHECK_EQ(Smi::FromInt(hash), obj->raw_properties_or_hash()); } TEST(AddHashCodeToFastObjectWithInObjectProperties) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); const char* source = " var x = { a: 1};"; CompileRun(source); Handle obj = GetGlobal("x"); CHECK_EQ(ReadOnlyRoots(isolate).empty_fixed_array(), obj->raw_properties_or_hash()); int hash = AddToSetAndGetHash(isolate, obj, true); CHECK_EQ(Smi::FromInt(hash), obj->raw_properties_or_hash()); } TEST(AddHashCodeToFastObjectWithPropertiesArray) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); const char* source = " var x = {}; " " x.a = 1; x.b = 2; x.c = 3; x.d = 4; x.e = 5; "; CompileRun(source); Handle obj = GetGlobal("x"); CHECK(obj->HasFastProperties()); int hash = AddToSetAndGetHash(isolate, obj, true); CheckFastObject(obj, hash); } TEST(AddHashCodeToSlowObject) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); Handle obj = isolate->factory()->NewJSObject(isolate->object_function()); CHECK(obj->HasFastProperties()); JSObject::NormalizeProperties(obj, CLEAR_INOBJECT_PROPERTIES, 0, "cctest/test-hashcode"); CHECK(obj->raw_properties_or_hash()->IsDictionary()); int hash = AddToSetAndGetHash(isolate, obj, false); CheckDictionaryObject(obj, hash); } TEST(TransitionFastWithInObjectToFastWithPropertyArray) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); const char* source = " var x = { };" " x.a = 1; x.b = 2; x.c = 3; x.d = 4;"; CompileRun(source); Handle obj = GetGlobal("x"); CHECK(obj->HasFastProperties()); int hash = AddToSetAndGetHash(isolate, obj, true); CHECK_EQ(Smi::FromInt(hash), obj->raw_properties_or_hash()); int length = obj->property_array()->length(); CompileRun("x.e = 5;"); CHECK(obj->property_array()->length() > length); CheckFastObject(obj, hash); } TEST(TransitionFastWithPropertyArray) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); const char* source = " var x = { };" " x.a = 1; x.b = 2; x.c = 3; x.d = 4; x.e = 5; "; CompileRun(source); Handle obj = GetGlobal("x"); CHECK(obj->raw_properties_or_hash()->IsPropertyArray()); int hash = AddToSetAndGetHash(isolate, obj, true); CHECK_EQ(hash, obj->property_array()->Hash()); int length = obj->property_array()->length(); CompileRun("x.f = 2; x.g = 5; x.h = 2"); CHECK(obj->property_array()->length() > length); CheckFastObject(obj, hash); } TEST(TransitionFastWithPropertyArrayToSlow) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); const char* source = " var x = { };" " x.a = 1; x.b = 2; x.c = 3; x.d = 4; x.e = 5; "; CompileRun(source); Handle obj = GetGlobal("x"); CHECK(obj->raw_properties_or_hash()->IsPropertyArray()); int hash = AddToSetAndGetHash(isolate, obj, true); CHECK(obj->raw_properties_or_hash()->IsPropertyArray()); CHECK_EQ(hash, obj->property_array()->Hash()); JSObject::NormalizeProperties(obj, KEEP_INOBJECT_PROPERTIES, 0, "cctest/test-hashcode"); CheckDictionaryObject(obj, hash); } TEST(TransitionSlowToSlow) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); const char* source = " var x = {}; "; CompileRun(source); Handle obj = GetGlobal("x"); JSObject::NormalizeProperties(obj, CLEAR_INOBJECT_PROPERTIES, 0, "cctest/test-hashcode"); CHECK(obj->raw_properties_or_hash()->IsDictionary()); int hash = AddToSetAndGetHash(isolate, obj, false); CHECK_EQ(hash, obj->property_dictionary()->Hash()); int length = obj->property_dictionary()->length(); CompileRun("for(var i = 0; i < 10; i++) { x['f'+i] = i };"); CHECK(obj->property_dictionary()->length() > length); CheckDictionaryObject(obj, hash); } TEST(TransitionSlowToFastWithoutProperties) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); Handle obj = isolate->factory()->NewJSObject(isolate->object_function()); JSObject::NormalizeProperties(obj, CLEAR_INOBJECT_PROPERTIES, 0, "cctest/test-hashcode"); CHECK(obj->raw_properties_or_hash()->IsDictionary()); int hash = AddToSetAndGetHash(isolate, obj, false); CHECK_EQ(hash, obj->property_dictionary()->Hash()); JSObject::MigrateSlowToFast(obj, 0, "cctest/test-hashcode"); CHECK_EQ(Smi::FromInt(hash), obj->GetHash()); } TEST(TransitionSlowToFastWithPropertyArray) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); const char* source = " var x = Object.create(null); " " for(var i = 0; i < 10; i++) { x['f'+i] = i }; "; CompileRun(source); Handle obj = GetGlobal("x"); CHECK(obj->raw_properties_or_hash()->IsDictionary()); int hash = AddToSetAndGetHash(isolate, obj, false); CHECK_EQ(hash, obj->property_dictionary()->Hash()); JSObject::MigrateSlowToFast(obj, 0, "cctest/test-hashcode"); CheckFastObject(obj, hash); } } // namespace internal } // namespace v8