test-transitions.cc 10.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
// Copyright 2014 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 "src/v8.h"

#include "src/compilation-cache.h"
#include "src/execution.h"
12
#include "src/field-type.h"
13
#include "src/global-handles.h"
14
#include "src/heap/factory.h"
15 16
#include "src/objects-inl.h"
#include "src/transitions.h"
17
#include "test/cctest/cctest.h"
18
#include "test/cctest/test-transitions.h"
19

20 21
namespace v8 {
namespace internal {
22 23 24 25 26 27 28 29 30 31 32 33 34

TEST(TransitionArray_SimpleFieldTransitions) {
  CcTest::InitializeVM();
  v8::HandleScope scope(CcTest::isolate());
  Isolate* isolate = CcTest::i_isolate();
  Factory* factory = isolate->factory();

  Handle<String> name1 = factory->InternalizeUtf8String("foo");
  Handle<String> name2 = factory->InternalizeUtf8String("bar");
  PropertyAttributes attributes = NONE;

  Handle<Map> map0 = Map::Create(isolate, 0);
  Handle<Map> map1 =
35 36 37
      Map::CopyWithField(isolate, map0, name1, FieldType::Any(isolate),
                         attributes, PropertyConstness::kMutable,
                         Representation::Tagged(), OMIT_TRANSITION)
38
          .ToHandleChecked();
39
  Handle<Map> map2 =
40 41 42
      Map::CopyWithField(isolate, map0, name2, FieldType::Any(isolate),
                         attributes, PropertyConstness::kMutable,
                         Representation::Tagged(), OMIT_TRANSITION)
43
          .ToHandleChecked();
44

45 46
  CHECK(map0->raw_transitions()->IsSmi());

47
  {
48
    TestTransitionsAccessor transitions(isolate, map0);
49 50 51
    transitions.Insert(name1, map1, SIMPLE_PROPERTY_TRANSITION);
  }
  {
52
    TestTransitionsAccessor transitions(isolate, map0);
53
    CHECK(transitions.IsWeakRefEncoding());
54 55 56 57 58 59
    CHECK_EQ(*map1, transitions.SearchTransition(*name1, kData, attributes));
    CHECK_EQ(1, transitions.NumberOfTransitions());
    CHECK_EQ(*name1, transitions.GetKey(0));
    CHECK_EQ(*map1, transitions.GetTarget(0));

    transitions.Insert(name2, map2, SIMPLE_PROPERTY_TRANSITION);
60
  }
61
  {
62
    TestTransitionsAccessor transitions(isolate, map0);
63 64 65 66 67 68
    CHECK(transitions.IsFullTransitionArrayEncoding());

    CHECK_EQ(*map1, transitions.SearchTransition(*name1, kData, attributes));
    CHECK_EQ(*map2, transitions.SearchTransition(*name2, kData, attributes));
    CHECK_EQ(2, transitions.NumberOfTransitions());
    for (int i = 0; i < 2; i++) {
69
      Name key = transitions.GetKey(i);
70
      Map target = transitions.GetTarget(i);
71 72 73
      CHECK((key == *name1 && target == *map1) ||
            (key == *name2 && target == *map2));
    }
74

75
    DCHECK(transitions.IsSortedNoDuplicates());
76
  }
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
}


TEST(TransitionArray_FullFieldTransitions) {
  CcTest::InitializeVM();
  v8::HandleScope scope(CcTest::isolate());
  Isolate* isolate = CcTest::i_isolate();
  Factory* factory = isolate->factory();

  Handle<String> name1 = factory->InternalizeUtf8String("foo");
  Handle<String> name2 = factory->InternalizeUtf8String("bar");
  PropertyAttributes attributes = NONE;

  Handle<Map> map0 = Map::Create(isolate, 0);
  Handle<Map> map1 =
92 93 94
      Map::CopyWithField(isolate, map0, name1, FieldType::Any(isolate),
                         attributes, PropertyConstness::kMutable,
                         Representation::Tagged(), OMIT_TRANSITION)
95
          .ToHandleChecked();
96
  Handle<Map> map2 =
97 98 99
      Map::CopyWithField(isolate, map0, name2, FieldType::Any(isolate),
                         attributes, PropertyConstness::kMutable,
                         Representation::Tagged(), OMIT_TRANSITION)
100
          .ToHandleChecked();
101

102 103
  CHECK(map0->raw_transitions()->IsSmi());

104
  {
105
    TestTransitionsAccessor transitions(isolate, map0);
106
    transitions.Insert(name1, map1, PROPERTY_TRANSITION);
107
  }
108
  {
109
    TestTransitionsAccessor transitions(isolate, map0);
110 111 112 113 114 115 116 117 118
    CHECK(transitions.IsFullTransitionArrayEncoding());
    CHECK_EQ(*map1, transitions.SearchTransition(*name1, kData, attributes));
    CHECK_EQ(1, transitions.NumberOfTransitions());
    CHECK_EQ(*name1, transitions.GetKey(0));
    CHECK_EQ(*map1, transitions.GetTarget(0));

    transitions.Insert(name2, map2, PROPERTY_TRANSITION);
  }
  {
119
    TestTransitionsAccessor transitions(isolate, map0);
120 121 122 123 124 125
    CHECK(transitions.IsFullTransitionArrayEncoding());

    CHECK_EQ(*map1, transitions.SearchTransition(*name1, kData, attributes));
    CHECK_EQ(*map2, transitions.SearchTransition(*name2, kData, attributes));
    CHECK_EQ(2, transitions.NumberOfTransitions());
    for (int i = 0; i < 2; i++) {
126
      Name key = transitions.GetKey(i);
127
      Map target = transitions.GetTarget(i);
128 129 130
      CHECK((key == *name1 && target == *map1) ||
            (key == *name2 && target == *map2));
    }
131

132
    DCHECK(transitions.IsSortedNoDuplicates());
133
  }
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
}


TEST(TransitionArray_DifferentFieldNames) {
  CcTest::InitializeVM();
  v8::HandleScope scope(CcTest::isolate());
  Isolate* isolate = CcTest::i_isolate();
  Factory* factory = isolate->factory();

  const int PROPS_COUNT = 10;
  Handle<String> names[PROPS_COUNT];
  Handle<Map> maps[PROPS_COUNT];
  PropertyAttributes attributes = NONE;

  Handle<Map> map0 = Map::Create(isolate, 0);
149
  CHECK(map0->raw_transitions()->IsSmi());
150 151 152 153 154

  for (int i = 0; i < PROPS_COUNT; i++) {
    EmbeddedVector<char, 64> buffer;
    SNPrintF(buffer, "prop%d", i);
    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
155
    Handle<Map> map =
156 157
        Map::CopyWithField(isolate, map0, name, FieldType::Any(isolate),
                           attributes, PropertyConstness::kMutable,
158
                           Representation::Tagged(), OMIT_TRANSITION)
159
            .ToHandleChecked();
160 161 162
    names[i] = name;
    maps[i] = map;

163
    TransitionsAccessor(isolate, map0).Insert(name, map, PROPERTY_TRANSITION);
164 165
  }

166
  TransitionsAccessor transitions(isolate, map0);
167
  for (int i = 0; i < PROPS_COUNT; i++) {
168 169
    CHECK_EQ(*maps[i],
             transitions.SearchTransition(*names[i], kData, attributes));
170 171
  }
  for (int i = 0; i < PROPS_COUNT; i++) {
172
    Name key = transitions.GetKey(i);
173
    Map target = transitions.GetTarget(i);
174 175 176 177 178 179
    for (int j = 0; j < PROPS_COUNT; j++) {
      if (*names[i] == key) {
        CHECK_EQ(*maps[i], target);
        break;
      }
    }
180 181
  }

182
  DCHECK(transitions.IsSortedNoDuplicates());
183 184 185 186 187 188 189 190 191 192
}


TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) {
  CcTest::InitializeVM();
  v8::HandleScope scope(CcTest::isolate());
  Isolate* isolate = CcTest::i_isolate();
  Factory* factory = isolate->factory();

  Handle<Map> map0 = Map::Create(isolate, 0);
193
  CHECK(map0->raw_transitions()->IsSmi());
194 195 196 197 198 199 200 201 202 203

  const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
  STATIC_ASSERT(ATTRS_COUNT == 8);
  Handle<Map> attr_maps[ATTRS_COUNT];
  Handle<String> name = factory->InternalizeUtf8String("foo");

  // Add transitions for same field name but different attributes.
  for (int i = 0; i < ATTRS_COUNT; i++) {
    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);

204
    Handle<Map> map =
205 206
        Map::CopyWithField(isolate, map0, name, FieldType::Any(isolate),
                           attributes, PropertyConstness::kMutable,
207
                           Representation::Tagged(), OMIT_TRANSITION)
208
            .ToHandleChecked();
209 210
    attr_maps[i] = map;

211
    TransitionsAccessor(isolate, map0).Insert(name, map, PROPERTY_TRANSITION);
212 213 214
  }

