V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
map-updater.cc
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  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 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  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 Name MapUpdater::GetKey(int descriptor) const {
42  return old_descriptors_->GetKey(descriptor);
43 }
44 
45 PropertyDetails MapUpdater::GetDetails(int descriptor) const {
46  DCHECK_LE(0, descriptor);
47  if (descriptor == modified_descriptor_) {
48  return PropertyDetails(new_kind_, new_attributes_, new_location_,
49  new_constness_, new_representation_);
50  }
51  return old_descriptors_->GetDetails(descriptor);
52 }
53 
54 Object* MapUpdater::GetValue(int descriptor) const {
55  DCHECK_LE(0, descriptor);
56  if (descriptor == modified_descriptor_) {
57  DCHECK_EQ(kDescriptor, new_location_);
58  return *new_value_;
59  }
60  DCHECK_EQ(kDescriptor, GetDetails(descriptor).location());
61  return old_descriptors_->GetStrongValue(descriptor);
62 }
63 
64 FieldType MapUpdater::GetFieldType(int descriptor) const {
65  DCHECK_LE(0, descriptor);
66  if (descriptor == modified_descriptor_) {
67  DCHECK_EQ(kField, new_location_);
68  return *new_field_type_;
69  }
70  DCHECK_EQ(kField, GetDetails(descriptor).location());
71  return old_descriptors_->GetFieldType(descriptor);
72 }
73 
74 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  if (location == kField) {
81  return handle(GetFieldType(descriptor), isolate_);
82  } else {
83  return GetValue(descriptor)->OptimalType(isolate_, representation);
84  }
85 }
86 
87 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  if (location == kField) {
93  return handle(descriptors->GetFieldType(descriptor), isolate_);
94  } else {
95  return descriptors->GetStrongValue(descriptor)
96  ->OptimalType(isolate_, representation);
97  }
98 }
99 
100 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  modified_descriptor_ = descriptor;
109  new_kind_ = kData;
110  new_attributes_ = attributes;
111  new_location_ = kField;
112 
113  PropertyDetails old_details =
114  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  if (old_details.kind() == new_kind_) {
119  new_constness_ = GeneralizeConstness(constness, old_details.constness());
120 
121  Representation old_representation = old_details.representation();
122  new_representation_ = representation.generalize(old_representation);
123 
124  Handle<FieldType> old_field_type =
125  GetOrComputeFieldType(old_descriptors_, modified_descriptor_,
126  old_details.location(), new_representation_);
127 
128  new_field_type_ =
129  Map::GeneralizeFieldType(old_representation, old_field_type,
130  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  new_constness_ = PropertyConstness::kMutable;
136  new_representation_ = representation;
137  new_field_type_ = field_type;
138  }
139 
140  Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
141  isolate_, old_map_->instance_type(), &new_constness_,
142  &new_representation_, &new_field_type_);
143 
144  if (TryRecofigureToDataFieldInplace() == kEnd) return result_map_;
145  if (FindRootMap() == kEnd) return result_map_;
146  if (FindTargetMap() == kEnd) return result_map_;
147  ConstructNewMap();
148  DCHECK_EQ(kEnd, state_);
149  return result_map_;
150 }
151 
152 Handle<Map> MapUpdater::ReconfigureElementsKind(ElementsKind elements_kind) {
153  DCHECK_EQ(kInitialized, state_);
154  new_elements_kind_ = elements_kind;
155  is_transitionable_fast_elements_kind_ =
156  IsTransitionableFastElementsKind(new_elements_kind_);
157 
158  if (FindRootMap() == kEnd) return result_map_;
159  if (FindTargetMap() == kEnd) return result_map_;
160  ConstructNewMap();
161  DCHECK_EQ(kEnd, state_);
162  return result_map_;
163 }
164 
165 Handle<Map> MapUpdater::Update() {
166  DCHECK_EQ(kInitialized, state_);
167  DCHECK(old_map_->is_deprecated());
168 
169  if (FindRootMap() == kEnd) return result_map_;
170  if (FindTargetMap() == kEnd) return result_map_;
171  ConstructNewMap();
172  DCHECK_EQ(kEnd, state_);
173  if (FLAG_fast_map_update) {
174  TransitionsAccessor(isolate_, old_map_).SetMigrationTarget(*result_map_);
175  }
176  return result_map_;
177 }
178 
179 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  new_representation, new_field_type);
185 
186  DCHECK_EQ(*old_descriptors_, old_map_->instance_descriptors());
187 }
188 
189 MapUpdater::State MapUpdater::CopyGeneralizeAllFields(const char* reason) {
190  result_map_ = Map::CopyGeneralizeAllFields(
191  isolate_, old_map_, new_elements_kind_, modified_descriptor_, new_kind_,
192  new_attributes_, reason);
193  state_ = kEnd;
194  return state_; // Done.
195 }
196 
197 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  if (new_representation_.IsNone() || new_representation_.IsDouble()) {
204  return state_; // Not done yet.
205  }
206 
207  PropertyDetails old_details =
208  old_descriptors_->GetDetails(modified_descriptor_);
209  Representation old_representation = old_details.representation();
210  if (!old_representation.IsNone()) {
211  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  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  MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>());
223  }
224  Handle<Map> field_owner(
225  old_map_->FindFieldOwner(isolate_, modified_descriptor_), isolate_);
226 
227  GeneralizeField(field_owner, modified_descriptor_, new_constness_,
228  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  result_map_ = old_map_;
237  state_ = kEnd;
238  return state_; // Done.
239 }
240 
241 MapUpdater::State MapUpdater::FindRootMap() {
242  DCHECK_EQ(kInitialized, state_);
243  // Check the state of the root map.
244  root_map_ = handle(old_map_->FindRootMap(isolate_), isolate_);
245  ElementsKind from_kind = root_map_->elements_kind();
246  ElementsKind to_kind = new_elements_kind_;
247  if (root_map_->is_deprecated()) {
248  state_ = kEnd;
249  result_map_ = handle(
250  JSFunction::cast(root_map_->GetConstructor())->initial_map(), isolate_);
251  result_map_ = Map::AsElementsKind(isolate_, result_map_, to_kind);
252  DCHECK(result_map_->is_dictionary_map());
253  return state_;
254  }
255  int root_nof = root_map_->NumberOfOwnDescriptors();
256  if (!old_map_->EquivalentToForTransition(*root_map_)) {
257  return CopyGeneralizeAllFields("GenAll_NotEquivalent");
258  }
259 
260  // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
261  if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
262  to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
263  to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
264  !(IsTransitionableFastElementsKind(from_kind) &&
265  IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
266  return CopyGeneralizeAllFields("GenAll_InvalidElementsTransition");
267  }
268 
269  if (modified_descriptor_ >= 0 && modified_descriptor_ < root_nof) {
270  PropertyDetails old_details =
271  old_descriptors_->GetDetails(modified_descriptor_);
272  if (old_details.kind() != new_kind_ ||
273  old_details.attributes() != new_attributes_) {
274  return CopyGeneralizeAllFields("GenAll_RootModification1");
275  }
276  if (old_details.location() != kField) {
277  return CopyGeneralizeAllFields("GenAll_RootModification2");
278  }
279  if (new_constness_ != old_details.constness() &&
280  (!FLAG_modify_map_inplace || !old_map_->is_prototype_map())) {
281  return CopyGeneralizeAllFields("GenAll_RootModification3");
282  }
283  if (!new_representation_.fits_into(old_details.representation())) {
284  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  old_descriptors_->GetFieldType(modified_descriptor_);
292  if (!new_field_type_->NowIs(old_field_type)) {
293  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  root_map_ = Map::AsElementsKind(isolate_, root_map_, to_kind);
312  state_ = kAtRootMap;
313  return state_; // Not done yet.
314 }
315 
316 MapUpdater::State MapUpdater::FindTargetMap() {
317  DCHECK_EQ(kAtRootMap, state_);
318  target_map_ = root_map_;
319 
320  int root_nof = root_map_->NumberOfOwnDescriptors();
321  for (int i = root_nof; i < old_nof_; ++i) {
322  PropertyDetails old_details = GetDetails(i);
323  Map transition = TransitionsAccessor(isolate_, target_map_)
324  .SearchTransition(GetKey(i), old_details.kind(),
325  old_details.attributes());
326  if (transition.is_null()) break;
327  Handle<Map> tmp_map(transition, isolate_);
328 
329  Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
330  isolate_);
331 
332  // Check if target map is incompatible.
333  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  if (old_details.kind() == kAccessor &&
337  !EqualImmutableValues(GetValue(i),
338  tmp_descriptors->GetStrongValue(i))) {
339  // TODO(ishell): mutable accessors are not implemented yet.
340  return CopyGeneralizeAllFields("GenAll_Incompatible");
341  }
342  PropertyConstness tmp_constness = tmp_details.constness();
343  if (!FLAG_modify_map_inplace &&
344  !IsGeneralizableTo(old_details.constness(), tmp_constness)) {
345  break;
346  }
347  if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) {
348  break;
349  }
350  Representation tmp_representation = tmp_details.representation();
351  if (!old_details.representation().fits_into(tmp_representation)) {
352  break;
353  }
354 
355  if (tmp_details.location() == kField) {
356  Handle<FieldType> old_field_type =
357  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  if (!EqualImmutableValues(GetValue(i),
365  tmp_descriptors->GetStrongValue(i))) {
366  break;
367  }
368  }
369  DCHECK(!tmp_map->is_deprecated());
370  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  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  if (*target_map_ != *old_map_) {
399  old_map_->NotifyLeafMapLayoutChange(isolate_);
400  }
401  result_map_ = target_map_;
402  state_ = kEnd;
403  return state_; // Done.
404  }
405 
406  // Find the last compatible target map in the transition tree.
407  for (int i = target_nof; i < old_nof_; ++i) {
408  PropertyDetails old_details = GetDetails(i);
409  Map transition = TransitionsAccessor(isolate_, target_map_)
410  .SearchTransition(GetKey(i), old_details.kind(),
411  old_details.attributes());
412  if (transition.is_null()) break;
413  Handle<Map> tmp_map(transition, isolate_);
414  Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
415  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  if (old_details.kind() == kAccessor &&
423  !EqualImmutableValues(GetValue(i),
424  tmp_descriptors->GetStrongValue(i))) {
425  return CopyGeneralizeAllFields("GenAll_Incompatible");
426  }
427  DCHECK(!tmp_map->is_deprecated());
428  target_map_ = tmp_map;
429  }
430 
431  state_ = kAtTargetMap;
432  return state_; // Not done yet.
433 }
434 
435 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  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  std::max<int>(old_nof_, old_descriptors_->number_of_descriptors()) -
446  old_nof_;
447  Handle<DescriptorArray> new_descriptors =
448  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  for (int i = 0; i < root_nof; ++i) {
464  PropertyDetails old_details = old_descriptors_->GetDetails(i);
465  if (old_details.location() == kField) {
466  current_offset += old_details.field_width_in_words();
467  }
468  Descriptor d(handle(GetKey(i), isolate_),
469  MaybeObjectHandle(old_descriptors_->GetValue(i), isolate_),
470  old_details);
471  new_descriptors->Set(i, &d);
472  }
473 
474  // Merge "updated" old_descriptor entries with target_descriptor entries.
475  // |root_nof| -> |target_nof|
476  for (int i = root_nof; i < target_nof; ++i) {
477  Handle<Name> key(GetKey(i), isolate_);
478  PropertyDetails old_details = GetDetails(i);
479  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  old_details.location() == kField ||
493  target_details.location() == kField ||
494  !EqualImmutableValues(target_descriptors->GetStrongValue(i),
495  GetValue(i))
496  ? kField
497  : kDescriptor;
498 
499  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  target_details.representation());
509 
510  if (next_location == kField) {
511  Handle<FieldType> old_field_type =
512  GetOrComputeFieldType(i, old_details.location(), next_representation);
513 
514  Handle<FieldType> target_field_type =
515  GetOrComputeFieldType(target_descriptors, i,
516  target_details.location(), next_representation);
517 
518  Handle<FieldType> next_field_type = Map::GeneralizeFieldType(
519  old_details.representation(), old_field_type, next_representation,
520  target_field_type, isolate_);
521 
522  Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
523  isolate_, instance_type, &next_constness, &next_representation,
524  &next_field_type);
525 
526  MaybeObjectHandle wrapped_type(
527  Map::WrapFieldType(isolate_, next_field_type));
528  Descriptor d;
529  if (next_kind == kData) {
530  d = Descriptor::DataField(key, current_offset, next_attributes,
531  next_constness, next_representation,
532  wrapped_type);
533  } else {
534  // TODO(ishell): mutable accessors are not implemented yet.
535  UNIMPLEMENTED();
536  }
537  current_offset += d.GetDetails().field_width_in_words();
538  new_descriptors->Set(i, &d);
539  } else {
540  DCHECK_EQ(kDescriptor, next_location);
541  DCHECK_EQ(PropertyConstness::kConst, next_constness);
542 
543  Handle<Object> value(GetValue(i), isolate_);
544  Descriptor d;
545  if (next_kind == kData) {
546  DCHECK(!FLAG_track_constant_fields);
547  d = Descriptor::DataConstant(key, value, next_attributes);
548  } else {
549  DCHECK_EQ(kAccessor, next_kind);
550  d = Descriptor::AccessorConstant(key, value, next_attributes);
551  }
552  new_descriptors->Set(i, &d);
553  }
554  }
555 
556  // Take "updated" old_descriptor entries.
557  // |target_nof| -> |old_nof|
558  for (int i = target_nof; i < old_nof_; ++i) {
559  PropertyDetails old_details = GetDetails(i);
560  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  Descriptor d;
569  if (next_location == kField) {
570  Handle<FieldType> next_field_type =
571  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  CHECK_IMPLIES(is_transitionable_fast_elements_kind_,
577  !Map::IsInplaceGeneralizableField(
578  next_constness, next_representation, *next_field_type));
579 
580  MaybeObjectHandle wrapped_type(
581  Map::WrapFieldType(isolate_, next_field_type));
582  Descriptor d;
583  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  wrapped_type);
589  } else {
590  // TODO(ishell): mutable accessors are not implemented yet.
591  UNIMPLEMENTED();
592  }
593  current_offset += d.GetDetails().field_width_in_words();
594  new_descriptors->Set(i, &d);
595  } else {
596  DCHECK_EQ(kDescriptor, next_location);
597  DCHECK_EQ(PropertyConstness::kConst, next_constness);
598 
599  Handle<Object> value(GetValue(i), isolate_);
600  if (next_kind == kData) {
601  d = Descriptor::DataConstant(key, value, next_attributes);
602  } else {
603  DCHECK_EQ(kAccessor, next_kind);
604  d = Descriptor::AccessorConstant(key, value, next_attributes);
605  }
606  new_descriptors->Set(i, &d);
607  }
608  }
609 
610  new_descriptors->Sort();
611  return new_descriptors;
612 }
613 
614 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  for (int i = root_nof; i < old_nof_; i++) {
620  Name name = descriptors->GetKey(i);
621  PropertyDetails details = descriptors->GetDetails(i);
622  Map next =
623  TransitionsAccessor(isolate_, current, &no_allocation)
624  .SearchTransition(name, details.kind(), details.attributes());
625  if (next.is_null()) break;
626  DescriptorArray* next_descriptors = next->instance_descriptors();
627 
628  PropertyDetails next_details = next_descriptors->GetDetails(i);
629  DCHECK_EQ(details.kind(), next_details.kind());
630  DCHECK_EQ(details.attributes(), next_details.attributes());
631  if (details.constness() != next_details.constness()) break;
632  if (details.location() != next_details.location()) break;
633  if (!details.representation().Equals(next_details.representation())) break;
634 
635  if (next_details.location() == kField) {
636  FieldType next_field_type = next_descriptors->GetFieldType(i);
637  if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
638  break;
639  }
640  } else {
641  if (!EqualImmutableValues(descriptors->GetStrongValue(i),
642  next_descriptors->GetStrongValue(i))) {
643  break;
644  }
645  }
646  current = next;
647  }
648  return handle(current, isolate_);
649 }
650 
651 MapUpdater::State MapUpdater::ConstructNewMap() {
652  Handle<DescriptorArray> new_descriptors = BuildDescriptorArray();
653 
654  Handle<Map> split_map = FindSplitMap(new_descriptors);
655  int split_nof = split_map->NumberOfOwnDescriptors();
656  DCHECK_NE(old_nof_, split_nof);
657 
658  PropertyDetails split_details = GetDetails(split_nof);
659  TransitionsAccessor transitions(isolate_, split_map);
660 
661  // Invalidate a transition target at |key|.
662  Map maybe_transition = transitions.SearchTransition(
663  GetKey(split_nof), split_details.kind(), split_details.attributes());
664  if (!maybe_transition.is_null()) {
665  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  if (maybe_transition.is_null() && !transitions.CanHaveMoreTransitions()) {
672  return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions");
673  }
674 
675  old_map_->NotifyLeafMapLayoutChange(isolate_);
676 
677  if (FLAG_trace_generalization && modified_descriptor_ >= 0) {
678  PropertyDetails old_details =
679  old_descriptors_->GetDetails(modified_descriptor_);
680  PropertyDetails new_details =
681  new_descriptors->GetDetails(modified_descriptor_);
682  MaybeHandle<FieldType> old_field_type;
683  MaybeHandle<FieldType> new_field_type;
684  MaybeHandle<Object> old_value;
685  MaybeHandle<Object> new_value;
686  if (old_details.location() == kField) {
687  old_field_type = handle(
688  old_descriptors_->GetFieldType(modified_descriptor_), isolate_);
689  } else {
690  old_value = handle(old_descriptors_->GetStrongValue(modified_descriptor_),
691  isolate_);
692  }
693  if (new_details.location() == kField) {
694  new_field_type =
695  handle(new_descriptors->GetFieldType(modified_descriptor_), isolate_);
696  } else {
697  new_value = handle(new_descriptors->GetStrongValue(modified_descriptor_),
698  isolate_);
699  }
700 
701  old_map_->PrintGeneralization(
702  isolate_, stdout, "", modified_descriptor_, split_nof, old_nof_,
703  old_details.location() == kDescriptor && new_location_ == kField,
704  old_details.representation(), new_details.representation(),
705  old_field_type, old_value, new_field_type, new_value);
706  }
707 
708  Handle<LayoutDescriptor> new_layout_descriptor =
709  LayoutDescriptor::New(isolate_, split_map, new_descriptors, old_nof_);
710 
711  Handle<Map> new_map = Map::AddMissingTransitions(
712  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  *new_layout_descriptor);
719 
720  result_map_ = new_map;
721  state_ = kEnd;
722  return state_; // Done.
723 }
724 
725 } // namespace internal
726 } // namespace v8
Definition: libplatform.h:13