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