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 3941 : 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 576125 : MapUpdater::MapUpdater(Isolate* isolate, Handle<Map> old_map)
28 : : isolate_(isolate),
29 : old_map_(old_map),
30 : old_descriptors_(old_map->instance_descriptors(), isolate_),
31 : old_nof_(old_map_->NumberOfOwnDescriptors()),
32 : new_elements_kind_(old_map_->elements_kind()),
33 : is_transitionable_fast_elements_kind_(
34 3456770 : IsTransitionableFastElementsKind(new_elements_kind_)) {
35 : // We shouldn't try to update remote objects.
36 : DCHECK(!old_map->FindRootMap(isolate)
37 : ->GetConstructor()
38 : ->IsFunctionTemplateInfo());
39 : }
40 :
41 384387 : Name MapUpdater::GetKey(int descriptor) const {
42 384387 : return old_descriptors_->GetKey(descriptor);
43 : }
44 :
45 382534 : PropertyDetails MapUpdater::GetDetails(int descriptor) const {
46 : DCHECK_LE(0, descriptor);
47 382534 : if (descriptor == modified_descriptor_) {
48 : return PropertyDetails(new_kind_, new_attributes_, new_location_,
49 278208 : new_constness_, new_representation_);
50 : }
51 243431 : return old_descriptors_->GetDetails(descriptor);
52 : }
53 :
54 5577 : Object MapUpdater::GetValue(int descriptor) const {
55 : DCHECK_LE(0, descriptor);
56 5577 : if (descriptor == modified_descriptor_) {
57 : DCHECK_EQ(kDescriptor, new_location_);
58 : return *new_value_;
59 : }
60 : DCHECK_EQ(kDescriptor, GetDetails(descriptor).location());
61 5577 : return old_descriptors_->GetStrongValue(descriptor);
62 : }
63 :
64 293201 : FieldType MapUpdater::GetFieldType(int descriptor) const {
65 : DCHECK_LE(0, descriptor);
66 293201 : if (descriptor == modified_descriptor_) {
67 : DCHECK_EQ(kField, new_location_);
68 : return *new_field_type_;
69 : }
70 : DCHECK_EQ(kField, GetDetails(descriptor).location());
71 213142 : return old_descriptors_->GetFieldType(descriptor);
72 : }
73 :
74 293553 : Handle<FieldType> MapUpdater::GetOrComputeFieldType(
75 : int descriptor, PropertyLocation location,
76 : Representation representation) const {
77 : DCHECK_LE(0, descriptor);
78 : // |location| is just a pre-fetched GetDetails(descriptor).location().
79 : DCHECK_EQ(location, GetDetails(descriptor).location());
80 293553 : if (location == kField) {
81 293201 : return handle(GetFieldType(descriptor), isolate_);
82 : } else {
83 352 : return GetValue(descriptor)->OptimalType(isolate_, representation);
84 : }
85 : }
86 :
87 347147 : Handle<FieldType> MapUpdater::GetOrComputeFieldType(
88 : Handle<DescriptorArray> descriptors, int descriptor,
89 : PropertyLocation location, Representation representation) {
90 : // |location| is just a pre-fetched GetDetails(descriptor).location().
91 : DCHECK_EQ(descriptors->GetDetails(descriptor).location(), location);
92 347147 : if (location == kField) {
93 972158 : return handle(descriptors->GetFieldType(descriptor), isolate_);
94 : } else {
95 46194 : return descriptors->GetStrongValue(descriptor)
96 46194 : ->OptimalType(isolate_, representation);
97 : }
98 : }
99 :
100 278479 : Handle<Map> MapUpdater::ReconfigureToDataField(int descriptor,
101 : PropertyAttributes attributes,
102 : PropertyConstness constness,
103 : Representation representation,
104 : Handle<FieldType> field_type) {
105 : DCHECK_EQ(kInitialized, state_);
106 : DCHECK_LE(0, descriptor);
107 : DCHECK(!old_map_->is_dictionary_map());
108 278479 : modified_descriptor_ = descriptor;
109 278479 : new_kind_ = kData;
110 278479 : new_attributes_ = attributes;
111 278479 : new_location_ = kField;
112 :
113 : PropertyDetails old_details =
114 278479 : old_descriptors_->GetDetails(modified_descriptor_);
115 :
116 : // If property kind is not reconfigured merge the result with
117 : // representation/field type from the old descriptor.
118 278480 : if (old_details.kind() == new_kind_) {
119 264602 : new_constness_ = GeneralizeConstness(constness, old_details.constness());
120 :
121 264602 : Representation old_representation = old_details.representation();
122 264602 : new_representation_ = representation.generalize(old_representation);
123 :
124 : Handle<FieldType> old_field_type =
125 : GetOrComputeFieldType(old_descriptors_, modified_descriptor_,
126 264602 : old_details.location(), new_representation_);
127 :
128 : new_field_type_ =
129 : Map::GeneralizeFieldType(old_representation, old_field_type,
130 264608 : new_representation_, field_type, isolate_);
131 : } else {
132 : // We don't know if this is a first property kind reconfiguration
133 : // and we don't know which value was in this property previously
134 : // therefore we can't treat such a property as constant.
135 13878 : new_constness_ = PropertyConstness::kMutable;
136 13878 : new_representation_ = representation;
137 13878 : new_field_type_ = field_type;
138 : }
139 :
140 : Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
141 : isolate_, old_map_->instance_type(), &new_constness_,
142 556978 : &new_representation_, &new_field_type_);
143 :
144 278484 : if (TryRecofigureToDataFieldInplace() == kEnd) return result_map_;
145 99868 : if (FindRootMap() == kEnd) return result_map_;
146 80006 : if (FindTargetMap() == kEnd) return result_map_;
147 19763 : ConstructNewMap();
148 : DCHECK_EQ(kEnd, state_);
149 19763 : return result_map_;
150 : }
151 :
152 294665 : Handle<Map> MapUpdater::ReconfigureElementsKind(ElementsKind elements_kind) {
153 : DCHECK_EQ(kInitialized, state_);
154 294665 : new_elements_kind_ = elements_kind;
155 : is_transitionable_fast_elements_kind_ =
156 294665 : IsTransitionableFastElementsKind(new_elements_kind_);
157 :
158 294665 : if (FindRootMap() == kEnd) return result_map_;
159 294665 : if (FindTargetMap() == kEnd) return result_map_;
160 808 : ConstructNewMap();
161 : DCHECK_EQ(kEnd, state_);
162 808 : return result_map_;
163 : }
164 :
165 2981 : Handle<Map> MapUpdater::Update() {
166 : DCHECK_EQ(kInitialized, state_);
167 : DCHECK(old_map_->is_deprecated());
168 :
169 2981 : if (FindRootMap() == kEnd) return result_map_;
170 2911 : if (FindTargetMap() == kEnd) return result_map_;
171 160 : ConstructNewMap();
172 : DCHECK_EQ(kEnd, state_);
173 : if (FLAG_fast_map_update) {
174 : TransitionsAccessor(isolate_, old_map_).SetMigrationTarget(*result_map_);
175 : }
176 160 : return result_map_;
177 : }
178 :
179 0 : void MapUpdater::GeneralizeField(Handle<Map> map, int modify_index,
180 : PropertyConstness new_constness,
181 : Representation new_representation,
182 : Handle<FieldType> new_field_type) {
183 : Map::GeneralizeField(isolate_, map, modify_index, new_constness,
184 387441 : new_representation, new_field_type);
185 :
186 : DCHECK_EQ(*old_descriptors_, old_map_->instance_descriptors());
187 0 : }
188 :
189 19949 : MapUpdater::State MapUpdater::CopyGeneralizeAllFields(const char* reason) {
190 : result_map_ = Map::CopyGeneralizeAllFields(
191 : isolate_, old_map_, new_elements_kind_, modified_descriptor_, new_kind_,
192 19949 : new_attributes_, reason);
193 19949 : state_ = kEnd;
194 19949 : return state_; // Done.
195 : }
196 :
197 278484 : MapUpdater::State MapUpdater::TryRecofigureToDataFieldInplace() {
198 : // If it's just a representation generalization case (i.e. property kind and
199 : // attributes stays unchanged) it's fine to transition from None to anything
200 : // but double without any modification to the object, because the default
201 : // uninitialized value for representation None can be overwritten by both
202 : // smi and tagged values. Doubles, however, would require a box allocation.
203 278484 : if (new_representation_.IsNone() || new_representation_.IsDouble()) {
204 28917 : return state_; // Not done yet.
205 : }
206 :
207 : PropertyDetails old_details =
208 499133 : old_descriptors_->GetDetails(modified_descriptor_);
209 : Representation old_representation = old_details.representation();
210 249568 : if (!old_representation.IsNone()) {
211 70951 : return state_; // Not done yet.
212 : }
213 :
214 : DCHECK_EQ(new_kind_, old_details.kind());
215 : DCHECK_EQ(new_attributes_, old_details.attributes());
216 : DCHECK_EQ(kField, old_details.location());
217 178617 : if (FLAG_trace_generalization) {
218 : old_map_->PrintGeneralization(
219 : isolate_, stdout, "uninitialized field", modified_descriptor_, old_nof_,
220 : old_nof_, false, old_representation, new_representation_,
221 : handle(old_descriptors_->GetFieldType(modified_descriptor_), isolate_),
222 0 : MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>());
223 : }
224 : Handle<Map> field_owner(
225 535850 : old_map_->FindFieldOwner(isolate_, modified_descriptor_), isolate_);
226 :
227 : GeneralizeField(field_owner, modified_descriptor_, new_constness_,
228 178617 : new_representation_, new_field_type_);
229 : // Check that the descriptor array was updated.
230 : DCHECK(old_descriptors_->GetDetails(modified_descriptor_)
231 : .representation()
232 : .Equals(new_representation_));
233 : DCHECK(old_descriptors_->GetFieldType(modified_descriptor_)
234 : ->NowIs(new_field_type_));
235 :
236 178615 : result_map_ = old_map_;
237 178615 : state_ = kEnd;
238 178615 : return state_; // Done.
239 : }
240 :
241 397513 : MapUpdater::State MapUpdater::FindRootMap() {
242 : DCHECK_EQ(kInitialized, state_);
243 : // Check the state of the root map.
244 1192537 : root_map_ = handle(old_map_->FindRootMap(isolate_), isolate_);
245 : ElementsKind from_kind = root_map_->elements_kind();
246 397512 : ElementsKind to_kind = new_elements_kind_;
247 397513 : if (root_map_->is_deprecated()) {
248 0 : state_ = kEnd;
249 : result_map_ = handle(
250 0 : JSFunction::cast(root_map_->GetConstructor())->initial_map(), isolate_);
251 0 : result_map_ = Map::AsElementsKind(isolate_, result_map_, to_kind);
252 : DCHECK(result_map_->is_dictionary_map());
253 0 : return state_;
254 : }
255 : int root_nof = root_map_->NumberOfOwnDescriptors();
256 397511 : if (!old_map_->EquivalentToForTransition(*root_map_)) {
257 93 : return CopyGeneralizeAllFields("GenAll_NotEquivalent");
258 : }
259 :
260 : // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
261 794842 : if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
262 10986 : to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
263 408213 : to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
264 : !(IsTransitionableFastElementsKind(from_kind) &&
265 5299 : IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
266 0 : return CopyGeneralizeAllFields("GenAll_InvalidElementsTransition");
267 : }
268 :
269 397421 : if (modified_descriptor_ >= 0 && modified_descriptor_ < root_nof) {
270 : PropertyDetails old_details =
271 19837 : old_descriptors_->GetDetails(modified_descriptor_);
272 25875 : if (old_details.kind() != new_kind_ ||
273 6038 : old_details.attributes() != new_attributes_) {
274 33636 : return CopyGeneralizeAllFields("GenAll_RootModification1");
275 : }
276 6038 : if (old_details.location() != kField) {
277 5255 : return CopyGeneralizeAllFields("GenAll_RootModification2");
278 : }
279 1566 : if (new_constness_ != old_details.constness() &&
280 : (!FLAG_modify_map_inplace || !old_map_->is_prototype_map())) {
281 0 : return CopyGeneralizeAllFields("GenAll_RootModification3");
282 : }
283 1566 : if (!new_representation_.fits_into(old_details.representation())) {
284 36 : return CopyGeneralizeAllFields("GenAll_RootModification4");
285 : }
286 :
287 : DCHECK_EQ(kData, old_details.kind());
288 : DCHECK_EQ(kData, new_kind_);
289 : DCHECK_EQ(kField, new_location_);
290 : FieldType old_field_type =
291 1494 : old_descriptors_->GetFieldType(modified_descriptor_);
292 747 : if (!new_field_type_->NowIs(old_field_type)) {
293 747 : return CopyGeneralizeAllFields("GenAll_RootModification5");
294 : }
295 :
296 : // Modify root map in-place.
297 : if (FLAG_modify_map_inplace && new_constness_ != old_details.constness()) {
298 : // Only prototype root maps are allowed to be updated in-place.
299 : // TODO(ishell): fix all the stubs that use prototype map check to
300 : // ensure that the prototype was not modified.
301 : DCHECK(old_map_->is_prototype_map());
302 : DCHECK(old_map_->is_stable());
303 : DCHECK(IsGeneralizableTo(old_details.constness(), new_constness_));
304 : GeneralizeField(old_map_, modified_descriptor_, new_constness_,
305 : old_details.representation(),
306 : handle(old_field_type, isolate_));
307 : }
308 : }
309 :
310 : // From here on, use the map with correct elements kind as root map.
311 377584 : root_map_ = Map::AsElementsKind(isolate_, root_map_, to_kind);
312 377581 : state_ = kAtRootMap;
313 377581 : return state_; // Not done yet.
314 : }
315 :
316 377581 : MapUpdater::State MapUpdater::FindTargetMap() {
317 : DCHECK_EQ(kAtRootMap, state_);
318 377581 : target_map_ = root_map_;
319 :
320 : int root_nof = root_map_->NumberOfOwnDescriptors();
321 587395 : for (int i = root_nof; i < old_nof_; ++i) {
322 230554 : PropertyDetails old_details = GetDetails(i);
323 : Map transition = TransitionsAccessor(isolate_, target_map_)
324 : .SearchTransition(GetKey(i), old_details.kind(),
325 230554 : old_details.attributes());
326 230558 : if (transition.is_null()) break;
327 228978 : Handle<Map> tmp_map(transition, isolate_);
328 :
329 : Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
330 686927 : isolate_);
331 :
332 : // Check if target map is incompatible.
333 228976 : PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
334 : DCHECK_EQ(old_details.kind(), tmp_details.kind());
335 : DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
336 686934 : if (old_details.kind() == kAccessor &&
337 : !EqualImmutableValues(GetValue(i),
338 229234 : tmp_descriptors->GetStrongValue(i))) {
339 : // TODO(ishell): mutable accessors are not implemented yet.
340 14 : return CopyGeneralizeAllFields("GenAll_Incompatible");
341 : }
342 : PropertyConstness tmp_constness = tmp_details.constness();
343 228964 : if (!FLAG_modify_map_inplace &&
344 : !IsGeneralizableTo(old_details.constness(), tmp_constness)) {
345 : break;
346 : }
347 220063 : if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) {
348 : break;
349 : }
350 220048 : Representation tmp_representation = tmp_details.representation();
351 440096 : if (!old_details.representation().fits_into(tmp_representation)) {
352 : break;
353 : }
354 :
355 209832 : if (tmp_details.location() == kField) {
356 : Handle<FieldType> old_field_type =
357 208827 : GetOrComputeFieldType(i, old_details.location(), tmp_representation);
358 : PropertyConstness constness =
359 : FLAG_modify_map_inplace ? old_details.constness() : tmp_constness;
360 : GeneralizeField(tmp_map, i, constness, tmp_representation,
361 : old_field_type);
362 : } else {
363 : // kDescriptor: Check that the value matches.
364 1005 : if (!EqualImmutableValues(GetValue(i),
365 2010 : tmp_descriptors->GetStrongValue(i))) {
366 : break;
367 : }
368 : }
369 : DCHECK(!tmp_map->is_deprecated());
370 209812 : target_map_ = tmp_map;
371 : }
372 :
373 : // Directly change the map if the target map is more general.
374 : int target_nof = target_map_->NumberOfOwnDescriptors();
375 377568 : if (target_nof == old_nof_) {
376 : #ifdef DEBUG
377 : if (modified_descriptor_ >= 0) {
378 : DescriptorArray target_descriptors = target_map_->instance_descriptors();
379 : PropertyDetails details =
380 : target_descriptors->GetDetails(modified_descriptor_);
381 : DCHECK_EQ(new_kind_, details.kind());
382 : DCHECK_EQ(new_attributes_, details.attributes());
383 : DCHECK(IsGeneralizableTo(new_constness_, details.constness()));
384 : DCHECK_EQ(new_location_, details.location());
385 : DCHECK(new_representation_.fits_into(details.representation()));
386 : if (new_location_ == kField) {
387 : DCHECK_EQ(kField, details.location());
388 : DCHECK(new_field_type_->NowIs(
389 : target_descriptors->GetFieldType(modified_descriptor_)));
390 : } else {
391 : DCHECK(details.location() == kField ||
392 : EqualImmutableValues(
393 : *new_value_,
394 : target_descriptors->GetStrongValue(modified_descriptor_)));
395 : }
396 : }
397 : #endif
398 356837 : if (*target_map_ != *old_map_) {
399 594564 : old_map_->NotifyLeafMapLayoutChange(isolate_);
400 : }
401 356837 : result_map_ = target_map_;
402 356837 : state_ = kEnd;
403 356837 : return state_; // Done.
404 : }
405 :
406 : // Find the last compatible target map in the transition tree.
407 42806 : for (int i = target_nof; i < old_nof_; ++i) {
408 44387 : PropertyDetails old_details = GetDetails(i);
409 : Map transition = TransitionsAccessor(isolate_, target_map_)
410 : .SearchTransition(GetKey(i), old_details.kind(),
411 44387 : old_details.attributes());
412 44387 : if (transition.is_null()) break;
413 42806 : Handle<Map> tmp_map(transition, isolate_);
414 : Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
415 128418 : isolate_);
416 : #ifdef DEBUG
417 : // Check that target map is compatible.
418 : PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
419 : DCHECK_EQ(old_details.kind(), tmp_details.kind());
420 : DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
421 : #endif
422 128418 : if (old_details.kind() == kAccessor &&
423 : !EqualImmutableValues(GetValue(i),
424 42836 : tmp_descriptors->GetStrongValue(i))) {
425 0 : return CopyGeneralizeAllFields("GenAll_Incompatible");
426 : }
427 : DCHECK(!tmp_map->is_deprecated());
428 42806 : target_map_ = tmp_map;
429 : }
430 :
431 20731 : state_ = kAtTargetMap;
432 20731 : return state_; // Not done yet.
433 : }
434 :
435 20731 : Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
436 : InstanceType instance_type = old_map_->instance_type();
437 : int target_nof = target_map_->NumberOfOwnDescriptors();
438 : Handle<DescriptorArray> target_descriptors(
439 62193 : target_map_->instance_descriptors(), isolate_);
440 :
441 : // Allocate a new descriptor array large enough to hold the required
442 : // descriptors, with minimally the exact same size as the old descriptor
443 : // array.
444 : int new_slack =
445 62193 : std::max<int>(old_nof_, old_descriptors_->number_of_descriptors()) -
446 20731 : old_nof_;
447 : Handle<DescriptorArray> new_descriptors =
448 20731 : DescriptorArray::Allocate(isolate_, old_nof_, new_slack);
449 : DCHECK(new_descriptors->number_of_all_descriptors() >
450 : target_descriptors->number_of_all_descriptors() ||
451 : new_descriptors->number_of_slack_descriptors() > 0 ||
452 : new_descriptors->number_of_descriptors() ==
453 : old_descriptors_->number_of_descriptors());
454 : DCHECK(new_descriptors->number_of_descriptors() == old_nof_);
455 :
456 : int root_nof = root_map_->NumberOfOwnDescriptors();
457 :
458 : // Given that we passed root modification check in FindRootMap() so
459 : // the root descriptors are either not modified at all or already more
460 : // general than we requested. Take |root_nof| entries as is.
461 : // 0 -> |root_nof|
462 : int current_offset = 0;
463 22585 : for (int i = 0; i < root_nof; ++i) {
464 1854 : PropertyDetails old_details = old_descriptors_->GetDetails(i);
465 1854 : if (old_details.location() == kField) {
466 163 : current_offset += old_details.field_width_in_words();
467 : }
468 : Descriptor d(handle(GetKey(i), isolate_),
469 : MaybeObjectHandle(old_descriptors_->GetValue(i), isolate_),
470 7416 : old_details);
471 1854 : new_descriptors->Set(i, &d);
472 : }
473 :
474 : // Merge "updated" old_descriptor entries with target_descriptor entries.
475 : // |root_nof| -> |target_nof|
476 84470 : for (int i = root_nof; i < target_nof; ++i) {
477 84470 : Handle<Name> key(GetKey(i), isolate_);
478 84470 : PropertyDetails old_details = GetDetails(i);
479 84470 : 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 1951 : old_details.location() == kField ||
493 : target_details.location() == kField ||
494 : !EqualImmutableValues(target_descriptors->GetStrongValue(i),
495 90296 : GetValue(i))
496 : ? kField
497 168940 : : kDescriptor;
498 :
499 84470 : if (!FLAG_track_constant_fields && next_location == kField) {
500 : next_constness = PropertyConstness::kMutable;
501 : }
502 : // Ensure that mutable values are stored in fields.
503 : DCHECK_IMPLIES(next_constness == PropertyConstness::kMutable,
504 : next_location == kField);
505 :
506 : Representation next_representation =
507 : old_details.representation().generalize(
508 84470 : target_details.representation());
509 :
510 84470 : if (next_location == kField) {
511 : Handle<FieldType> old_field_type =
512 82547 : GetOrComputeFieldType(i, old_details.location(), next_representation);
513 :
514 : Handle<FieldType> target_field_type =
515 : GetOrComputeFieldType(target_descriptors, i,
516 82547 : target_details.location(), next_representation);
517 :
518 : Handle<FieldType> next_field_type = Map::GeneralizeFieldType(
519 : old_details.representation(), old_field_type, next_representation,
520 82547 : target_field_type, isolate_);
521 :
522 : Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
523 : isolate_, instance_type, &next_constness, &next_representation,
524 82547 : &next_field_type);
525 :
526 : MaybeObjectHandle wrapped_type(
527 82547 : Map::WrapFieldType(isolate_, next_field_type));
528 82547 : Descriptor d;
529 82547 : if (next_kind == kData) {
530 : d = Descriptor::DataField(key, current_offset, next_attributes,
531 : next_constness, next_representation,
532 82547 : wrapped_type);
533 : } else {
534 : // TODO(ishell): mutable accessors are not implemented yet.
535 0 : UNIMPLEMENTED();
536 : }
537 82547 : current_offset += d.GetDetails().field_width_in_words();
538 82547 : new_descriptors->Set(i, &d);
539 : } else {
540 : DCHECK_EQ(kDescriptor, next_location);
541 : DCHECK_EQ(PropertyConstness::kConst, next_constness);
542 :
543 1923 : Handle<Object> value(GetValue(i), isolate_);
544 1923 : Descriptor d;
545 1923 : if (next_kind == kData) {
546 : DCHECK(!FLAG_track_constant_fields);
547 1861 : d = Descriptor::DataConstant(key, value, next_attributes);
548 : } else {
549 : DCHECK_EQ(kAccessor, next_kind);
550 62 : d = Descriptor::AccessorConstant(key, value, next_attributes);
551 : }
552 1923 : new_descriptors->Set(i, &d);
553 : }
554 : }
555 :
556 : // Take "updated" old_descriptor entries.
557 : // |target_nof| -> |old_nof|
558 2391 : for (int i = target_nof; i < old_nof_; ++i) {
559 2391 : PropertyDetails old_details = GetDetails(i);
560 2391 : Handle<Name> key(GetKey(i), isolate_);
561 :
562 : PropertyKind next_kind = old_details.kind();
563 : PropertyAttributes next_attributes = old_details.attributes();
564 : PropertyConstness next_constness = old_details.constness();
565 : PropertyLocation next_location = old_details.location();
566 : Representation next_representation = old_details.representation();
567 :
568 2391 : Descriptor d;
569 2391 : if (next_location == kField) {
570 : Handle<FieldType> next_field_type =
571 2179 : GetOrComputeFieldType(i, old_details.location(), next_representation);
572 :
573 : // If the |new_elements_kind_| is still transitionable then the old map's
574 : // elements kind is also transitionable and therefore the old descriptors
575 : // array must already have non in-place generalizable fields.
576 2553 : CHECK_IMPLIES(is_transitionable_fast_elements_kind_,
577 : !Map::IsInplaceGeneralizableField(
578 : next_constness, next_representation, *next_field_type));
579 :
580 : MaybeObjectHandle wrapped_type(
581 2179 : Map::WrapFieldType(isolate_, next_field_type));
582 2179 : Descriptor d;
583 2179 : if (next_kind == kData) {
584 : DCHECK_IMPLIES(!FLAG_track_constant_fields,
585 : next_constness == PropertyConstness::kMutable);
586 : d = Descriptor::DataField(key, current_offset, next_attributes,
587 : next_constness, next_representation,
588 2179 : wrapped_type);
589 : } else {
590 : // TODO(ishell): mutable accessors are not implemented yet.
591 0 : UNIMPLEMENTED();
592 : }
593 2179 : current_offset += d.GetDetails().field_width_in_words();
594 2179 : new_descriptors->Set(i, &d);
595 : } else {
596 : DCHECK_EQ(kDescriptor, next_location);
597 : DCHECK_EQ(PropertyConstness::kConst, next_constness);
598 :
599 212 : Handle<Object> value(GetValue(i), isolate_);
600 212 : if (next_kind == kData) {
601 144 : d = Descriptor::DataConstant(key, value, next_attributes);
602 : } else {
603 : DCHECK_EQ(kAccessor, next_kind);
604 68 : d = Descriptor::AccessorConstant(key, value, next_attributes);
605 : }
606 212 : new_descriptors->Set(i, &d);
607 : }
608 : }
609 :
610 20731 : new_descriptors->Sort();
611 20731 : return new_descriptors;
612 : }
613 :
614 20731 : Handle<Map> MapUpdater::FindSplitMap(Handle<DescriptorArray> descriptors) {
615 : DisallowHeapAllocation no_allocation;
616 :
617 : int root_nof = root_map_->NumberOfOwnDescriptors();
618 : Map current = *root_map_;
619 62395 : for (int i = root_nof; i < old_nof_; i++) {
620 62395 : Name name = descriptors->GetKey(i);
621 62395 : PropertyDetails details = descriptors->GetDetails(i);
622 : Map next =
623 : TransitionsAccessor(isolate_, current, &no_allocation)
624 124790 : .SearchTransition(name, details.kind(), details.attributes());
625 62395 : if (next.is_null()) break;
626 60814 : DescriptorArray next_descriptors = next->instance_descriptors();
627 :
628 60814 : PropertyDetails next_details = next_descriptors->GetDetails(i);
629 : DCHECK_EQ(details.kind(), next_details.kind());
630 : DCHECK_EQ(details.attributes(), next_details.attributes());
631 60814 : if (details.constness() != next_details.constness()) break;
632 51879 : if (details.location() != next_details.location()) break;
633 51879 : if (!details.representation().Equals(next_details.representation())) break;
634 :
635 41664 : if (next_details.location() == kField) {
636 40813 : FieldType next_field_type = next_descriptors->GetFieldType(i);
637 40813 : if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
638 : break;
639 : }
640 : } else {
641 851 : if (!EqualImmutableValues(descriptors->GetStrongValue(i),
642 2553 : next_descriptors->GetStrongValue(i))) {
643 : break;
644 : }
645 : }
646 41664 : current = next;
647 : }
648 41462 : return handle(current, isolate_);
649 : }
650 :
651 20731 : MapUpdater::State MapUpdater::ConstructNewMap() {
652 20731 : Handle<DescriptorArray> new_descriptors = BuildDescriptorArray();
653 :
654 20731 : Handle<Map> split_map = FindSplitMap(new_descriptors);
655 : int split_nof = split_map->NumberOfOwnDescriptors();
656 : DCHECK_NE(old_nof_, split_nof);
657 :
658 20731 : PropertyDetails split_details = GetDetails(split_nof);
659 20731 : TransitionsAccessor transitions(isolate_, split_map);
660 :
661 : // Invalidate a transition target at |key|.
662 : Map maybe_transition = transitions.SearchTransition(
663 20731 : GetKey(split_nof), split_details.kind(), split_details.attributes());
664 20731 : if (!maybe_transition.is_null()) {
665 19150 : maybe_transition->DeprecateTransitionTree(isolate_);
666 : }
667 :
668 : // If |maybe_transition| is not nullptr then the transition array already
669 : // contains entry for given descriptor. This means that the transition
670 : // could be inserted regardless of whether transitions array is full or not.
671 20731 : if (maybe_transition.is_null() && !transitions.CanHaveMoreTransitions()) {
672 5 : return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions");
673 : }
674 :
675 41452 : old_map_->NotifyLeafMapLayoutChange(isolate_);
676 :
677 20726 : if (FLAG_trace_generalization && modified_descriptor_ >= 0) {
678 : PropertyDetails old_details =
679 0 : old_descriptors_->GetDetails(modified_descriptor_);
680 : PropertyDetails new_details =
681 0 : new_descriptors->GetDetails(modified_descriptor_);
682 0 : MaybeHandle<FieldType> old_field_type;
683 0 : MaybeHandle<FieldType> new_field_type;
684 0 : MaybeHandle<Object> old_value;
685 0 : MaybeHandle<Object> new_value;
686 0 : if (old_details.location() == kField) {
687 : old_field_type = handle(
688 0 : old_descriptors_->GetFieldType(modified_descriptor_), isolate_);
689 : } else {
690 : old_value = handle(old_descriptors_->GetStrongValue(modified_descriptor_),
691 0 : isolate_);
692 : }
693 0 : if (new_details.location() == kField) {
694 : new_field_type =
695 0 : handle(new_descriptors->GetFieldType(modified_descriptor_), isolate_);
696 : } else {
697 : new_value = handle(new_descriptors->GetStrongValue(modified_descriptor_),
698 0 : isolate_);
699 : }
700 :
701 : old_map_->PrintGeneralization(
702 : isolate_, stdout, "", modified_descriptor_, split_nof, old_nof_,
703 0 : old_details.location() == kDescriptor && new_location_ == kField,
704 : old_details.representation(), new_details.representation(),
705 0 : old_field_type, old_value, new_field_type, new_value);
706 : }
707 :
708 : Handle<LayoutDescriptor> new_layout_descriptor =
709 20726 : LayoutDescriptor::New(isolate_, split_map, new_descriptors, old_nof_);
710 :
711 : Handle<Map> new_map = Map::AddMissingTransitions(
712 20726 : isolate_, split_map, new_descriptors, new_layout_descriptor);
713 :
714 : // Deprecated part of the transition tree is no longer reachable, so replace
715 : // current instance descriptors in the "survived" part of the tree with
716 : // the new descriptors to maintain descriptors sharing invariant.
717 : split_map->ReplaceDescriptors(isolate_, *new_descriptors,
718 41452 : *new_layout_descriptor);
719 :
720 20726 : result_map_ = new_map;
721 20726 : state_ = kEnd;
722 20726 : return state_; // Done.
723 : }
724 :
725 : } // namespace internal
726 183867 : } // namespace v8
|