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 32387 : 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 1447341 : Name* MapUpdater::GetKey(int descriptor) const {
28 1447341 : return old_descriptors_->GetKey(descriptor);
29 : }
30 :
31 1442253 : PropertyDetails MapUpdater::GetDetails(int descriptor) const {
32 : DCHECK_LE(0, descriptor);
33 1442253 : if (descriptor == modified_descriptor_) {
34 : return PropertyDetails(new_kind_, new_attributes_, new_location_,
35 1646126 : new_constness_, new_representation_);
36 : }
37 619190 : return old_descriptors_->GetDetails(descriptor);
38 : }
39 :
40 50260 : Object* MapUpdater::GetValue(int descriptor) const {
41 : DCHECK_LE(0, descriptor);
42 50260 : if (descriptor == modified_descriptor_) {
43 : DCHECK_EQ(kDescriptor, new_location_);
44 0 : return *new_value_;
45 : }
46 : DCHECK_EQ(kDescriptor, GetDetails(descriptor).location());
47 50260 : return old_descriptors_->GetValue(descriptor);
48 : }
49 :
50 839454 : FieldType* MapUpdater::GetFieldType(int descriptor) const {
51 : DCHECK_LE(0, descriptor);
52 839454 : if (descriptor == modified_descriptor_) {
53 : DCHECK_EQ(kField, new_location_);
54 324850 : return *new_field_type_;
55 : }
56 : DCHECK_EQ(kField, GetDetails(descriptor).location());
57 514604 : return old_descriptors_->GetFieldType(descriptor);
58 : }
59 :
60 840736 : 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 840736 : if (location == kField) {
67 839454 : return handle(GetFieldType(descriptor), isolate_);
68 : } else {
69 1282 : return GetValue(descriptor)->OptimalType(isolate_, representation);
70 : }
71 : }
72 :
73 1531325 : 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 1531325 : if (location == kField) {
79 1651906 : return handle(descriptors->GetFieldType(descriptor), isolate_);
80 : } else {
81 : return descriptors->GetValue(descriptor)
82 1410744 : ->OptimalType(isolate_, representation);
83 : }
84 : }
85 :
86 1183448 : Handle<Map> MapUpdater::ReconfigureToDataField(int descriptor,
87 : PropertyAttributes attributes,
88 : PropertyConstness constness,
89 : Representation representation,
90 : Handle<FieldType> field_type) {
91 : DCHECK_EQ(kInitialized, state_);
92 : DCHECK_LE(0, descriptor);
93 : DCHECK(!old_map_->is_dictionary_map());
94 1183448 : modified_descriptor_ = descriptor;
95 1183448 : new_kind_ = kData;
96 1183448 : new_attributes_ = attributes;
97 1183448 : new_location_ = kField;
98 :
99 : PropertyDetails old_details =
100 1183448 : 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 1183448 : if (old_details.kind() == new_kind_) {
105 1160156 : new_constness_ = GeneralizeConstness(constness, old_details.constness());
106 :
107 1160156 : Representation old_representation = old_details.representation();
108 1160156 : new_representation_ = representation.generalize(old_representation);
109 :
110 : Handle<FieldType> old_field_type =
111 : GetOrComputeFieldType(old_descriptors_, modified_descriptor_,
112 1160156 : old_details.location(), new_representation_);
113 :
114 : new_field_type_ =
115 : Map::GeneralizeFieldType(old_representation, old_field_type,
116 1160156 : 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 23292 : new_constness_ = kMutable;
122 23292 : new_representation_ = representation;
123 23292 : new_field_type_ = field_type;
124 : }
125 :
126 1183448 : if (TryRecofigureToDataFieldInplace() == kEnd) return result_map_;
127 782110 : if (FindRootMap() == kEnd) return result_map_;
128 325334 : if (FindTargetMap() == kEnd) return result_map_;
129 166181 : ConstructNewMap();
130 : DCHECK_EQ(kEnd, state_);
131 166181 : return result_map_;
132 : }
133 :
134 652950 : Handle<Map> MapUpdater::ReconfigureElementsKind(ElementsKind elements_kind) {
135 : DCHECK_EQ(kInitialized, state_);
136 652950 : new_elements_kind_ = elements_kind;
137 :
138 652950 : if (FindRootMap() == kEnd) return result_map_;
139 652950 : if (FindTargetMap() == kEnd) return result_map_;
140 1092 : ConstructNewMap();
141 : DCHECK_EQ(kEnd, state_);
142 1092 : return result_map_;
143 : }
144 :
145 10342 : Handle<Map> MapUpdater::Update() {
146 : DCHECK_EQ(kInitialized, state_);
147 : DCHECK(old_map_->is_deprecated());
148 :
149 10342 : if (FindRootMap() == kEnd) return result_map_;
150 10258 : if (FindTargetMap() == kEnd) return result_map_;
151 240 : ConstructNewMap();
152 : DCHECK_EQ(kEnd, state_);
153 240 : return result_map_;
154 : }
155 :
156 0 : void MapUpdater::GeneralizeField(Handle<Map> map, int modify_index,
157 : PropertyConstness new_constness,
158 : Representation new_representation,
159 : Handle<FieldType> new_field_type) {
160 : Map::GeneralizeField(map, modify_index, new_constness, new_representation,
161 867911 : new_field_type);
162 :
163 : DCHECK_EQ(*old_descriptors_, old_map_->instance_descriptors());
164 0 : }
165 :
166 456886 : MapUpdater::State MapUpdater::CopyGeneralizeAllFields(const char* reason) {
167 : result_map_ = Map::CopyGeneralizeAllFields(old_map_, new_elements_kind_,
168 : modified_descriptor_, new_kind_,
169 456886 : new_attributes_, reason);
170 456886 : state_ = kEnd;
171 456886 : return state_; // Done.
172 : }
173 :
174 1183448 : MapUpdater::State MapUpdater::TryRecofigureToDataFieldInplace() {
175 : // If it's just a representation generalization case (i.e. property kind and
176 : // attributes stays unchanged) it's fine to transition from None to anything
177 : // but double without any modification to the object, because the default
178 : // uninitialized value for representation None can be overwritten by both
179 : // smi and tagged values. Doubles, however, would require a box allocation.
180 1183448 : if (new_representation_.IsNone() || new_representation_.IsDouble()) {
181 30082 : return state_; // Not done yet.
182 : }
183 :
184 : PropertyDetails old_details =
185 2306732 : old_descriptors_->GetDetails(modified_descriptor_);
186 : Representation old_representation = old_details.representation();
187 1153366 : if (!old_representation.IsNone()) {
188 752028 : return state_; // Not done yet.
189 : }
190 :
191 : DCHECK_EQ(new_kind_, old_details.kind());
192 : DCHECK_EQ(new_attributes_, old_details.attributes());
193 : DCHECK_EQ(kField, old_details.location());
194 401338 : if (FLAG_trace_generalization) {
195 : old_map_->PrintGeneralization(
196 : stdout, "uninitialized field", modified_descriptor_, old_nof_, old_nof_,
197 : false, old_representation, new_representation_,
198 : handle(old_descriptors_->GetFieldType(modified_descriptor_), isolate_),
199 0 : MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>());
200 : }
201 : Handle<Map> field_owner(old_map_->FindFieldOwner(modified_descriptor_),
202 802676 : isolate_);
203 :
204 : GeneralizeField(field_owner, modified_descriptor_, new_constness_,
205 401338 : new_representation_, new_field_type_);
206 : // Check that the descriptor array was updated.
207 : DCHECK(old_descriptors_->GetDetails(modified_descriptor_)
208 : .representation()
209 : .Equals(new_representation_));
210 : DCHECK(old_descriptors_->GetFieldType(modified_descriptor_)
211 : ->NowIs(new_field_type_));
212 :
213 401338 : result_map_ = old_map_;
214 401338 : state_ = kEnd;
215 401338 : return state_; // Done.
216 : }
217 :
218 1445402 : MapUpdater::State MapUpdater::FindRootMap() {
219 : DCHECK_EQ(kInitialized, state_);
220 : // Check the state of the root map.
221 4336206 : root_map_ = handle(old_map_->FindRootMap(), isolate_);
222 : ElementsKind from_kind = root_map_->elements_kind();
223 1445402 : ElementsKind to_kind = new_elements_kind_;
224 1445402 : if (root_map_->is_deprecated()) {
225 0 : state_ = kEnd;
226 : result_map_ = handle(
227 0 : JSFunction::cast(root_map_->GetConstructor())->initial_map(), isolate_);
228 0 : if (from_kind != to_kind) {
229 0 : result_map_ = Map::AsElementsKind(result_map_, to_kind);
230 : }
231 : DCHECK(result_map_->is_dictionary_map());
232 0 : return state_;
233 : }
234 : int root_nof = root_map_->NumberOfOwnDescriptors();
235 1445402 : if (!old_map_->EquivalentToForTransition(*root_map_)) {
236 120 : return CopyGeneralizeAllFields("GenAll_NotEquivalent");
237 : }
238 :
239 : // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
240 2890564 : if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
241 379970 : to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
242 1824964 : to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
243 : !(IsTransitionableFastElementsKind(from_kind) &&
244 189697 : IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
245 0 : return CopyGeneralizeAllFields("GenAll_InvalidElementsTransition");
246 : }
247 :
248 1445282 : if (modified_descriptor_ >= 0 && modified_descriptor_ < root_nof) {
249 : PropertyDetails old_details =
250 457298 : old_descriptors_->GetDetails(modified_descriptor_);
251 891408 : if (old_details.kind() != new_kind_ ||
252 434110 : old_details.attributes() != new_attributes_) {
253 23188 : return CopyGeneralizeAllFields("GenAll_RootModification1");
254 : }
255 434110 : if (old_details.location() != kField) {
256 432388 : return CopyGeneralizeAllFields("GenAll_RootModification2");
257 : }
258 3444 : if (new_constness_ != old_details.constness() &&
259 : (!FLAG_modify_map_inplace || !old_map_->is_prototype_map())) {
260 0 : return CopyGeneralizeAllFields("GenAll_RootModification3");
261 : }
262 3444 : if (!new_representation_.fits_into(old_details.representation())) {
263 30 : return CopyGeneralizeAllFields("GenAll_RootModification4");
264 : }
265 :
266 : DCHECK_EQ(kData, old_details.kind());
267 : DCHECK_EQ(kData, new_kind_);
268 : DCHECK_EQ(kField, new_location_);
269 : FieldType* old_field_type =
270 3384 : old_descriptors_->GetFieldType(modified_descriptor_);
271 1692 : if (!new_field_type_->NowIs(old_field_type)) {
272 1134 : return CopyGeneralizeAllFields("GenAll_RootModification5");
273 : }
274 :
275 : // Modify root map in-place.
276 : if (FLAG_modify_map_inplace && new_constness_ != old_details.constness()) {
277 : // Only prototype root maps are allowed to be updated in-place.
278 : // TODO(ishell): fix all the stubs that use prototype map check to
279 : // ensure that the prototype was not modified.
280 : DCHECK(old_map_->is_prototype_map());
281 : DCHECK(old_map_->is_stable());
282 : DCHECK(IsGeneralizableTo(old_details.constness(), new_constness_));
283 : GeneralizeField(old_map_, modified_descriptor_, new_constness_,
284 : old_details.representation(),
285 : handle(old_field_type, isolate_));
286 : }
287 : }
288 :
289 : // From here on, use the map with correct elements kind as root map.
290 988542 : if (from_kind != to_kind) {
291 653956 : root_map_ = Map::AsElementsKind(root_map_, to_kind);
292 : }
293 988542 : state_ = kAtRootMap;
294 988542 : return state_; // Not done yet.
295 : }
296 :
297 988542 : MapUpdater::State MapUpdater::FindTargetMap() {
298 : DCHECK_EQ(kAtRootMap, state_);
299 988542 : target_map_ = root_map_;
300 :
301 : int root_nof = root_map_->NumberOfOwnDescriptors();
302 1460676 : for (int i = root_nof; i < old_nof_; ++i) {
303 639667 : PropertyDetails old_details = GetDetails(i);
304 : Map* transition = TransitionArray::SearchTransition(
305 1279334 : *target_map_, old_details.kind(), GetKey(i), old_details.attributes());
306 639667 : if (transition == NULL) break;
307 637450 : Handle<Map> tmp_map(transition, isolate_);
308 :
309 : Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
310 637450 : isolate_);
311 :
312 : // Check if target map is incompatible.
313 637450 : PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
314 : DCHECK_EQ(old_details.kind(), tmp_details.kind());
315 : DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
316 637628 : if (old_details.kind() == kAccessor &&
317 178 : !EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) {
318 : // TODO(ishell): mutable accessors are not implemented yet.
319 20 : return CopyGeneralizeAllFields("GenAll_Incompatible");
320 : }
321 : PropertyConstness tmp_constness = tmp_details.constness();
322 637430 : if (!FLAG_modify_map_inplace &&
323 : !IsGeneralizableTo(old_details.constness(), tmp_constness)) {
324 : break;
325 : }
326 501000 : if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) {
327 : break;
328 : }
329 500980 : Representation tmp_representation = tmp_details.representation();
330 1001960 : if (!old_details.representation().fits_into(tmp_representation)) {
331 : break;
332 : }
333 :
334 472161 : if (tmp_details.location() == kField) {
335 : Handle<FieldType> old_field_type =
336 466573 : GetOrComputeFieldType(i, old_details.location(), tmp_representation);
337 : PropertyConstness constness =
338 : FLAG_modify_map_inplace ? old_details.constness() : tmp_constness;
339 : GeneralizeField(tmp_map, i, constness, tmp_representation,
340 : old_field_type);
341 : } else {
342 : // kDescriptor: Check that the value matches.
343 11176 : if (!EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) {
344 : break;
345 : }
346 : }
347 : DCHECK(!tmp_map->is_deprecated());
348 472134 : target_map_ = tmp_map;
349 : }
350 :
351 : // Directly change the map if the target map is more general.
352 : int target_nof = target_map_->NumberOfOwnDescriptors();
353 988522 : if (target_nof == old_nof_) {
354 : #ifdef DEBUG
355 : if (modified_descriptor_ >= 0) {
356 : DescriptorArray* target_descriptors = target_map_->instance_descriptors();
357 : PropertyDetails details =
358 : target_descriptors->GetDetails(modified_descriptor_);
359 : DCHECK_EQ(new_kind_, details.kind());
360 : DCHECK_EQ(new_attributes_, details.attributes());
361 : DCHECK(IsGeneralizableTo(new_constness_, details.constness()));
362 : DCHECK_EQ(new_location_, details.location());
363 : DCHECK(new_representation_.fits_into(details.representation()));
364 : if (new_location_ == kField) {
365 : DCHECK_EQ(kField, details.location());
366 : DCHECK(new_field_type_->NowIs(
367 : target_descriptors->GetFieldType(modified_descriptor_)));
368 : } else {
369 : DCHECK(details.location() == kField ||
370 : EqualImmutableValues(*new_value_, target_descriptors->GetValue(
371 : modified_descriptor_)));
372 : }
373 : }
374 : #endif
375 821009 : if (*target_map_ != *old_map_) {
376 662877 : old_map_->NotifyLeafMapLayoutChange();
377 : }
378 821009 : result_map_ = target_map_;
379 821009 : state_ = kEnd;
380 821009 : return state_; // Done.
381 : }
382 :
383 : // Find the last compatible target map in the transition tree.
384 237064 : for (int i = target_nof; i < old_nof_; ++i) {
385 239281 : PropertyDetails old_details = GetDetails(i);
386 : Map* transition = TransitionArray::SearchTransition(
387 478562 : *target_map_, old_details.kind(), GetKey(i), old_details.attributes());
388 239281 : if (transition == NULL) break;
389 237064 : Handle<Map> tmp_map(transition, isolate_);
390 : Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
391 237064 : isolate_);
392 : #ifdef DEBUG
393 : // Check that target map is compatible.
394 : PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
395 : DCHECK_EQ(old_details.kind(), tmp_details.kind());
396 : DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
397 : #endif
398 237096 : if (old_details.kind() == kAccessor &&
399 32 : !EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) {
400 0 : return CopyGeneralizeAllFields("GenAll_Incompatible");
401 : }
402 : DCHECK(!tmp_map->is_deprecated());
403 237064 : target_map_ = tmp_map;
404 : }
405 :
406 167513 : state_ = kAtTargetMap;
407 167513 : return state_; // Not done yet.
408 : }
409 :
410 167513 : Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
411 : int target_nof = target_map_->NumberOfOwnDescriptors();
412 : Handle<DescriptorArray> target_descriptors(
413 167513 : target_map_->instance_descriptors(), isolate_);
414 :
415 : // Allocate a new descriptor array large enough to hold the required
416 : // descriptors, with minimally the exact same size as the old descriptor
417 : // array.
418 : int new_slack =
419 335026 : Max(old_nof_, old_descriptors_->number_of_descriptors()) - old_nof_;
420 : Handle<DescriptorArray> new_descriptors =
421 167513 : DescriptorArray::Allocate(isolate_, old_nof_, new_slack);
422 : DCHECK(new_descriptors->length() > target_descriptors->length() ||
423 : new_descriptors->NumberOfSlackDescriptors() > 0 ||
424 : new_descriptors->number_of_descriptors() ==
425 : old_descriptors_->number_of_descriptors());
426 : DCHECK(new_descriptors->number_of_descriptors() == old_nof_);
427 :
428 : int root_nof = root_map_->NumberOfOwnDescriptors();
429 :
430 : // Given that we passed root modification check in FindRootMap() so
431 : // the root descriptors are either not modified at all or already more
432 : // general than we requested. Take |root_nof| entries as is.
433 : // 0 -> |root_nof|
434 : int current_offset = 0;
435 172601 : for (int i = 0; i < root_nof; ++i) {
436 5088 : PropertyDetails old_details = old_descriptors_->GetDetails(i);
437 5088 : if (old_details.location() == kField) {
438 330 : current_offset += old_details.field_width_in_words();
439 : }
440 : Descriptor d(handle(GetKey(i), isolate_),
441 10176 : handle(old_descriptors_->GetValue(i), isolate_), old_details);
442 5088 : new_descriptors->Set(i, &d);
443 : }
444 :
445 : // Merge "updated" old_descriptor entries with target_descriptor entries.
446 : // |root_nof| -> |target_nof|
447 392621 : for (int i = root_nof; i < target_nof; ++i) {
448 392621 : Handle<Name> key(GetKey(i), isolate_);
449 392621 : PropertyDetails old_details = GetDetails(i);
450 392621 : PropertyDetails target_details = target_descriptors->GetDetails(i);
451 :
452 : PropertyKind next_kind = old_details.kind();
453 : PropertyAttributes next_attributes = old_details.attributes();
454 : DCHECK_EQ(next_kind, target_details.kind());
455 : DCHECK_EQ(next_attributes, target_details.attributes());
456 :
457 : PropertyConstness next_constness = GeneralizeConstness(
458 : old_details.constness(), target_details.constness());
459 :
460 : // Note: failed values equality check does not invalidate per-object
461 : // property constness.
462 : PropertyLocation next_location =
463 21572 : old_details.location() == kField ||
464 : target_details.location() == kField ||
465 : !EqualImmutableValues(target_descriptors->GetValue(i),
466 21551 : GetValue(i))
467 : ? kField
468 414172 : : kDescriptor;
469 :
470 392621 : if (!FLAG_track_constant_fields && next_location == kField) {
471 : next_constness = kMutable;
472 : }
473 : // Ensure that mutable values are stored in fields.
474 : DCHECK_IMPLIES(next_constness == kMutable, next_location == kField);
475 :
476 : Representation next_representation =
477 : old_details.representation().generalize(
478 392621 : target_details.representation());
479 :
480 392621 : if (next_location == kField) {
481 : Handle<FieldType> old_field_type =
482 371169 : GetOrComputeFieldType(i, old_details.location(), next_representation);
483 :
484 : Handle<FieldType> target_field_type =
485 : GetOrComputeFieldType(target_descriptors, i,
486 371169 : target_details.location(), next_representation);
487 :
488 : Handle<FieldType> next_field_type = Map::GeneralizeFieldType(
489 : old_details.representation(), old_field_type, next_representation,
490 371169 : target_field_type, isolate_);
491 :
492 371169 : Handle<Object> wrapped_type(Map::WrapFieldType(next_field_type));
493 : Descriptor d;
494 371169 : if (next_kind == kData) {
495 : d = Descriptor::DataField(key, current_offset, next_attributes,
496 : next_constness, next_representation,
497 371169 : wrapped_type);
498 : } else {
499 : // TODO(ishell): mutable accessors are not implemented yet.
500 0 : UNIMPLEMENTED();
501 : }
502 371169 : current_offset += d.GetDetails().field_width_in_words();
503 371169 : new_descriptors->Set(i, &d);
504 : } else {
505 : DCHECK_EQ(kDescriptor, next_location);
506 : DCHECK_EQ(kConst, next_constness);
507 :
508 21452 : Handle<Object> value(GetValue(i), isolate_);
509 : Descriptor d;
510 21452 : if (next_kind == kData) {
511 : DCHECK(!FLAG_track_constant_fields);
512 21352 : d = Descriptor::DataConstant(key, value, next_attributes);
513 : } else {
514 : DCHECK_EQ(kAccessor, next_kind);
515 100 : d = Descriptor::AccessorConstant(key, value, next_attributes);
516 : }
517 21452 : new_descriptors->Set(i, &d);
518 : }
519 : }
520 :
521 : // Take "updated" old_descriptor entries.
522 : // |target_nof| -> |old_nof|
523 3171 : for (int i = target_nof; i < old_nof_; ++i) {
524 3171 : PropertyDetails old_details = GetDetails(i);
525 3171 : Handle<Name> key(GetKey(i), isolate_);
526 :
527 : PropertyKind next_kind = old_details.kind();
528 : PropertyAttributes next_attributes = old_details.attributes();
529 : PropertyConstness next_constness = old_details.constness();
530 : PropertyLocation next_location = old_details.location();
531 3171 : Representation next_representation = old_details.representation();
532 :
533 : Descriptor d;
534 3171 : if (next_location == kField) {
535 : Handle<FieldType> old_field_type =
536 2994 : GetOrComputeFieldType(i, old_details.location(), next_representation);
537 :
538 2994 : Handle<Object> wrapped_type(Map::WrapFieldType(old_field_type));
539 : Descriptor d;
540 2994 : if (next_kind == kData) {
541 : DCHECK_IMPLIES(!FLAG_track_constant_fields, next_constness == kMutable);
542 : d = Descriptor::DataField(key, current_offset, next_attributes,
543 : next_constness, next_representation,
544 2994 : wrapped_type);
545 : } else {
546 : // TODO(ishell): mutable accessors are not implemented yet.
547 0 : UNIMPLEMENTED();
548 : }
549 2994 : current_offset += d.GetDetails().field_width_in_words();
550 2994 : new_descriptors->Set(i, &d);
551 : } else {
552 : DCHECK_EQ(kDescriptor, next_location);
553 : DCHECK_EQ(kConst, next_constness);
554 :
555 177 : Handle<Object> value(GetValue(i), isolate_);
556 177 : if (next_kind == kData) {
557 71 : d = Descriptor::DataConstant(key, value, next_attributes);
558 : } else {
559 : DCHECK_EQ(kAccessor, next_kind);
560 106 : d = Descriptor::AccessorConstant(key, value, next_attributes);
561 : }
562 177 : new_descriptors->Set(i, &d);
563 : }
564 : }
565 :
566 167513 : new_descriptors->Sort();
567 167513 : return new_descriptors;
568 : }
569 :
570 167513 : Handle<Map> MapUpdater::FindSplitMap(Handle<DescriptorArray> descriptors) {
571 : DisallowHeapAllocation no_allocation;
572 :
573 : int root_nof = root_map_->NumberOfOwnDescriptors();
574 : Map* current = *root_map_;
575 323070 : for (int i = root_nof; i < old_nof_; i++) {
576 : Name* name = descriptors->GetKey(i);
577 323070 : PropertyDetails details = descriptors->GetDetails(i);
578 : Map* next = TransitionArray::SearchTransition(current, details.kind(), name,
579 323070 : details.attributes());
580 323070 : if (next == NULL) break;
581 : DescriptorArray* next_descriptors = next->instance_descriptors();
582 :
583 320853 : PropertyDetails next_details = next_descriptors->GetDetails(i);
584 : DCHECK_EQ(details.kind(), next_details.kind());
585 : DCHECK_EQ(details.attributes(), next_details.attributes());
586 320853 : if (details.constness() != next_details.constness()) break;
587 184376 : if (details.location() != next_details.location()) break;
588 184376 : if (!details.representation().Equals(next_details.representation())) break;
589 :
590 155557 : if (next_details.location() == kField) {
591 150519 : FieldType* next_field_type = next_descriptors->GetFieldType(i);
592 150519 : if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
593 : break;
594 : }
595 : } else {
596 5038 : if (!EqualImmutableValues(descriptors->GetValue(i),
597 : next_descriptors->GetValue(i))) {
598 : break;
599 : }
600 : }
601 : current = next;
602 : }
603 335026 : return handle(current, isolate_);
604 : }
605 :
606 167513 : MapUpdater::State MapUpdater::ConstructNewMap() {
607 167513 : Handle<DescriptorArray> new_descriptors = BuildDescriptorArray();
608 :
609 167513 : Handle<Map> split_map = FindSplitMap(new_descriptors);
610 : int split_nof = split_map->NumberOfOwnDescriptors();
611 : DCHECK_NE(old_nof_, split_nof);
612 :
613 167513 : PropertyDetails split_details = GetDetails(split_nof);
614 :
615 : // Invalidate a transition target at |key|.
616 : Map* maybe_transition = TransitionArray::SearchTransition(
617 : *split_map, split_details.kind(), GetKey(split_nof),
618 335026 : split_details.attributes());
619 167513 : if (maybe_transition != NULL) {
620 165296 : maybe_transition->DeprecateTransitionTree();
621 : }
622 :
623 : // If |maybe_transition| is not NULL then the transition array already
624 : // contains entry for given descriptor. This means that the transition
625 : // could be inserted regardless of whether transitions array is full or not.
626 169730 : if (maybe_transition == NULL &&
627 2217 : !TransitionArray::CanHaveMoreTransitions(split_map)) {
628 6 : return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions");
629 : }
630 :
631 167507 : old_map_->NotifyLeafMapLayoutChange();
632 :
633 167507 : if (FLAG_trace_generalization && modified_descriptor_ >= 0) {
634 : PropertyDetails old_details =
635 0 : old_descriptors_->GetDetails(modified_descriptor_);
636 : PropertyDetails new_details =
637 0 : new_descriptors->GetDetails(modified_descriptor_);
638 : MaybeHandle<FieldType> old_field_type;
639 : MaybeHandle<FieldType> new_field_type;
640 : MaybeHandle<Object> old_value;
641 : MaybeHandle<Object> new_value;
642 0 : if (old_details.location() == kField) {
643 : old_field_type = handle(
644 0 : old_descriptors_->GetFieldType(modified_descriptor_), isolate_);
645 : } else {
646 : old_value =
647 0 : handle(old_descriptors_->GetValue(modified_descriptor_), isolate_);
648 : }
649 0 : if (new_details.location() == kField) {
650 : new_field_type =
651 0 : handle(new_descriptors->GetFieldType(modified_descriptor_), isolate_);
652 : } else {
653 : new_value =
654 0 : handle(new_descriptors->GetValue(modified_descriptor_), isolate_);
655 : }
656 :
657 : old_map_->PrintGeneralization(
658 : stdout, "", modified_descriptor_, split_nof, old_nof_,
659 0 : old_details.location() == kDescriptor && new_location_ == kField,
660 : old_details.representation(), new_details.representation(),
661 0 : old_field_type, old_value, new_field_type, new_value);
662 : }
663 :
664 : Handle<LayoutDescriptor> new_layout_descriptor =
665 167507 : LayoutDescriptor::New(split_map, new_descriptors, old_nof_);
666 :
667 : Handle<Map> new_map = Map::AddMissingTransitions(split_map, new_descriptors,
668 167507 : new_layout_descriptor);
669 :
670 : // Deprecated part of the transition tree is no longer reachable, so replace
671 : // current instance descriptors in the "survived" part of the tree with
672 : // the new descriptors to maintain descriptors sharing invariant.
673 167507 : split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor);
674 :
675 167507 : result_map_ = new_map;
676 167507 : state_ = kEnd;
677 167507 : return state_; // Done.
678 : }
679 :
680 : } // namespace internal
681 : } // namespace v8
|