  // Ensure that transitions for |name| field are valid.
215
  TransitionsAccessor transitions(isolate, map0);
216 217
  for (int i = 0; i < ATTRS_COUNT; i++) {
    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
218 219
    CHECK_EQ(*attr_maps[i],
             transitions.SearchTransition(*name, kData, attributes));
220 221
    // All transitions use the same key, so this check doesn't need to
    // care about ordering.
222
    CHECK_EQ(*name, transitions.GetKey(i));
223 224
  }

225
  DCHECK(transitions.IsSortedNoDuplicates());
226 227 228 229 230 231 232 233 234 235 236 237 238 239
}


TEST(TransitionArray_SameFieldNamesDifferentAttributes) {
  CcTest::InitializeVM();
  v8::HandleScope scope(CcTest::isolate());
  Isolate* isolate = CcTest::i_isolate();
  Factory* factory = isolate->factory();

  const int PROPS_COUNT = 10;
  Handle<String> names[PROPS_COUNT];
  Handle<Map> maps[PROPS_COUNT];

  Handle<Map> map0 = Map::Create(isolate, 0);
240
  CHECK(map0->raw_transitions()->IsSmi());
241 242 243 244 245 246 247

  // Some number of fields.
  for (int i = 0; i < PROPS_COUNT; i++) {
    EmbeddedVector<char, 64> buffer;
    SNPrintF(buffer, "prop%d", i);
    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
    Handle<Map> map =
248
        Map::CopyWithField(isolate, map0, name, FieldType::Any(isolate), NONE,
249 250
                           PropertyConstness::kMutable,
                           Representation::Tagged(), OMIT_TRANSITION)
251
            .ToHandleChecked();
252 253 254
    names[i] = name;
    maps[i] = map;

255
    TransitionsAccessor(isolate, map0).Insert(name, map, PROPERTY_TRANSITION);
256 257 258 259 260 261 262 263 264 265 266
  }

  const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
  STATIC_ASSERT(ATTRS_COUNT == 8);
  Handle<Map> attr_maps[ATTRS_COUNT];
  Handle<String> name = factory->InternalizeUtf8String("foo");

  // Add transitions for same field name but different attributes.
  for (int i = 0; i < ATTRS_COUNT; i++) {
    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);

267
    Handle<Map> map =
268 269
        Map::CopyWithField(isolate, map0, name, FieldType::Any(isolate),
                           attributes, PropertyConstness::kMutable,
270
                           Representation::Tagged(), OMIT_TRANSITION)
271
            .ToHandleChecked();
272 273
    attr_maps[i] = map;

274
    TransitionsAccessor(isolate, map0).Insert(name, map, PROPERTY_TRANSITION);
275 276 277
  }

  // Ensure that transitions for |name| field are valid.
