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