1 // Copyright 2014 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <stdlib.h> 6 #include <utility> 7 8 #include "src/v8.h" 9 10 #include "src/compilation-cache.h" 11 #include "src/execution.h" 12 #include "src/factory.h" 13 #include "src/field-type.h" 14 #include "src/global-handles.h" 15 #include "test/cctest/cctest.h" 16 17 using namespace v8::internal; 18 19 20 // 21 // Helper functions. 22 // 23 24 static void CheckPropertyDetailsFieldsConsistency(PropertyType type, 25 PropertyKind kind, 26 PropertyLocation location) { 27 int type_value = PropertyDetails::TypeField::encode(type); 28 int kind_location_value = PropertyDetails::KindField::encode(kind) | 29 PropertyDetails::LocationField::encode(location); 30 CHECK_EQ(type_value, kind_location_value); 31 } 32 33 34 TEST(PropertyDetailsFieldsConsistency) { 35 CheckPropertyDetailsFieldsConsistency(DATA, kData, kField); 36 CheckPropertyDetailsFieldsConsistency(DATA_CONSTANT, kData, kDescriptor); 37 CheckPropertyDetailsFieldsConsistency(ACCESSOR, kAccessor, kField); 38 CheckPropertyDetailsFieldsConsistency(ACCESSOR_CONSTANT, kAccessor, 39 kDescriptor); 40 } 41 42 43 TEST(TransitionArray_SimpleFieldTransitions) { 44 CcTest::InitializeVM(); 45 v8::HandleScope scope(CcTest::isolate()); 46 Isolate* isolate = CcTest::i_isolate(); 47 Factory* factory = isolate->factory(); 48 49 Handle<String> name1 = factory->InternalizeUtf8String("foo"); 50 Handle<String> name2 = factory->InternalizeUtf8String("bar"); 51 PropertyAttributes attributes = NONE; 52 53 Handle<Map> map0 = Map::Create(isolate, 0); 54 Handle<Map> map1 = 55 Map::CopyWithField(map0, name1, handle(FieldType::Any(), isolate), 56 attributes, Representation::Tagged(), OMIT_TRANSITION) 57 .ToHandleChecked(); 58 Handle<Map> map2 = 59 Map::CopyWithField(map0, name2, handle(FieldType::Any(), isolate), 60 attributes, Representation::Tagged(), OMIT_TRANSITION) 61 .ToHandleChecked(); 62 63 CHECK(map0->raw_transitions()->IsSmi()); 64 65 TransitionArray::Insert(map0, name1, map1, SIMPLE_PROPERTY_TRANSITION); 66 CHECK(TransitionArray::IsSimpleTransition(map0->raw_transitions())); 67 CHECK_EQ(*map1, 68 TransitionArray::SearchTransition(*map0, kData, *name1, attributes)); 69 CHECK_EQ(1, TransitionArray::NumberOfTransitions(map0->raw_transitions())); 70 CHECK_EQ(*name1, TransitionArray::GetKey(map0->raw_transitions(), 0)); 71 CHECK_EQ(*map1, TransitionArray::GetTarget(map0->raw_transitions(), 0)); 72 73 TransitionArray::Insert(map0, name2, map2, SIMPLE_PROPERTY_TRANSITION); 74 CHECK(TransitionArray::IsFullTransitionArray(map0->raw_transitions())); 75 76 CHECK_EQ(*map1, 77 TransitionArray::SearchTransition(*map0, kData, *name1, attributes)); 78 CHECK_EQ(*map2, 79 TransitionArray::SearchTransition(*map0, kData, *name2, attributes)); 80 CHECK_EQ(2, TransitionArray::NumberOfTransitions(map0->raw_transitions())); 81 for (int i = 0; i < 2; i++) { 82 Name* key = TransitionArray::GetKey(map0->raw_transitions(), i); 83 Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i); 84 CHECK((key == *name1 && target == *map1) || 85 (key == *name2 && target == *map2)); 86 } 87 88 #ifdef DEBUG 89 CHECK(TransitionArray::IsSortedNoDuplicates(*map0)); 90 #endif 91 } 92 93 94 TEST(TransitionArray_FullFieldTransitions) { 95 CcTest::InitializeVM(); 96 v8::HandleScope scope(CcTest::isolate()); 97 Isolate* isolate = CcTest::i_isolate(); 98 Factory* factory = isolate->factory(); 99 100 Handle<String> name1 = factory->InternalizeUtf8String("foo"); 101 Handle<String> name2 = factory->InternalizeUtf8String("bar"); 102 PropertyAttributes attributes = NONE; 103 104 Handle<Map> map0 = Map::Create(isolate, 0); 105 Handle<Map> map1 = 106 Map::CopyWithField(map0, name1, handle(FieldType::Any(), isolate), 107 attributes, Representation::Tagged(), OMIT_TRANSITION) 108 .ToHandleChecked(); 109 Handle<Map> map2 = 110 Map::CopyWithField(map0, name2, handle(FieldType::Any(), isolate), 111 attributes, Representation::Tagged(), OMIT_TRANSITION) 112 .ToHandleChecked(); 113 114 CHECK(map0->raw_transitions()->IsSmi()); 115 116 TransitionArray::Insert(map0, name1, map1, PROPERTY_TRANSITION); 117 CHECK(TransitionArray::IsFullTransitionArray(map0->raw_transitions())); 118 CHECK_EQ(*map1, 119 TransitionArray::SearchTransition(*map0, kData, *name1, attributes)); 120 CHECK_EQ(1, TransitionArray::NumberOfTransitions(map0->raw_transitions())); 121 CHECK_EQ(*name1, TransitionArray::GetKey(map0->raw_transitions(), 0)); 122 CHECK_EQ(*map1, TransitionArray::GetTarget(map0->raw_transitions(), 0)); 123 124 TransitionArray::Insert(map0, name2, map2, PROPERTY_TRANSITION); 125 CHECK(TransitionArray::IsFullTransitionArray(map0->raw_transitions())); 126 127 CHECK_EQ(*map1, 128 TransitionArray::SearchTransition(*map0, kData, *name1, attributes)); 129 CHECK_EQ(*map2, 130 TransitionArray::SearchTransition(*map0, kData, *name2, attributes)); 131 CHECK_EQ(2, TransitionArray::NumberOfTransitions(map0->raw_transitions())); 132 for (int i = 0; i < 2; i++) { 133 Name* key = TransitionArray::GetKey(map0->raw_transitions(), i); 134 Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i); 135 CHECK((key == *name1 && target == *map1) || 136 (key == *name2 && target == *map2)); 137 } 138 139 #ifdef DEBUG 140 CHECK(TransitionArray::IsSortedNoDuplicates(*map0)); 141 #endif 142 } 143 144 145 TEST(TransitionArray_DifferentFieldNames) { 146 CcTest::InitializeVM(); 147 v8::HandleScope scope(CcTest::isolate()); 148 Isolate* isolate = CcTest::i_isolate(); 149 Factory* factory = isolate->factory(); 150 151 const int PROPS_COUNT = 10; 152 Handle<String> names[PROPS_COUNT]; 153 Handle<Map> maps[PROPS_COUNT]; 154 PropertyAttributes attributes = NONE; 155 156 Handle<Map> map0 = Map::Create(isolate, 0); 157 CHECK(map0->raw_transitions()->IsSmi()); 158 159 for (int i = 0; i < PROPS_COUNT; i++) { 160 EmbeddedVector<char, 64> buffer; 161 SNPrintF(buffer, "prop%d", i); 162 Handle<String> name = factory->InternalizeUtf8String(buffer.start()); 163 Handle<Map> map = Map::CopyWithField( 164 map0, name, handle(FieldType::Any(), isolate), 165 attributes, Representation::Tagged(), OMIT_TRANSITION) 166 .ToHandleChecked(); 167 names[i] = name; 168 maps[i] = map; 169 170 TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION); 171 } 172 173 for (int i = 0; i < PROPS_COUNT; i++) { 174 CHECK_EQ(*maps[i], TransitionArray::SearchTransition( 175 *map0, kData, *names[i], attributes)); 176 } 177 for (int i = 0; i < PROPS_COUNT; i++) { 178 Name* key = TransitionArray::GetKey(map0->raw_transitions(), i); 179 Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i); 180 for (int j = 0; j < PROPS_COUNT; j++) { 181 if (*names[i] == key) { 182 CHECK_EQ(*maps[i], target); 183 break; 184 } 185 } 186 } 187 188 #ifdef DEBUG 189 CHECK(TransitionArray::IsSortedNoDuplicates(*map0)); 190 #endif 191 } 192 193 194 TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) { 195 CcTest::InitializeVM(); 196 v8::HandleScope scope(CcTest::isolate()); 197 Isolate* isolate = CcTest::i_isolate(); 198 Factory* factory = isolate->factory(); 199 200 Handle<Map> map0 = Map::Create(isolate, 0); 201 CHECK(map0->raw_transitions()->IsSmi()); 202 203 const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1; 204 STATIC_ASSERT(ATTRS_COUNT == 8); 205 Handle<Map> attr_maps[ATTRS_COUNT]; 206 Handle<String> name = factory->InternalizeUtf8String("foo"); 207 208 // Add transitions for same field name but different attributes. 209 for (int i = 0; i < ATTRS_COUNT; i++) { 210 PropertyAttributes attributes = static_cast<PropertyAttributes>(i); 211 212 Handle<Map> map = Map::CopyWithField( 213 map0, name, handle(FieldType::Any(), isolate), 214 attributes, Representation::Tagged(), OMIT_TRANSITION) 215 .ToHandleChecked(); 216 attr_maps[i] = map; 217 218 TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION); 219 } 220 221 // Ensure that transitions for |name| field are valid. 222 for (int i = 0; i < ATTRS_COUNT; i++) { 223 PropertyAttributes attributes = static_cast<PropertyAttributes>(i); 224 CHECK_EQ(*attr_maps[i], TransitionArray::SearchTransition( 225 *map0, kData, *name, attributes)); 226 // All transitions use the same key, so this check doesn't need to 227 // care about ordering. 228 CHECK_EQ(*name, TransitionArray::GetKey(map0->raw_transitions(), i)); 229 } 230 231 #ifdef DEBUG 232 CHECK(TransitionArray::IsSortedNoDuplicates(*map0)); 233 #endif 234 } 235 236 237 TEST(TransitionArray_SameFieldNamesDifferentAttributes) { 238 CcTest::InitializeVM(); 239 v8::HandleScope scope(CcTest::isolate()); 240 Isolate* isolate = CcTest::i_isolate(); 241 Factory* factory = isolate->factory(); 242 243 const int PROPS_COUNT = 10; 244 Handle<String> names[PROPS_COUNT]; 245 Handle<Map> maps[PROPS_COUNT]; 246 247 Handle<Map> map0 = Map::Create(isolate, 0); 248 CHECK(map0->raw_transitions()->IsSmi()); 249 250 // Some number of fields. 251 for (int i = 0; i < PROPS_COUNT; i++) { 252 EmbeddedVector<char, 64> buffer; 253 SNPrintF(buffer, "prop%d", i); 254 Handle<String> name = factory->InternalizeUtf8String(buffer.start()); 255 Handle<Map> map = 256 Map::CopyWithField(map0, name, handle(FieldType::Any(), isolate), NONE, 257 Representation::Tagged(), OMIT_TRANSITION) 258 .ToHandleChecked(); 259 names[i] = name; 260 maps[i] = map; 261 262 TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION); 263 } 264 265 const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1; 266 STATIC_ASSERT(ATTRS_COUNT == 8); 267 Handle<Map> attr_maps[ATTRS_COUNT]; 268 Handle<String> name = factory->InternalizeUtf8String("foo"); 269 270 // Add transitions for same field name but different attributes. 271 for (int i = 0; i < ATTRS_COUNT; i++) { 272 PropertyAttributes attributes = static_cast<PropertyAttributes>(i); 273 274 Handle<Map> map = Map::CopyWithField( 275 map0, name, handle(FieldType::Any(), isolate), 276 attributes, Representation::Tagged(), OMIT_TRANSITION) 277 .ToHandleChecked(); 278 attr_maps[i] = map; 279 280 TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION); 281 } 282 283 // Ensure that transitions for |name| field are valid. 284 for (int i = 0; i < ATTRS_COUNT; i++) { 285 PropertyAttributes attr = static_cast<PropertyAttributes>(i); 286 CHECK_EQ(*attr_maps[i], 287 TransitionArray::SearchTransition(*map0, kData, *name, attr)); 288 } 289 290 // Ensure that info about the other fields still valid. 291 CHECK_EQ(PROPS_COUNT + ATTRS_COUNT, 292 TransitionArray::NumberOfTransitions(map0->raw_transitions())); 293 for (int i = 0; i < PROPS_COUNT + ATTRS_COUNT; i++) { 294 Name* key = TransitionArray::GetKey(map0->raw_transitions(), i); 295 Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i); 296 if (key == *name) { 297 // Attributes transition. 298 PropertyAttributes attributes = 299 target->GetLastDescriptorDetails().attributes(); 300 CHECK_EQ(*attr_maps[static_cast<int>(attributes)], target); 301 } else { 302 for (int j = 0; j < PROPS_COUNT; j++) { 303 if (*names[j] == key) { 304 CHECK_EQ(*maps[j], target); 305 break; 306 } 307 } 308 } 309 } 310 311 #ifdef DEBUG 312 CHECK(TransitionArray::IsSortedNoDuplicates(*map0)); 313 #endif 314 } 315