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