Line data Source code
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-updater.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 4769 : 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 397902 : Name* MapUpdater::GetKey(int descriptor) const {
28 397902 : return old_descriptors_->GetKey(descriptor);
29 : }
30 :
31 395831 : PropertyDetails MapUpdater::GetDetails(int descriptor) const {
32 : DCHECK_LE(0, descriptor);
33 395831 : if (descriptor == modified_descriptor_) {
34 : return PropertyDetails(new_kind_, new_attributes_, new_location_,
35 272978 : new_constness_, new_representation_);
36 : }
37 259342 : return old_descriptors_->GetDetails(descriptor);
38 : }
39 :
40 7252 : Object* MapUpdater::GetValue(int descriptor) const {
41 : DCHECK_LE(0, descriptor);
42 7252 : if (descriptor == modified_descriptor_) {
43 : DCHECK_EQ(kDescriptor, new_location_);
44 0 : return *new_value_;
45 : }
46 : DCHECK_EQ(kDescriptor, GetDetails(descriptor).location());
47 7252 : return old_descriptors_->GetValue(descriptor);
48 : }
49 :
50 287251 : FieldType* MapUpdater::GetFieldType(int descriptor) const {
51 : DCHECK_LE(0, descriptor);
52 287251 : if (descriptor == modified_descriptor_) {
53 : DCHECK_EQ(kField, new_location_);
54 65443 : return *new_field_type_;
55 : }
56 : DCHECK_EQ(kField, GetDetails(descriptor).location());
57 221808 : return old_descriptors_->GetFieldType(descriptor);
58 : }
59 :
60 288319 : Handle<FieldType> MapUpdater::GetOrComputeFieldType(
61 : int descriptor, PropertyLocation location,
62 : Representation representation) const {
63 : DCHECK_LE(0, descriptor);
64 : // |location| is just a pre-fetched GetDetails(descriptor).location().
65 : DCHECK_EQ(location, GetDetails(descriptor).location());
66 288319 : if (location == kField) {
67 287251 : return handle(GetFieldType(descriptor), isolate_);
68 : } else {
69 1068 : return GetValue(descriptor)->OptimalType(isolate_, representation);
70 : }
71 : }
72 :
73 450564 : Handle<FieldType> MapUpdater::GetOrComputeFieldType(
74 : Handle<DescriptorArray> descriptors, int descriptor,
75 : PropertyLocation location, Representation representation) {
76 : // |location| is just a pre-fetched GetDetails(descriptor).location().
77 : DCHECK_EQ(descriptors->GetDetails(descriptor).location(), location);
78 450564 : if (location == kField) {
79 854278 : return handle(descriptors->GetFieldType(descriptor), isolate_);
80 : } else {
81 : return descriptors->GetValue(descriptor)
82 46850 : ->OptimalType(isolate_, representation);
83 : }
84 : }
85 :
86 360534 : Handle<Map> MapUpdater::ReconfigureToDataField(int descriptor,
87 : PropertyAttributes attributes,
88 : PropertyConstness constness,
89 : Representation representation,
90 360534 : Handle<FieldType> field_type) {
91 : DCHECK_EQ(kInitialized, state_);
92 : DCHECK_LE(0, descriptor);
93 : DCHECK(!old_map_->is_dictionary_map());
94 360534 : modified_descriptor_ = descriptor;
95 360534 : new_kind_ = kData;
96 360534 : new_attributes_ = attributes;
97 360534 : new_location_ = kField;
98 :
99 : PropertyDetails old_details =
100 360534 : old_descriptors_->GetDetails(modified_descriptor_);
101 :
102 : // If property kind is not reconfigured merge the result with
103 : // representation/field type from the old descriptor.
104 360534 : if (old_details.kind() == new_kind_) {
105 349250 : new_constness_ = GeneralizeConstness(constness, old_details.constness());
106 :
107 349250 : Representation old_representation = old_details.representation();
108 349250 : new_representation_ = representation.generalize(old_representation);
109 :
110 : Handle<FieldType> old_field_type =
111 : GetOrComputeFieldType(old_descriptors_, modified_descriptor_,
112 349250 : old_details.location(), new_representation_);
113 :
114 : new_field_type_ =
115 : Map::GeneralizeFieldType(old_representation, old_field_type,
116 349250 : new_representation_, field_type, isolate_);
117 : } else {
118 : // We don't know if this is a first property kind reconfiguration
119 : // and we don't know which value was in this property previously
120 : // therefore we can't treat such a property as constant.
121 11284 : new_constness_ = kMutable;
122 11284 : new_representation_ = representation;
123 11284 : new_field_type_ = field_type;
124 : }
125 :
126 : GeneralizeIfTransitionableFastElementsKind(
127 721068 : &new_constness_, &new_representation_, &new_field_type_);
128 :
129 360534 : if (TryRecofigureToDataFieldInplace() == kEnd) return result_map_;
130 82966 : if (FindRootMap() == kEnd) return result_map_;
131 65985 : if (FindTargetMap() == kEnd) return result_map_;
132 23763 : ConstructNewMap();
133 : DCHECK_EQ(kEnd, state_);
134 23763 : return result_map_;
135 : }
136 :
137 427557 : Handle<Map> MapUpdater::ReconfigureElementsKind(ElementsKind elements_kind) {
138 : DCHECK_EQ(kInitialized, state_);
139 427557 : new_elements_kind_ = elements_kind;
140 : is_transitionable_fast_elements_kind_ =
141 427557 : IsTransitionableFastElementsKind(new_elements_kind_);
142 :
143 427557 : if (FindRootMap() == kEnd) return result_map_;
144 427557 : if (FindTargetMap() == kEnd) return result_map_;
145 868 : ConstructNewMap();
146 : DCHECK_EQ(kEnd, state_);
147 868 : return result_map_;
148 : }
149 :
150 4167 : Handle<Map> MapUpdater::Update() {
151 : DCHECK_EQ(kInitialized, state_);
152 : DCHECK(old_map_->is_deprecated());
153 :
154 4167 : if (FindRootMap() == kEnd) return result_map_;
155 4097 : if (FindTargetMap() == kEnd) return result_map_;
156 199 : ConstructNewMap();
157 : DCHECK_EQ(kEnd, state_);
158 199 : return result_map_;
159 : }
160 :
161 461848 : void MapUpdater::GeneralizeIfTransitionableFastElementsKind(
162 : PropertyConstness* constness, Representation* representation,
163 : Handle<FieldType>* field_type) {
164 : DCHECK_EQ(is_transitionable_fast_elements_kind_,
165 : IsTransitionableFastElementsKind(new_elements_kind_));
166 476338 : if (is_transitionable_fast_elements_kind_ &&
167 : Map::IsInplaceGeneralizableField(*constness, *representation,
168 : **field_type)) {
169 : // We don't support propagation of field generalization through elements
170 : // kind transitions because they are inserted into the transition tree
171 : // before field transitions. In order to avoid complexity of handling
172 : // such a case we ensure that all maps with transitionable elements kinds
173 : // do not have fields that can be generalized in-place (without creation
174 : // of a new map).
175 : if (FLAG_track_constant_fields && FLAG_modify_map_inplace) {
176 : *constness = kMutable;
177 : }
178 : DCHECK(representation->IsHeapObject());
179 126 : *field_type = FieldType::Any(isolate_);
180 : }
181 461848 : }
182 :
183 0 : void MapUpdater::GeneralizeField(Handle<Map> map, int modify_index,
184 : PropertyConstness new_constness,
185 : Representation new_representation,
186 : Handle<FieldType> new_field_type) {
187 : Map::GeneralizeField(map, modify_index, new_constness, new_representation,
188 462385 : new_field_type);
189 :
190 : DCHECK_EQ(*old_descriptors_, old_map_->instance_descriptors());
191 0 : }
192 :
193 17070 : MapUpdater::State MapUpdater::CopyGeneralizeAllFields(const char* reason) {
194 : result_map_ = Map::CopyGeneralizeAllFields(old_map_, new_elements_kind_,
195 : modified_descriptor_, new_kind_,
196 17070 : new_attributes_, reason);
197 17070 : state_ = kEnd;
198 17070 : return state_; // Done.
199 : }
200 :
201 360534 : MapUpdater::State MapUpdater::TryRecofigureToDataFieldInplace() {
202 : // If it's just a representation generalization case (i.e. property kind and
203 : // attributes stays unchanged) it's fine to transition from None to anything
204 : // but double without any modification to the object, because the default
205 : // uninitialized value for representation None can be overwritten by both
206 : // smi and tagged values. Doubles, however, would require a box allocation.
207 360534 : if (new_representation_.IsNone() || new_representation_.IsDouble()) {
208 16528 : return state_; // Not done yet.
209 : }
210 :
211 : PropertyDetails old_details =
212 688012 : old_descriptors_->GetDetails(modified_descriptor_);
213 : Representation old_representation = old_details.representation();
214 344006 : if (!old_representation.IsNone()) {
215 66438 : return state_; // Not done yet.
216 : }
217 :
218 : DCHECK_EQ(new_kind_, old_details.kind());
219 : DCHECK_EQ(new_attributes_, old_details.attributes());
220 : DCHECK_EQ(kField, old_details.location());
221 277568 : if (FLAG_trace_generalization) {
222 : old_map_->PrintGeneralization(
223 : stdout, "uninitialized field", modified_descriptor_, old_nof_, old_nof_,
224 : false, old_representation, new_representation_,
225 : handle(old_descriptors_->GetFieldType(modified_descriptor_), isolate_),
226 0 : MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>());
227 : }
228 : Handle<Map> field_owner(old_map_->FindFieldOwner(modified_descriptor_),
229 555136 : isolate_);
230 :
231 : GeneralizeField(field_owner, modified_descriptor_, new_constness_,
232 277568 : new_representation_, new_field_type_);
233 : // Check that the descriptor array was updated.
234 : DCHECK(old_descriptors_->GetDetails(modified_descriptor_)
235 : .representation()
236 : .Equals(new_representation_));
237 : DCHECK(old_descriptors_->GetFieldType(modified_descriptor_)
238 : ->NowIs(new_field_type_));
239 :
240 277568 : result_map_ = old_map_;
241 277568 : state_ = kEnd;
242 277568 : return state_; // Done.
243 : }
244 :
245 514690 : MapUpdater::State MapUpdater::FindRootMap() {
246 : DCHECK_EQ(kInitialized, state_);
247 : // Check the state of the root map.
248 1544070 : root_map_ = handle(old_map_->FindRootMap(), isolate_);
249 : ElementsKind from_kind = root_map_->elements_kind();
250 514690 : ElementsKind to_kind = new_elements_kind_;
251 514690 : if (root_map_->is_deprecated()) {
252 0 : state_ = kEnd;
253 : result_map_ = handle(
254 0 : JSFunction::cast(root_map_->GetConstructor())->initial_map(), isolate_);
255 0 : if (from_kind != to_kind) {
256 0 : result_map_ = Map::AsElementsKind(result_map_, to_kind);
257 : }
258 : DCHECK(result_map_->is_dictionary_map());
259 0 : return state_;
260 : }
261 : int root_nof = root_map_->NumberOfOwnDescriptors();
262 514690 : if (!old_map_->EquivalentToForTransition(*root_map_)) {
263 95 : return CopyGeneralizeAllFields("GenAll_NotEquivalent");
264 : }
265 :
266 : // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
267 1029190 : if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
268 252482 : to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
269 766875 : to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
270 : !(IsTransitionableFastElementsKind(from_kind) &&
271 126039 : IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
272 0 : return CopyGeneralizeAllFields("GenAll_InvalidElementsTransition");
273 : }
274 :
275 514595 : if (modified_descriptor_ >= 0 && modified_descriptor_ < root_nof) {
276 : PropertyDetails old_details =
277 17549 : old_descriptors_->GetDetails(modified_descriptor_);
278 23885 : if (old_details.kind() != new_kind_ ||
279 6336 : old_details.attributes() != new_attributes_) {
280 11213 : return CopyGeneralizeAllFields("GenAll_RootModification1");
281 : }
282 6336 : if (old_details.location() != kField) {
283 4984 : return CopyGeneralizeAllFields("GenAll_RootModification2");
284 : }
285 2704 : if (new_constness_ != old_details.constness() &&
286 : (!FLAG_modify_map_inplace || !old_map_->is_prototype_map())) {
287 0 : return CopyGeneralizeAllFields("GenAll_RootModification3");
288 : }
289 2704 : if (!new_representation_.fits_into(old_details.representation())) {
290 20 : return CopyGeneralizeAllFields("GenAll_RootModification4");
291 : }
292 :
293 : DCHECK_EQ(kData, old_details.kind());
294 : DCHECK_EQ(kData, new_kind_);
295 : DCHECK_EQ(kField, new_location_);
296 : FieldType* old_field_type =
297 2664 : old_descriptors_->GetFieldType(modified_descriptor_);
298 1332 : if (!new_field_type_->NowIs(old_field_type)) {
299 739 : return CopyGeneralizeAllFields("GenAll_RootModification5");
300 : }
301 :
302 : // Modify root map in-place.
303 : if (FLAG_modify_map_inplace && new_constness_ != old_details.constness()) {
304 : // Only prototype root maps are allowed to be updated in-place.
305 : // TODO(ishell): fix all the stubs that use prototype map check to
306 : // ensure that the prototype was not modified.
307 : DCHECK(old_map_->is_prototype_map());
308 : DCHECK(old_map_->is_stable());
309 : DCHECK(IsGeneralizableTo(old_details.constness(), new_constness_));
310 : GeneralizeField(old_map_, modified_descriptor_, new_constness_,
311 : old_details.representation(),
312 : handle(old_field_type, isolate_));
313 : }
314 : }
315 :
316 : // From here on, use the map with correct elements kind as root map.
317 497639 : if (from_kind != to_kind) {
318 428253 : root_map_ = Map::AsElementsKind(root_map_, to_kind);
319 : }
320 497639 : state_ = kAtRootMap;
321 497639 : return state_; // Not done yet.
322 : }
323 :
324 497639 : MapUpdater::State MapUpdater::FindTargetMap() {
325 : DCHECK_EQ(kAtRootMap, state_);
326 497639 : target_map_ = root_map_;
327 :
328 : int root_nof = root_map_->NumberOfOwnDescriptors();
329 683636 : for (int i = root_nof; i < old_nof_; ++i) {
330 210841 : PropertyDetails old_details = GetDetails(i);
331 : Map* transition = TransitionsAccessor(target_map_)
332 : .SearchTransition(GetKey(i), old_details.kind(),
333 421682 : old_details.attributes());
334 210841 : if (transition == nullptr) break;
335 209212 : Handle<Map> tmp_map(transition, isolate_);
336 :
337 : Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
338 209212 : isolate_);
339 :
340 : // Check if target map is incompatible.
341 209212 : PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
342 : DCHECK_EQ(old_details.kind(), tmp_details.kind());
343 : DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
344 209342 : if (old_details.kind() == kAccessor &&
345 130 : !EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) {
346 : // TODO(ishell): mutable accessors are not implemented yet.
347 14 : return CopyGeneralizeAllFields("GenAll_Incompatible");
348 : }
349 : PropertyConstness tmp_constness = tmp_details.constness();
350 209198 : if (!FLAG_modify_map_inplace &&
351 : !IsGeneralizableTo(old_details.constness(), tmp_constness)) {
352 : break;
353 : }
354 200167 : if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) {
355 : break;
356 : }
357 200150 : Representation tmp_representation = tmp_details.representation();
358 400300 : if (!old_details.representation().fits_into(tmp_representation)) {
359 : break;
360 : }
361 :
362 186052 : if (tmp_details.location() == kField) {
363 : Handle<FieldType> old_field_type =
364 184817 : GetOrComputeFieldType(i, old_details.location(), tmp_representation);
365 : PropertyConstness constness =
366 : FLAG_modify_map_inplace ? old_details.constness() : tmp_constness;
367 : GeneralizeField(tmp_map, i, constness, tmp_representation,
368 : old_field_type);
369 : } else {
370 : // kDescriptor: Check that the value matches.
371 2470 : if (!EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) {
372 : break;
373 : }
374 : }
375 : DCHECK(!tmp_map->is_deprecated());
376 185997 : target_map_ = tmp_map;
377 : }
378 :
379 : // Directly change the map if the target map is more general.
380 : int target_nof = target_map_->NumberOfOwnDescriptors();
381 497625 : if (target_nof == old_nof_) {
382 : #ifdef DEBUG
383 : if (modified_descriptor_ >= 0) {
384 : DescriptorArray* target_descriptors = target_map_->instance_descriptors();
385 : PropertyDetails details =
386 : target_descriptors->GetDetails(modified_descriptor_);
387 : DCHECK_EQ(new_kind_, details.kind());
388 : DCHECK_EQ(new_attributes_, details.attributes());
389 : DCHECK(IsGeneralizableTo(new_constness_, details.constness()));
390 : DCHECK_EQ(new_location_, details.location());
391 : DCHECK(new_representation_.fits_into(details.representation()));
392 : if (new_location_ == kField) {
393 : DCHECK_EQ(kField, details.location());
394 : DCHECK(new_field_type_->NowIs(
395 : target_descriptors->GetFieldType(modified_descriptor_)));
396 : } else {
397 : DCHECK(details.location() == kField ||
398 : EqualImmutableValues(*new_value_, target_descriptors->GetValue(
399 : modified_descriptor_)));
400 : }
401 : }
402 : #endif
403 472795 : if (*target_map_ != *old_map_) {
404 431252 : old_map_->NotifyLeafMapLayoutChange();
405 : }
406 472795 : result_map_ = target_map_;
407 472795 : state_ = kEnd;
408 472795 : return state_; // Done.
409 : }
410 :
411 : // Find the last compatible target map in the transition tree.
412 52685 : for (int i = target_nof; i < old_nof_; ++i) {
413 54314 : PropertyDetails old_details = GetDetails(i);
414 : Map* transition = TransitionsAccessor(target_map_)
415 : .SearchTransition(GetKey(i), old_details.kind(),
416 108628 : old_details.attributes());
417 54314 : if (transition == nullptr) break;
418 52685 : Handle<Map> tmp_map(transition, isolate_);
419 : Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
420 52685 : isolate_);
421 : #ifdef DEBUG
422 : // Check that target map is compatible.
423 : PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
424 : DCHECK_EQ(old_details.kind(), tmp_details.kind());
425 : DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
426 : #endif
427 52700 : if (old_details.kind() == kAccessor &&
428 15 : !EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) {
429 0 : return CopyGeneralizeAllFields("GenAll_Incompatible");
430 : }
431 : DCHECK(!tmp_map->is_deprecated());
432 52685 : target_map_ = tmp_map;
433 : }
434 :
435 24830 : state_ = kAtTargetMap;
436 24830 : return state_; // Not done yet.
437 : }
438 :
439 126144 : Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
440 : int target_nof = target_map_->NumberOfOwnDescriptors();
441 : Handle<DescriptorArray> target_descriptors(
442 24830 : target_map_->instance_descriptors(), isolate_);
443 :
444 : // Allocate a new descriptor array large enough to hold the required
445 : // descriptors, with minimally the exact same size as the old descriptor
446 : // array.
447 : int new_slack =
448 49660 : Max(old_nof_, old_descriptors_->number_of_descriptors()) - old_nof_;
449 : Handle<DescriptorArray> new_descriptors =
450 24830 : DescriptorArray::Allocate(isolate_, old_nof_, new_slack);
451 : DCHECK(new_descriptors->length() > target_descriptors->length() ||
452 : new_descriptors->NumberOfSlackDescriptors() > 0 ||
453 : new_descriptors->number_of_descriptors() ==
454 : old_descriptors_->number_of_descriptors());
455 : DCHECK(new_descriptors->number_of_descriptors() == old_nof_);
456 :
457 : int root_nof = root_map_->NumberOfOwnDescriptors();
458 :
459 : // Given that we passed root modification check in FindRootMap() so
460 : // the root descriptors are either not modified at all or already more
461 : // general than we requested. Take |root_nof| entries as is.
462 : // 0 -> |root_nof|
463 : int current_offset = 0;
464 26901 : for (int i = 0; i < root_nof; ++i) {
465 2071 : PropertyDetails old_details = old_descriptors_->GetDetails(i);
466 2071 : if (old_details.location() == kField) {
467 200 : current_offset += old_details.field_width_in_words();
468 : }
469 : Descriptor d(handle(GetKey(i), isolate_),
470 4142 : handle(old_descriptors_->GetValue(i), isolate_), old_details);
471 2071 : new_descriptors->Set(i, &d);
472 : }
473 :
474 : // Merge "updated" old_descriptor entries with target_descriptor entries.
475 : // |root_nof| -> |target_nof|
476 103419 : for (int i = root_nof; i < target_nof; ++i) {
477 103419 : Handle<Name> key(GetKey(i), isolate_);
478 103419 : PropertyDetails old_details = GetDetails(i);
479 103419 : PropertyDetails target_details = target_descriptors->GetDetails(i);
480 :
481 : PropertyKind next_kind = old_details.kind();
482 : PropertyAttributes next_attributes = old_details.attributes();
483 : DCHECK_EQ(next_kind, target_details.kind());
484 : DCHECK_EQ(next_attributes, target_details.attributes());
485 :
486 : PropertyConstness next_constness = GeneralizeConstness(
487 : old_details.constness(), target_details.constness());
488 :
489 : // Note: failed values equality check does not invalidate per-object
490 : // property constness.
491 : PropertyLocation next_location =
492 2495 : old_details.location() == kField ||
493 : target_details.location() == kField ||
494 : !EqualImmutableValues(target_descriptors->GetValue(i),
495 2460 : GetValue(i))
496 : ? kField
497 105879 : : kDescriptor;
498 :
499 103419 : if (!FLAG_track_constant_fields && next_location == kField) {
500 : next_constness = kMutable;
501 : }
502 : // Ensure that mutable values are stored in fields.
503 : DCHECK_IMPLIES(next_constness == kMutable, next_location == kField);
504 :
505 : Representation next_representation =
506 : old_details.representation().generalize(
507 103419 : target_details.representation());
508 :
509 103419 : if (next_location == kField) {
510 : Handle<FieldType> old_field_type =
511 101314 : GetOrComputeFieldType(i, old_details.location(), next_representation);
512 :
513 : Handle<FieldType> target_field_type =
514 : GetOrComputeFieldType(target_descriptors, i,
515 101314 : target_details.location(), next_representation);
516 :
517 : Handle<FieldType> next_field_type = Map::GeneralizeFieldType(
518 : old_details.representation(), old_field_type, next_representation,
519 101314 : target_field_type, isolate_);
520 :
521 : GeneralizeIfTransitionableFastElementsKind(
522 101314 : &next_constness, &next_representation, &next_field_type);
523 :
524 101314 : Handle<Object> wrapped_type(Map::WrapFieldType(next_field_type));
525 : Descriptor d;
526 101314 : if (next_kind == kData) {
527 : d = Descriptor::DataField(key, current_offset, next_attributes,
528 : next_constness, next_representation,
529 101314 : wrapped_type);
530 : } else {
531 : // TODO(ishell): mutable accessors are not implemented yet.
532 0 : UNIMPLEMENTED();
533 : }
534 101314 : current_offset += d.GetDetails().field_width_in_words();
535 101314 : new_descriptors->Set(i, &d);
536 : } else {
537 : DCHECK_EQ(kDescriptor, next_location);
538 : DCHECK_EQ(kConst, next_constness);
539 :
540 2105 : Handle<Object> value(GetValue(i), isolate_);
541 : Descriptor d;
542 2105 : if (next_kind == kData) {
543 : DCHECK(!FLAG_track_constant_fields);
544 2041 : d = Descriptor::DataConstant(key, value, next_attributes);
545 : } else {
546 : DCHECK_EQ(kAccessor, next_kind);
547 64 : d = Descriptor::AccessorConstant(key, value, next_attributes);
548 : }
549 2105 : new_descriptors->Set(i, &d);
550 : }
551 : }
552 :
553 : // Take "updated" old_descriptor entries.
554 : // |target_nof| -> |old_nof|
555 2427 : for (int i = target_nof; i < old_nof_; ++i) {
556 2427 : PropertyDetails old_details = GetDetails(i);
557 2427 : Handle<Name> key(GetKey(i), isolate_);
558 :
559 : PropertyKind next_kind = old_details.kind();
560 : PropertyAttributes next_attributes = old_details.attributes();
561 : PropertyConstness next_constness = old_details.constness();
562 : PropertyLocation next_location = old_details.location();
563 : Representation next_representation = old_details.representation();
564 :
565 : Descriptor d;
566 2427 : if (next_location == kField) {
567 : Handle<FieldType> next_field_type =
568 2188 : GetOrComputeFieldType(i, old_details.location(), next_representation);
569 :
570 : // If the |new_elements_kind_| is still transitionable then the old map's
571 : // elements kind is also transitionable and therefore the old descriptors
572 : // array must already have non in-place generalizable fields.
573 2665 : CHECK_IMPLIES(is_transitionable_fast_elements_kind_,
574 : !Map::IsInplaceGeneralizableField(
575 : next_constness, next_representation, *next_field_type));
576 :
577 2188 : Handle<Object> wrapped_type(Map::WrapFieldType(next_field_type));
578 : Descriptor d;
579 2188 : if (next_kind == kData) {
580 : DCHECK_IMPLIES(!FLAG_track_constant_fields, next_constness == kMutable);
581 : d = Descriptor::DataField(key, current_offset, next_attributes,
582 : next_constness, next_representation,
583 2188 : wrapped_type);
584 : } else {
585 : // TODO(ishell): mutable accessors are not implemented yet.
586 0 : UNIMPLEMENTED();
587 : }
588 2188 : current_offset += d.GetDetails().field_width_in_words();
589 2188 : new_descriptors->Set(i, &d);
590 : } else {
591 : DCHECK_EQ(kDescriptor, next_location);
592 : DCHECK_EQ(kConst, next_constness);
593 :
594 239 : Handle<Object> value(GetValue(i), isolate_);
595 239 : if (next_kind == kData) {
596 169 : d = Descriptor::DataConstant(key, value, next_attributes);
597 : } else {
598 : DCHECK_EQ(kAccessor, next_kind);
599 70 : d = Descriptor::AccessorConstant(key, value, next_attributes);
600 : }
601 239 : new_descriptors->Set(i, &d);
602 : }
603 : }
604 :
605 24830 : new_descriptors->Sort();
606 24830 : return new_descriptors;
607 : }
608 :
609 24830 : Handle<Map> MapUpdater::FindSplitMap(Handle<DescriptorArray> descriptors) {
610 : DisallowHeapAllocation no_allocation;
611 :
612 : int root_nof = root_map_->NumberOfOwnDescriptors();
613 : Map* current = *root_map_;
614 75564 : for (int i = root_nof; i < old_nof_; i++) {
615 : Name* name = descriptors->GetKey(i);
616 75564 : PropertyDetails details = descriptors->GetDetails(i);
617 : Map* next =
618 : TransitionsAccessor(current, &no_allocation)
619 75564 : .SearchTransition(name, details.kind(), details.attributes());
620 75564 : if (next == nullptr) break;
621 : DescriptorArray* next_descriptors = next->instance_descriptors();
622 :
623 73935 : PropertyDetails next_details = next_descriptors->GetDetails(i);
624 : DCHECK_EQ(details.kind(), next_details.kind());
625 : DCHECK_EQ(details.attributes(), next_details.attributes());
626 73935 : if (details.constness() != next_details.constness()) break;
627 64832 : if (details.location() != next_details.location()) break;
628 64832 : if (!details.representation().Equals(next_details.representation())) break;
629 :
630 50734 : if (next_details.location() == kField) {
631 49805 : FieldType* next_field_type = next_descriptors->GetFieldType(i);
632 49805 : if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
633 : break;
634 : }
635 : } else {
636 929 : if (!EqualImmutableValues(descriptors->GetValue(i),
637 : next_descriptors->GetValue(i))) {
638 : break;
639 : }
640 : }
641 : current = next;
642 : }
643 49660 : return handle(current, isolate_);
644 : }
645 :
646 24830 : MapUpdater::State MapUpdater::ConstructNewMap() {
647 24830 : Handle<DescriptorArray> new_descriptors = BuildDescriptorArray();
648 :
649 24830 : Handle<Map> split_map = FindSplitMap(new_descriptors);
650 : int split_nof = split_map->NumberOfOwnDescriptors();
651 : DCHECK_NE(old_nof_, split_nof);
652 :
653 24830 : PropertyDetails split_details = GetDetails(split_nof);
654 : TransitionsAccessor transitions(split_map);
655 :
656 : // Invalidate a transition target at |key|.
657 : Map* maybe_transition = transitions.SearchTransition(
658 24830 : GetKey(split_nof), split_details.kind(), split_details.attributes());
659 24830 : if (maybe_transition != nullptr) {
660 23201 : maybe_transition->DeprecateTransitionTree();
661 : }
662 :
663 : // If |maybe_transition| is not nullptr then the transition array already
664 : // contains entry for given descriptor. This means that the transition
665 : // could be inserted regardless of whether transitions array is full or not.
666 24830 : if (maybe_transition == nullptr && !transitions.CanHaveMoreTransitions()) {
667 5 : return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions");
668 : }
669 :
670 24825 : old_map_->NotifyLeafMapLayoutChange();
671 :
672 24825 : if (FLAG_trace_generalization && modified_descriptor_ >= 0) {
673 : PropertyDetails old_details =
674 0 : old_descriptors_->GetDetails(modified_descriptor_);
675 : PropertyDetails new_details =
676 0 : new_descriptors->GetDetails(modified_descriptor_);
677 : MaybeHandle<FieldType> old_field_type;
678 : MaybeHandle<FieldType> new_field_type;
679 : MaybeHandle<Object> old_value;
680 : MaybeHandle<Object> new_value;
681 0 : if (old_details.location() == kField) {
682 : old_field_type = handle(
683 0 : old_descriptors_->GetFieldType(modified_descriptor_), isolate_);
684 : } else {
685 : old_value =
686 0 : handle(old_descriptors_->GetValue(modified_descriptor_), isolate_);
687 : }
688 0 : if (new_details.location() == kField) {
689 : new_field_type =
690 0 : handle(new_descriptors->GetFieldType(modified_descriptor_), isolate_);
691 : } else {
692 : new_value =
693 0 : handle(new_descriptors->GetValue(modified_descriptor_), isolate_);
694 : }
695 :
696 : old_map_->PrintGeneralization(
697 : stdout, "", modified_descriptor_, split_nof, old_nof_,
698 0 : old_details.location() == kDescriptor && new_location_ == kField,
699 : old_details.representation(), new_details.representation(),
700 0 : old_field_type, old_value, new_field_type, new_value);
701 : }
702 :
703 : Handle<LayoutDescriptor> new_layout_descriptor =
704 24825 : LayoutDescriptor::New(split_map, new_descriptors, old_nof_);
705 :
706 : Handle<Map> new_map = Map::AddMissingTransitions(split_map, new_descriptors,
707 24825 : new_layout_descriptor);
708 :
709 : // Deprecated part of the transition tree is no longer reachable, so replace
710 : // current instance descriptors in the "survived" part of the tree with
711 : // the new descriptors to maintain descriptors sharing invariant.
712 24825 : split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor);
713 :
714 24825 : result_map_ = new_map;
715 24825 : state_ = kEnd;
716 24825 : return state_; // Done.
717 : }
718 :
719 : } // namespace internal
720 : } // namespace v8
|