278
  TransitionsAccessor transitions(isolate, map0);
279
  for (int i = 0; i < ATTRS_COUNT; i++) {
280
    PropertyAttributes attr = static_cast<PropertyAttributes>(i);
281
    CHECK_EQ(*attr_maps[i], transitions.SearchTransition(*name, kData, attr));
282 283 284
  }

  // Ensure that info about the other fields still valid.
285
  CHECK_EQ(PROPS_COUNT + ATTRS_COUNT, transitions.NumberOfTransitions());
286
  for (int i = 0; i < PROPS_COUNT + ATTRS_COUNT; i++) {
287
    Name key = transitions.GetKey(i);
288
    Map target = transitions.GetTarget(i);
289 290 291 292 293 294 295 296 297 298 299 300 301
    if (key == *name) {
      // Attributes transition.
      PropertyAttributes attributes =
          target->GetLastDescriptorDetails().attributes();
      CHECK_EQ(*attr_maps[static_cast<int>(attributes)], target);
    } else {
      for (int j = 0; j < PROPS_COUNT; j++) {
        if (*names[j] == key) {
          CHECK_EQ(*maps[j], target);
          break;
        }
      }
    }
302 303
  }

304
  DCHECK(transitions.IsSortedNoDuplicates());
305
}
306 307 308

}  // namespace internal
}  // namespace v8