| // Copyright 2016 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 <cmath> |
| #include <iostream> |
| #include <limits> |
| |
| #include "src/api-inl.h" |
| #include "src/compiler.h" |
| #include "src/objects-inl.h" |
| #include "src/objects.h" |
| #include "src/objects/hash-table-inl.h" |
| #include "test/unittests/test-utils.h" |
| |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| namespace { |
| |
| bool IsInStringInstanceTypeList(InstanceType instance_type) { |
| switch (instance_type) { |
| #define ASSERT_INSTANCE_TYPE(type, ...) \ |
| STATIC_ASSERT(InstanceType::type < InstanceType::FIRST_NONSTRING_TYPE); |
| STRING_TYPE_LIST(ASSERT_INSTANCE_TYPE) |
| #undef ASSERT_INSTANCE_TYPE |
| #define TEST_INSTANCE_TYPE(type, ...) case InstanceType::type: |
| STRING_TYPE_LIST(TEST_INSTANCE_TYPE) |
| #undef TEST_INSTANCE_TYPE |
| return true; |
| default: |
| EXPECT_LE(InstanceType::FIRST_NONSTRING_TYPE, instance_type); |
| return false; |
| } |
| } |
| |
| void CheckOneInstanceType(InstanceType instance_type) { |
| if (IsInStringInstanceTypeList(instance_type)) { |
| EXPECT_TRUE((instance_type & kIsNotStringMask) == kStringTag) |
| << "Failing IsString mask check for " << instance_type; |
| } else { |
| EXPECT_FALSE((instance_type & kIsNotStringMask) == kStringTag) |
| << "Failing !IsString mask check for " << instance_type; |
| } |
| } |
| |
| } // namespace |
| |
| TEST(Object, InstanceTypeList) { |
| #define TEST_INSTANCE_TYPE(type) CheckOneInstanceType(InstanceType::type); |
| |
| INSTANCE_TYPE_LIST(TEST_INSTANCE_TYPE) |
| #undef TEST_INSTANCE_TYPE |
| } |
| |
| TEST(Object, InstanceTypeListOrder) { |
| int current = 0; |
| int last = -1; |
| InstanceType current_type = static_cast<InstanceType>(current); |
| EXPECT_EQ(current_type, InstanceType::FIRST_TYPE); |
| EXPECT_EQ(current_type, InstanceType::INTERNALIZED_STRING_TYPE); |
| #define TEST_INSTANCE_TYPE(type) \ |
| current_type = InstanceType::type; \ |
| current = static_cast<int>(current_type); \ |
| if (current > static_cast<int>(LAST_NAME_TYPE)) { \ |
| EXPECT_LE(last + 1, current); \ |
| } \ |
| EXPECT_LT(last, current) << " INSTANCE_TYPE_LIST is not ordered: " \ |
| << "last = " << static_cast<InstanceType>(last) \ |
| << " vs. current = " << current_type; \ |
| last = current; |
| |
| INSTANCE_TYPE_LIST(TEST_INSTANCE_TYPE) |
| #undef TEST_INSTANCE_TYPE |
| } |
| |
| TEST(Object, StructListOrder) { |
| int current = static_cast<int>(InstanceType::ACCESS_CHECK_INFO_TYPE); |
| int last = current - 1; |
| ASSERT_LT(0, last); |
| InstanceType current_type = static_cast<InstanceType>(current); |
| #define TEST_STRUCT(TYPE, class, name) \ |
| current_type = InstanceType::TYPE; \ |
| current = static_cast<int>(current_type); \ |
| EXPECT_EQ(last + 1, current) \ |
| << " STRUCT_LIST is not ordered: " \ |
| << " last = " << static_cast<InstanceType>(last) \ |
| << " vs. current = " << current_type; \ |
| last = current; |
| |
| STRUCT_LIST(TEST_STRUCT) |
| #undef TEST_STRUCT |
| } |
| |
| typedef TestWithIsolate ObjectWithIsolate; |
| |
| TEST_F(ObjectWithIsolate, DictionaryGrowth) { |
| Handle<NumberDictionary> dict = NumberDictionary::New(isolate(), 1); |
| Handle<Object> value = isolate()->factory()->null_value(); |
| PropertyDetails details = PropertyDetails::Empty(); |
| |
| // This test documents the expected growth behavior of a dictionary getting |
| // elements added to it one by one. |
| STATIC_ASSERT(HashTableBase::kMinCapacity == 4); |
| uint32_t i = 1; |
| // 3 elements fit into the initial capacity. |
| for (; i <= 3; i++) { |
| dict = NumberDictionary::Add(isolate(), dict, i, value, details); |
| CHECK_EQ(4, dict->Capacity()); |
| } |
| // 4th element triggers growth. |
| DCHECK_EQ(4, i); |
| for (; i <= 5; i++) { |
| dict = NumberDictionary::Add(isolate(), dict, i, value, details); |
| CHECK_EQ(8, dict->Capacity()); |
| } |
| // 6th element triggers growth. |
| DCHECK_EQ(6, i); |
| for (; i <= 11; i++) { |
| dict = NumberDictionary::Add(isolate(), dict, i, value, details); |
| CHECK_EQ(16, dict->Capacity()); |
| } |
| // 12th element triggers growth. |
| DCHECK_EQ(12, i); |
| for (; i <= 21; i++) { |
| dict = NumberDictionary::Add(isolate(), dict, i, value, details); |
| CHECK_EQ(32, dict->Capacity()); |
| } |
| // 22nd element triggers growth. |
| DCHECK_EQ(22, i); |
| for (; i <= 43; i++) { |
| dict = NumberDictionary::Add(isolate(), dict, i, value, details); |
| CHECK_EQ(64, dict->Capacity()); |
| } |
| // 44th element triggers growth. |
| DCHECK_EQ(44, i); |
| for (; i <= 50; i++) { |
| dict = NumberDictionary::Add(isolate(), dict, i, value, details); |
| CHECK_EQ(128, dict->Capacity()); |
| } |
| |
| // If we grow by larger chunks, the next (sufficiently big) power of 2 is |
| // chosen as the capacity. |
| dict = NumberDictionary::New(isolate(), 1); |
| dict = NumberDictionary::EnsureCapacity(isolate(), dict, 65); |
| CHECK_EQ(128, dict->Capacity()); |
| |
| dict = NumberDictionary::New(isolate(), 1); |
| dict = NumberDictionary::EnsureCapacity(isolate(), dict, 30); |
| CHECK_EQ(64, dict->Capacity()); |
| } |
| |
| TEST_F(TestWithNativeContext, EmptyFunctionScopeInfo) { |
| // Check that the empty_function has a properly set up ScopeInfo. |
| Handle<JSFunction> function = RunJS<JSFunction>("(function(){})"); |
| |
| Handle<ScopeInfo> scope_info(function->shared()->scope_info(), |
| function->GetIsolate()); |
| Handle<ScopeInfo> empty_function_scope_info( |
| isolate()->empty_function()->shared()->scope_info(), |
| function->GetIsolate()); |
| |
| EXPECT_EQ(scope_info->length(), empty_function_scope_info->length()); |
| EXPECT_EQ(scope_info->Flags(), empty_function_scope_info->Flags()); |
| EXPECT_EQ(scope_info->ParameterCount(), |
| empty_function_scope_info->ParameterCount()); |
| EXPECT_EQ(scope_info->ContextLocalCount(), |
| empty_function_scope_info->ContextLocalCount()); |
| } |
| |
| } // namespace internal |
| } // namespace v8 |