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