OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 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 "src/map-reconfigurer.h" | |
6 | |
7 #include "src/field-type.h" | |
8 #include "src/handles.h" | |
9 #include "src/isolate.h" | |
10 #include "src/objects-inl.h" | |
11 #include "src/objects.h" | |
12 #include "src/transitions.h" | |
13 | |
14 namespace v8 { | |
15 namespace internal { | |
16 | |
17 namespace { | |
18 | |
19 inline bool EqualImmutableValues(Object* obj1, Object* obj2) { | |
20 if (obj1 == obj2) return true; // Valid for both kData and kAccessor kinds. | |
21 // TODO(ishell): compare AccessorPairs. | |
22 return false; | |
23 } | |
24 | |
25 } // namespace | |
26 | |
27 Handle<Map> MapReconfigurer::Result() const { | |
28 DCHECK_EQ(kEnd, state_); | |
29 return result_map_; | |
30 } | |
31 | |
32 Name* MapReconfigurer::GetKey(int descriptor) const { | |
33 return old_descriptors_->GetKey(descriptor); | |
34 } | |
35 | |
36 PropertyDetails MapReconfigurer::GetDetails(int descriptor) const { | |
37 DCHECK_LE(0, descriptor); | |
38 if (descriptor == modified_descriptor_) { | |
39 return PropertyDetails(new_kind_, new_attributes_, new_location_, | |
40 new_representation_); | |
41 } | |
42 return old_descriptors_->GetDetails(descriptor); | |
43 } | |
44 | |
45 Object* MapReconfigurer::GetValue(int descriptor) const { | |
46 DCHECK_LE(0, descriptor); | |
47 if (descriptor == modified_descriptor_) { | |
48 DCHECK_EQ(kDescriptor, new_location_); | |
49 return *new_value_; | |
50 } | |
51 DCHECK_EQ(kDescriptor, GetDetails(descriptor).location()); | |
52 return old_descriptors_->GetValue(descriptor); | |
53 } | |
54 | |
55 FieldType* MapReconfigurer::GetFieldType(int descriptor) const { | |
56 DCHECK_LE(0, descriptor); | |
57 if (descriptor == modified_descriptor_) { | |
58 DCHECK_EQ(kField, new_location_); | |
59 return *new_field_type_; | |
60 } | |
61 DCHECK_EQ(kField, GetDetails(descriptor).location()); | |
62 return old_descriptors_->GetFieldType(descriptor); | |
63 } | |
64 | |
65 Handle<FieldType> MapReconfigurer::GetOrComputeFieldType( | |
66 int descriptor, PropertyLocation location, | |
67 Representation representation) const { | |
68 DCHECK_LE(0, descriptor); | |
69 // |location| is just a pre-fetched GetDetails(descriptor).location(). | |
70 DCHECK_EQ(location, GetDetails(descriptor).location()); | |
71 if (location == kField) { | |
72 return handle(GetFieldType(descriptor), isolate_); | |
73 } else { | |
74 return GetValue(descriptor)->OptimalType(isolate_, representation); | |
75 } | |
76 } | |
77 | |
78 Handle<FieldType> MapReconfigurer::GetOrComputeFieldType( | |
79 Handle<DescriptorArray> descriptors, int descriptor, | |
80 PropertyLocation location, Representation representation) { | |
81 // |location| is just a pre-fetched GetDetails(descriptor).location(). | |
82 DCHECK_EQ(descriptors->GetDetails(descriptor).location(), location); | |
83 if (location == kField) { | |
84 return handle(descriptors->GetFieldType(descriptor), isolate_); | |
85 } else { | |
86 return descriptors->GetValue(descriptor) | |
87 ->OptimalType(isolate_, representation); | |
88 } | |
89 } | |
90 | |
91 Handle<Map> MapReconfigurer::ReconfigureToDataField( | |
92 int descriptor, PropertyAttributes attributes, | |
93 Representation representation, Handle<FieldType> field_type) { | |
94 DCHECK_EQ(kInitialized, state_); | |
95 DCHECK_LE(0, descriptor); | |
96 DCHECK(!old_map_->is_dictionary_map()); | |
97 modified_descriptor_ = descriptor; | |
98 new_kind_ = kData; | |
99 new_attributes_ = attributes; | |
100 new_location_ = kField; | |
101 new_representation_ = representation; | |
102 new_field_type_ = field_type; | |
103 | |
104 PropertyDetails old_details = | |
105 old_descriptors_->GetDetails(modified_descriptor_); | |
106 | |
107 // If property kind is not reconfigured merge the result with | |
108 // representation/field type from the old descriptor. | |
109 if (old_details.kind() == new_kind_) { | |
110 Representation old_representation = old_details.representation(); | |
111 new_representation_ = new_representation_.generalize(old_representation); | |
112 | |
113 Handle<FieldType> old_field_type = | |
114 GetOrComputeFieldType(old_descriptors_, modified_descriptor_, | |
115 old_details.location(), new_representation_); | |
116 | |
117 new_field_type_ = Map::GeneralizeFieldTypes( | |
118 old_representation, old_field_type, new_representation_, | |
119 new_field_type_, isolate_); | |
120 } | |
121 | |
122 if (TryRecofigureToDataFieldInplace()) return Result(); | |
123 if (FindRootMap()) return Result(); | |
Toon Verwaest
2017/01/09 13:01:19
This is odd to read... I'd expect if (!FindRootMap
Igor Sheludko
2017/01/09 14:54:25
true means "done", therefore it returns. And all t
Igor Sheludko
2017/01/10 10:28:08
As discussed offline, these methods now return an
| |
124 if (FindTargetMap()) return Result(); | |
125 ConstructNewMap(); | |
126 return Result(); | |
127 } | |
128 | |
129 Handle<Map> MapReconfigurer::ReconfigureElementsKind( | |
130 ElementsKind elements_kind) { | |
131 DCHECK_EQ(kInitialized, state_); | |
132 new_elements_kind_ = elements_kind; | |
133 | |
134 if (FindRootMap()) return Result(); | |
135 if (FindTargetMap()) return Result(); | |
136 ConstructNewMap(); | |
137 return Result(); | |
138 } | |
139 | |
140 Handle<Map> MapReconfigurer::Update() { | |
141 DCHECK_EQ(kInitialized, state_); | |
142 DCHECK(old_map_->is_deprecated()); | |
143 | |
144 if (FindRootMap()) return Result(); | |
145 if (FindTargetMap()) return Result(); | |
146 ConstructNewMap(); | |
147 return Result(); | |
148 } | |
149 | |
150 bool MapReconfigurer::CopyGeneralizeAllRepresentations(const char* reason) { | |
151 StoreMode store_mode = | |
152 modified_descriptor_ >= 0 ? FORCE_FIELD : ALLOW_IN_DESCRIPTOR; | |
153 result_map_ = Map::CopyGeneralizeAllRepresentations( | |
154 old_map_, new_elements_kind_, modified_descriptor_, store_mode, new_kind_, | |
155 new_attributes_, reason); | |
156 state_ = kEnd; | |
Toon Verwaest
2017/01/09 13:01:19
these states are a little odd. That's just for deb
Igor Sheludko
2017/01/09 14:54:25
Right. And the updater instance should not be used
| |
157 return true; // Done. | |
158 } | |
159 | |
160 bool MapReconfigurer::TryRecofigureToDataFieldInplace() { | |
161 // If it's just a representation generalization case (i.e. property kind and | |
162 // attributes stays unchanged) it's fine to transition from None to anything | |
163 // but double without any modification to the object, because the default | |
164 // uninitialized value for representation None can be overwritten by both | |
165 // smi and tagged values. Doubles, however, would require a box allocation. | |
166 if (new_representation_.IsNone() || new_representation_.IsDouble()) { | |
167 return false; // Not done yet. | |
168 } | |
169 | |
170 PropertyDetails old_details = | |
171 old_descriptors_->GetDetails(modified_descriptor_); | |
172 Representation old_representation = old_details.representation(); | |
173 if (!old_representation.IsNone()) { | |
174 return false; // Not done yet. | |
175 } | |
176 | |
177 DCHECK_EQ(new_kind_, old_details.kind()); | |
178 DCHECK_EQ(new_attributes_, old_details.attributes()); | |
179 DCHECK_EQ(kField, old_details.location()); | |
180 if (FLAG_trace_generalization) { | |
181 old_map_->PrintGeneralization( | |
182 stdout, "uninitialized field", modified_descriptor_, old_nof_, old_nof_, | |
183 false, old_representation, new_representation_, | |
184 handle(old_descriptors_->GetFieldType(modified_descriptor_), isolate_), | |
185 MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>()); | |
186 } | |
187 Handle<Map> field_owner(old_map_->FindFieldOwner(modified_descriptor_), | |
188 isolate_); | |
189 | |
190 Map::GeneralizeFieldType(field_owner, modified_descriptor_, | |
191 new_representation_, new_field_type_); | |
192 // Check that the descriptor array was updated. | |
193 DCHECK(old_descriptors_->GetDetails(modified_descriptor_) | |
194 .representation() | |
195 .Equals(new_representation_)); | |
196 DCHECK(old_descriptors_->GetFieldType(modified_descriptor_) | |
197 ->NowIs(new_field_type_)); | |
198 | |
199 result_map_ = old_map_; | |
200 state_ = kEnd; | |
201 return true; // Done. | |
202 } | |
203 | |
204 bool MapReconfigurer::FindRootMap() { | |
205 DCHECK_EQ(kInitialized, state_); | |
206 // Check the state of the root map. | |
207 root_map_ = handle(old_map_->FindRootMap(), isolate_); | |
208 int root_nof = root_map_->NumberOfOwnDescriptors(); | |
209 if (!old_map_->EquivalentToForTransition(*root_map_)) { | |
210 return CopyGeneralizeAllRepresentations("GenAll_NotEquivalent"); | |
211 } | |
212 | |
213 ElementsKind from_kind = root_map_->elements_kind(); | |
214 ElementsKind to_kind = new_elements_kind_; | |
215 // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS. | |
216 if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS && | |
217 to_kind != SLOW_STRING_WRAPPER_ELEMENTS && | |
218 to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS && | |
219 !(IsTransitionableFastElementsKind(from_kind) && | |
220 IsMoreGeneralElementsKindTransition(from_kind, to_kind))) { | |
221 return CopyGeneralizeAllRepresentations("GenAll_InvalidElementsTransition"); | |
222 } | |
223 | |
224 if (modified_descriptor_ >= 0 && modified_descriptor_ < root_nof) { | |
225 PropertyDetails old_details = | |
226 old_descriptors_->GetDetails(modified_descriptor_); | |
227 if (old_details.kind() != new_kind_ || | |
228 old_details.attributes() != new_attributes_) { | |
229 return CopyGeneralizeAllRepresentations("GenAll_RootModification1"); | |
230 } | |
231 if (!new_representation_.fits_into(old_details.representation())) { | |
232 return CopyGeneralizeAllRepresentations("GenAll_RootModification2"); | |
233 } | |
234 if (old_details.location() != kField) { | |
235 return CopyGeneralizeAllRepresentations("GenAll_RootModification3"); | |
236 } | |
237 DCHECK_EQ(kData, old_details.kind()); | |
238 DCHECK_EQ(kData, new_kind_); | |
239 DCHECK_EQ(kField, new_location_); | |
240 FieldType* old_field_type = | |
241 old_descriptors_->GetFieldType(modified_descriptor_); | |
242 if (!new_field_type_->NowIs(old_field_type)) { | |
243 return CopyGeneralizeAllRepresentations("GenAll_RootModification4"); | |
244 } | |
245 } | |
246 | |
247 // From here on, use the map with correct elements kind as root map. | |
248 if (from_kind != to_kind) { | |
249 root_map_ = Map::AsElementsKind(root_map_, to_kind); | |
250 } | |
251 state_ = kAtRootMap; | |
252 return false; // Not done yet. | |
253 } | |
254 | |
255 bool MapReconfigurer::FindTargetMap() { | |
256 DCHECK_EQ(kAtRootMap, state_); | |
257 target_map_ = root_map_; | |
258 | |
259 int root_nof = root_map_->NumberOfOwnDescriptors(); | |
260 for (int i = root_nof; i < old_nof_; ++i) { | |
261 PropertyDetails old_details = GetDetails(i); | |
262 Map* transition = TransitionArray::SearchTransition( | |
263 *target_map_, old_details.kind(), GetKey(i), old_details.attributes()); | |
264 if (transition == NULL) break; | |
265 Handle<Map> tmp_map(transition, isolate_); | |
266 | |
267 Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(), | |
268 isolate_); | |
269 | |
270 // Check if target map is incompatible. | |
271 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i); | |
272 DCHECK_EQ(old_details.kind(), tmp_details.kind()); | |
273 DCHECK_EQ(old_details.attributes(), tmp_details.attributes()); | |
274 if (old_details.kind() == kAccessor && | |
275 !EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) { | |
276 // TODO(ishell): mutable accessors are not implemented yet. | |
277 return CopyGeneralizeAllRepresentations("GenAll_Incompatible"); | |
278 } | |
279 // Check if old location fits into tmp location. | |
280 if (old_details.location() == kField && | |
281 tmp_details.location() == kDescriptor) { | |
282 break; | |
283 } | |
284 | |
285 // Check if old representation fits into tmp representation. | |
286 Representation tmp_representation = tmp_details.representation(); | |
287 if (!old_details.representation().fits_into(tmp_representation)) { | |
288 break; | |
289 } | |
290 | |
291 if (tmp_details.location() == kField) { | |
292 Handle<FieldType> old_field_type = | |
293 GetOrComputeFieldType(i, old_details.location(), tmp_representation); | |
294 Map::GeneralizeFieldType(tmp_map, i, tmp_representation, old_field_type); | |
295 } else { | |
296 // kDescriptor: Check that the value matches. | |
297 if (!EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) { | |
298 break; | |
299 } | |
300 } | |
301 DCHECK(!tmp_map->is_deprecated()); | |
302 target_map_ = tmp_map; | |
303 } | |
304 | |
305 // Directly change the map if the target map is more general. | |
306 int target_nof = target_map_->NumberOfOwnDescriptors(); | |
307 if (target_nof == old_nof_) { | |
308 #ifdef DEBUG | |
309 if (modified_descriptor_ >= 0) { | |
310 DescriptorArray* target_descriptors = target_map_->instance_descriptors(); | |
311 PropertyDetails details = | |
312 target_descriptors->GetDetails(modified_descriptor_); | |
313 DCHECK_EQ(new_kind_, details.kind()); | |
314 DCHECK_EQ(new_attributes_, details.attributes()); | |
315 DCHECK_EQ(new_location_, details.location()); | |
316 DCHECK(new_representation_.fits_into(details.representation())); | |
317 if (new_location_ == kField) { | |
318 DCHECK_EQ(kField, details.location()); | |
319 DCHECK(new_field_type_->NowIs( | |
320 target_descriptors->GetFieldType(modified_descriptor_))); | |
321 } else { | |
322 DCHECK(details.location() == kField || | |
323 EqualImmutableValues(*new_value_, target_descriptors->GetValue( | |
324 modified_descriptor_))); | |
325 } | |
326 } | |
327 #endif | |
328 if (*target_map_ != *old_map_) { | |
329 old_map_->NotifyLeafMapLayoutChange(); | |
330 } | |
331 result_map_ = target_map_; | |
332 state_ = kEnd; | |
333 return true; // Done. | |
334 } | |
335 | |
336 // Find the last compatible target map in the transition tree. | |
337 for (int i = target_nof; i < old_nof_; ++i) { | |
338 PropertyDetails old_details = GetDetails(i); | |
339 Map* transition = TransitionArray::SearchTransition( | |
340 *target_map_, old_details.kind(), GetKey(i), old_details.attributes()); | |
341 if (transition == NULL) break; | |
342 Handle<Map> tmp_map(transition, isolate_); | |
343 Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(), | |
344 isolate_); | |
345 | |
346 #ifdef DEBUG | |
347 // Check that target map is compatible. | |
348 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i); | |
349 DCHECK_EQ(old_details.kind(), tmp_details.kind()); | |
350 DCHECK_EQ(old_details.attributes(), tmp_details.attributes()); | |
351 #endif | |
352 if (old_details.kind() == kAccessor && | |
353 !EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) { | |
354 return CopyGeneralizeAllRepresentations("GenAll_Incompatible"); | |
355 } | |
356 DCHECK(!tmp_map->is_deprecated()); | |
357 target_map_ = tmp_map; | |
358 } | |
359 | |
360 state_ = kAtTargetMap; | |
361 return false; // Not done yet. | |
362 } | |
363 | |
364 Handle<DescriptorArray> MapReconfigurer::BuildDescriptorArray() { | |
365 int target_nof = target_map_->NumberOfOwnDescriptors(); | |
366 Handle<DescriptorArray> target_descriptors( | |
367 target_map_->instance_descriptors(), isolate_); | |
368 | |
369 // Allocate a new descriptor array large enough to hold the required | |
370 // descriptors, with minimally the exact same size as the old descriptor | |
371 // array. | |
372 int new_slack = | |
373 Max(old_nof_, old_descriptors_->number_of_descriptors()) - old_nof_; | |
374 Handle<DescriptorArray> new_descriptors = | |
375 DescriptorArray::Allocate(isolate_, old_nof_, new_slack); | |
376 DCHECK(new_descriptors->length() > target_descriptors->length() || | |
377 new_descriptors->NumberOfSlackDescriptors() > 0 || | |
378 new_descriptors->number_of_descriptors() == | |
379 old_descriptors_->number_of_descriptors()); | |
380 DCHECK(new_descriptors->number_of_descriptors() == old_nof_); | |
381 | |
382 int root_nof = root_map_->NumberOfOwnDescriptors(); | |
383 | |
384 // Given that we passed root modification check in FindRootMap() so | |
385 // the root descriptors are either not modified at all or already more | |
386 // general than we requested. Take |root_nof| entries as is. | |
387 // 0 -> |root_nof| | |
388 int current_offset = 0; | |
389 for (int i = 0; i < root_nof; ++i) { | |
390 PropertyDetails old_details = old_descriptors_->GetDetails(i); | |
391 if (old_details.location() == kField) { | |
392 current_offset += old_details.field_width_in_words(); | |
393 } | |
394 Descriptor d(handle(GetKey(i), isolate_), | |
395 handle(old_descriptors_->GetValue(i), isolate_), old_details); | |
396 new_descriptors->Set(i, &d); | |
397 } | |
398 | |
399 // Merge virtually modified old_descriptor entries with target_descriptor | |
400 // entries. | |
401 // |root_nof| -> |target_nof| | |
402 for (int i = root_nof; i < target_nof; ++i) { | |
403 Handle<Name> key(GetKey(i), isolate_); | |
404 PropertyDetails old_details = GetDetails(i); | |
405 PropertyDetails target_details = target_descriptors->GetDetails(i); | |
406 | |
407 PropertyKind next_kind = old_details.kind(); | |
408 PropertyAttributes next_attributes = old_details.attributes(); | |
409 PropertyLocation next_location = | |
410 old_details.location() == kField || | |
411 target_details.location() == kField || | |
412 !EqualImmutableValues(target_descriptors->GetValue(i), | |
413 GetValue(i)) | |
414 ? kField | |
415 : kDescriptor; | |
416 | |
417 Representation next_representation = | |
418 old_details.representation().generalize( | |
419 target_details.representation()); | |
420 | |
421 DCHECK_EQ(next_kind, target_details.kind()); | |
422 DCHECK_EQ(next_attributes, target_details.attributes()); | |
423 | |
424 if (next_location == kField) { | |
425 Handle<FieldType> old_field_type = | |
426 GetOrComputeFieldType(i, old_details.location(), next_representation); | |
427 | |
428 Handle<FieldType> target_field_type = | |
429 GetOrComputeFieldType(target_descriptors, i, | |
430 target_details.location(), next_representation); | |
431 | |
432 Handle<FieldType> next_field_type = Map::GeneralizeFieldTypes( | |
433 old_details.representation(), old_field_type, next_representation, | |
434 target_field_type, isolate_); | |
435 | |
436 Handle<Object> wrapped_type(Map::WrapType(next_field_type)); | |
437 Descriptor d; | |
438 if (next_kind == kData) { | |
439 d = Descriptor::DataField(key, current_offset, wrapped_type, | |
440 next_attributes, next_representation); | |
441 } else { | |
442 // TODO(ishell): mutable accessors are not implemented yet. | |
443 UNIMPLEMENTED(); | |
444 } | |
445 current_offset += d.GetDetails().field_width_in_words(); | |
446 new_descriptors->Set(i, &d); | |
447 } else { | |
448 DCHECK_EQ(kDescriptor, next_location); | |
449 | |
450 Handle<Object> value(GetValue(i), isolate_); | |
451 Descriptor d; | |
452 if (next_kind == kData) { | |
453 d = Descriptor::DataConstant(key, value, next_attributes); | |
454 } else { | |
455 DCHECK_EQ(kAccessor, next_kind); | |
456 d = Descriptor::AccessorConstant(key, value, next_attributes); | |
457 } | |
458 new_descriptors->Set(i, &d); | |
459 } | |
460 } | |
461 | |
462 // Take virtually modified old_descriptor entries. | |
463 // |target_nof| -> |old_nof| | |
464 for (int i = target_nof; i < old_nof_; ++i) { | |
465 PropertyDetails old_details = GetDetails(i); | |
466 Handle<Name> key(GetKey(i), isolate_); | |
467 | |
468 PropertyKind next_kind = old_details.kind(); | |
469 PropertyAttributes next_attributes = old_details.attributes(); | |
470 PropertyLocation next_location = old_details.location(); | |
471 Representation next_representation = old_details.representation(); | |
472 | |
473 Descriptor d; | |
474 if (next_location == kField) { | |
475 Handle<FieldType> old_field_type = | |
476 GetOrComputeFieldType(i, old_details.location(), next_representation); | |
477 | |
478 Handle<Object> wrapped_type(Map::WrapType(old_field_type)); | |
479 Descriptor d; | |
480 if (next_kind == kData) { | |
481 d = Descriptor::DataField(key, current_offset, wrapped_type, | |
482 next_attributes, next_representation); | |
483 } else { | |
484 // TODO(ishell): mutable accessors are not implemented yet. | |
485 UNIMPLEMENTED(); | |
486 } | |
487 current_offset += d.GetDetails().field_width_in_words(); | |
488 new_descriptors->Set(i, &d); | |
489 } else { | |
490 DCHECK_EQ(kDescriptor, next_location); | |
491 | |
492 Handle<Object> value(GetValue(i), isolate_); | |
493 if (next_kind == kData) { | |
494 d = Descriptor::DataConstant(key, value, next_attributes); | |
495 } else { | |
496 DCHECK_EQ(kAccessor, next_kind); | |
497 d = Descriptor::AccessorConstant(key, value, next_attributes); | |
498 } | |
499 new_descriptors->Set(i, &d); | |
500 } | |
501 } | |
502 | |
503 new_descriptors->Sort(); | |
504 return new_descriptors; | |
505 } | |
506 | |
507 Handle<Map> MapReconfigurer::FindSplitMap(Handle<DescriptorArray> descriptors) { | |
508 DisallowHeapAllocation no_allocation; | |
509 | |
510 int root_nof = root_map_->NumberOfOwnDescriptors(); | |
511 Map* current = *root_map_; | |
512 for (int i = root_nof; i < old_nof_; i++) { | |
513 Name* name = descriptors->GetKey(i); | |
514 PropertyDetails details = descriptors->GetDetails(i); | |
515 Map* next = TransitionArray::SearchTransition(current, details.kind(), name, | |
516 details.attributes()); | |
517 if (next == NULL) break; | |
518 DescriptorArray* next_descriptors = next->instance_descriptors(); | |
519 | |
520 PropertyDetails next_details = next_descriptors->GetDetails(i); | |
521 DCHECK_EQ(details.kind(), next_details.kind()); | |
522 DCHECK_EQ(details.attributes(), next_details.attributes()); | |
523 if (details.location() != next_details.location()) break; | |
524 if (!details.representation().Equals(next_details.representation())) break; | |
525 | |
526 if (next_details.location() == kField) { | |
527 FieldType* next_field_type = next_descriptors->GetFieldType(i); | |
528 if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) { | |
529 break; | |
530 } | |
531 } else { | |
532 if (!EqualImmutableValues(descriptors->GetValue(i), | |
533 next_descriptors->GetValue(i))) { | |
534 break; | |
535 } | |
536 } | |
537 current = next; | |
538 } | |
539 return handle(current, isolate_); | |
540 } | |
541 | |
542 bool MapReconfigurer::ConstructNewMap() { | |
543 Handle<DescriptorArray> new_descriptors = BuildDescriptorArray(); | |
544 | |
545 Handle<Map> split_map = FindSplitMap(new_descriptors); | |
546 int split_nof = split_map->NumberOfOwnDescriptors(); | |
547 DCHECK_NE(old_nof_, split_nof); | |
548 | |
549 PropertyDetails split_details = GetDetails(split_nof); | |
550 | |
551 // Invalidate a transition target at |key|. | |
552 Map* maybe_transition = TransitionArray::SearchTransition( | |
553 *split_map, split_details.kind(), GetKey(split_nof), | |
554 split_details.attributes()); | |
555 if (maybe_transition != NULL) { | |
556 maybe_transition->DeprecateTransitionTree(); | |
557 } | |
558 | |
559 // If |maybe_transition| is not NULL then the transition array already | |
560 // contains entry for given descriptor. This means that the transition | |
561 // could be inserted regardless of whether transitions array is full or not. | |
562 if (maybe_transition == NULL && | |
563 !TransitionArray::CanHaveMoreTransitions(split_map)) { | |
564 return CopyGeneralizeAllRepresentations("GenAll_CantHaveMoreTransitions"); | |
565 } | |
566 | |
567 old_map_->NotifyLeafMapLayoutChange(); | |
568 | |
569 if (FLAG_trace_generalization && modified_descriptor_ >= 0) { | |
570 PropertyDetails old_details = | |
571 old_descriptors_->GetDetails(modified_descriptor_); | |
572 PropertyDetails new_details = | |
573 new_descriptors->GetDetails(modified_descriptor_); | |
574 MaybeHandle<FieldType> old_field_type; | |
575 MaybeHandle<FieldType> new_field_type; | |
576 MaybeHandle<Object> old_value; | |
577 MaybeHandle<Object> new_value; | |
578 if (old_details.type() == DATA) { | |
579 old_field_type = handle( | |
580 old_descriptors_->GetFieldType(modified_descriptor_), isolate_); | |
581 } else { | |
582 old_value = | |
583 handle(old_descriptors_->GetValue(modified_descriptor_), isolate_); | |
584 } | |
585 if (new_details.type() == DATA) { | |
586 new_field_type = | |
587 handle(new_descriptors->GetFieldType(modified_descriptor_), isolate_); | |
588 } else { | |
589 new_value = | |
590 handle(new_descriptors->GetValue(modified_descriptor_), isolate_); | |
591 } | |
592 | |
593 old_map_->PrintGeneralization( | |
594 stdout, "", modified_descriptor_, split_nof, old_nof_, | |
595 old_details.location() == kDescriptor && new_location_ == kField, | |
596 old_details.representation(), new_details.representation(), | |
597 old_field_type, old_value, new_field_type, new_value); | |
598 } | |
599 | |
600 Handle<LayoutDescriptor> new_layout_descriptor = | |
601 LayoutDescriptor::New(split_map, new_descriptors, old_nof_); | |
602 | |
603 Handle<Map> new_map = Map::AddMissingTransitions(split_map, new_descriptors, | |
604 new_layout_descriptor); | |
605 | |
606 // Deprecated part of the transition tree is no longer reachable, so replace | |
607 // current instance descriptors in the "survived" part of the tree with | |
608 // the new descriptors to maintain descriptors sharing invariant. | |
609 split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor); | |
610 | |
611 result_map_ = new_map; | |
612 state_ = kEnd; | |
613 return true; // Done. | |
614 } | |
615 | |
616 } // namespace internal | |
617 } // namespace v8 | |
OLD | NEW |