Home | History | Annotate | Download | only in cctest
      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