| // Copyright 2017 the V8 project authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef V8_OBJECTS_MAP_UPDATER_H_ | 
 | #define V8_OBJECTS_MAP_UPDATER_H_ | 
 |  | 
 | #include "src/common/globals.h" | 
 | #include "src/handles/handles.h" | 
 | #include "src/objects/elements-kind.h" | 
 | #include "src/objects/field-type.h" | 
 | #include "src/objects/map.h" | 
 | #include "src/objects/property-details.h" | 
 |  | 
 | namespace v8 { | 
 | namespace internal { | 
 |  | 
 | // The |MapUpdater| class implements all sorts of map reconfigurations | 
 | // including changes of elements kind, property attributes, property kind, | 
 | // property location and field representations/type changes. It ensures that | 
 | // the reconfigured map and all the intermediate maps are properly integrated | 
 | // into the exising transition tree. | 
 | // | 
 | // To avoid high degrees over polymorphism, and to stabilize quickly, on every | 
 | // rewrite the new type is deduced by merging the current type with any | 
 | // potential new (partial) version of the type in the transition tree. | 
 | // To do this, on each rewrite: | 
 | // - Search the root of the transition tree using FindRootMap, remember | 
 | //   the integrity level (preventExtensions/seal/freeze) transitions. | 
 | // - Find/create a |root_map| with requested |new_elements_kind|. | 
 | // - Find |target_map|, the newest matching version of this map using the | 
 | //   "updated" |old_map|'s descriptor array (i.e. whose entry at |modify_index| | 
 | //   is considered to be of |new_kind| and having |new_attributes|) to walk | 
 | //   the transition tree. If there was an integrity level transition on the path | 
 | //   to the old map, use the descriptor array of the map preceding the first | 
 | //   integrity level transition (|integrity_source_map|), and try to replay | 
 | //   the integrity level transition afterwards. | 
 | // - Merge/generalize the "updated" descriptor array of the |old_map| and | 
 | //   descriptor array of the |target_map|. | 
 | // - Generalize the |modify_index| descriptor using |new_representation| and | 
 | //   |new_field_type|. | 
 | // - Walk the tree again starting from the root towards |target_map|. Stop at | 
 | //   |split_map|, the first map who's descriptor array does not match the merged | 
 | //   descriptor array. | 
 | // - If |target_map| == |split_map|, and there are no integrity level | 
 | //   transitions, |target_map| is in the expected state. Return it. | 
 | // - Otherwise, invalidate the outdated transition target from |target_map|, and | 
 | //   replace its transition tree with a new branch for the updated descriptors. | 
 | // - If the |old_map| had integrity level transition, create the new map for it. | 
 | class MapUpdater { | 
 |  public: | 
 |   MapUpdater(Isolate* isolate, Handle<Map> old_map); | 
 |  | 
 |   // Prepares for reconfiguring of a property at |descriptor| to data field | 
 |   // with given |attributes| and |representation|/|field_type| and | 
 |   // performs the steps 1-5. | 
 |   Handle<Map> ReconfigureToDataField(InternalIndex descriptor, | 
 |                                      PropertyAttributes attributes, | 
 |                                      PropertyConstness constness, | 
 |                                      Representation representation, | 
 |                                      Handle<FieldType> field_type); | 
 |  | 
 |   // Prepares for reconfiguring elements kind and performs the steps 1-5. | 
 |   Handle<Map> ReconfigureElementsKind(ElementsKind elements_kind); | 
 |  | 
 |   // Prepares for updating deprecated map to most up-to-date non-deprecated | 
 |   // version and performs the steps 1-5. | 
 |   Handle<Map> Update(); | 
 |  | 
 |  private: | 
 |   enum State { | 
 |     kInitialized, | 
 |     kAtRootMap, | 
 |     kAtTargetMap, | 
 |     kAtIntegrityLevelSource, | 
 |     kEnd | 
 |   }; | 
 |  | 
 |   // Try to reconfigure property in-place without rebuilding transition tree | 
 |   // and creating new maps. See implementation for details. | 
 |   State TryReconfigureToDataFieldInplace(); | 
 |  | 
 |   // Step 1. | 
 |   // - Search the root of the transition tree using FindRootMap. | 
 |   // - Find/create a |root_map_| with requested |new_elements_kind_|. | 
 |   State FindRootMap(); | 
 |  | 
 |   // Step 2. | 
 |   // - Find |target_map|, the newest matching version of this map using the | 
 |   //   "updated" |old_map|'s descriptor array (i.e. whose entry at | 
 |   //   |modify_index| is considered to be of |new_kind| and having | 
 |   //   |new_attributes|) to walk the transition tree. If there was an integrity | 
 |   //   level transition on the path to the old map, use the descriptor array | 
 |   //   of the map preceding the first integrity level transition | 
 |   //   (|integrity_source_map|), and try to replay the integrity level | 
 |   //   transition afterwards. | 
 |   State FindTargetMap(); | 
 |  | 
 |   // Step 3. | 
 |   // - Merge/generalize the "updated" descriptor array of the |old_map_| and | 
 |   //   descriptor array of the |target_map_|. | 
 |   // - Generalize the |modified_descriptor_| using |new_representation| and | 
 |   //   |new_field_type_|. | 
 |   Handle<DescriptorArray> BuildDescriptorArray(); | 
 |  | 
 |   // Step 4. | 
 |   // - Walk the tree again starting from the root towards |target_map|. Stop at | 
 |   //   |split_map|, the first map who's descriptor array does not match the | 
 |   //   merged descriptor array. | 
 |   Handle<Map> FindSplitMap(Handle<DescriptorArray> descriptors); | 
 |  | 
 |   // Step 5. | 
 |   // - If |target_map| == |split_map|, |target_map| is in the expected state. | 
 |   //   Return it. | 
 |   // - Otherwise, invalidate the outdated transition target from |target_map|, | 
 |   //   and replace its transition tree with a new branch for the updated | 
 |   //   descriptors. | 
 |   State ConstructNewMap(); | 
 |  | 
 |   // Step 6 (if there was | 
 |   // - If the |old_map| had integrity level transition, create the new map | 
 |   //   for it. | 
 |   State ConstructNewMapWithIntegrityLevelTransition(); | 
 |  | 
 |   // When a requested reconfiguration can not be done the result is a copy | 
 |   // of |old_map_| in dictionary mode. | 
 |   State Normalize(const char* reason); | 
 |  | 
 |   // Returns name of a |descriptor| property. | 
 |   inline Name GetKey(InternalIndex descriptor) const; | 
 |  | 
 |   // Returns property details of a |descriptor| in "updated" |old_descrtiptors_| | 
 |   // array. | 
 |   inline PropertyDetails GetDetails(InternalIndex descriptor) const; | 
 |  | 
 |   // Returns value of a |descriptor| with kDescriptor location in "updated" | 
 |   // |old_descrtiptors_| array. | 
 |   inline Object GetValue(InternalIndex descriptor) const; | 
 |  | 
 |   // Returns field type for a |descriptor| with kField location in "updated" | 
 |   // |old_descrtiptors_| array. | 
 |   inline FieldType GetFieldType(InternalIndex descriptor) const; | 
 |  | 
 |   // If a |descriptor| property in "updated" |old_descriptors_| has kField | 
 |   // location then returns it's field type otherwise computes optimal field | 
 |   // type for the descriptor's value and |representation|. The |location| | 
 |   // value must be a pre-fetched location for |descriptor|. | 
 |   inline Handle<FieldType> GetOrComputeFieldType( | 
 |       InternalIndex descriptor, PropertyLocation location, | 
 |       Representation representation) const; | 
 |  | 
 |   // If a |descriptor| property in given |descriptors| array has kField | 
 |   // location then returns it's field type otherwise computes optimal field | 
 |   // type for the descriptor's value and |representation|. | 
 |   // The |location| value must be a pre-fetched location for |descriptor|. | 
 |   inline Handle<FieldType> GetOrComputeFieldType( | 
 |       Handle<DescriptorArray> descriptors, InternalIndex descriptor, | 
 |       PropertyLocation location, Representation representation); | 
 |  | 
 |   void GeneralizeField(Handle<Map> map, InternalIndex modify_index, | 
 |                        PropertyConstness new_constness, | 
 |                        Representation new_representation, | 
 |                        Handle<FieldType> new_field_type); | 
 |  | 
 |   bool TrySaveIntegrityLevelTransitions(); | 
 |  | 
 |   Isolate* isolate_; | 
 |   Handle<Map> old_map_; | 
 |   Handle<DescriptorArray> old_descriptors_; | 
 |   Handle<Map> root_map_; | 
 |   Handle<Map> target_map_; | 
 |   Handle<Map> result_map_; | 
 |   int old_nof_; | 
 |  | 
 |   // Information about integrity level transitions. | 
 |   bool has_integrity_level_transition_ = false; | 
 |   PropertyAttributes integrity_level_ = NONE; | 
 |   Handle<Symbol> integrity_level_symbol_; | 
 |   Handle<Map> integrity_source_map_; | 
 |  | 
 |   State state_ = kInitialized; | 
 |   ElementsKind new_elements_kind_; | 
 |   bool is_transitionable_fast_elements_kind_; | 
 |  | 
 |   // If |modified_descriptor_.is_found()|, then the fields below form | 
 |   // an "update" of the |old_map_|'s descriptors. | 
 |   InternalIndex modified_descriptor_ = InternalIndex::NotFound(); | 
 |   PropertyKind new_kind_ = kData; | 
 |   PropertyAttributes new_attributes_ = NONE; | 
 |   PropertyConstness new_constness_ = PropertyConstness::kMutable; | 
 |   PropertyLocation new_location_ = kField; | 
 |   Representation new_representation_ = Representation::None(); | 
 |  | 
 |   // Data specific to kField location. | 
 |   Handle<FieldType> new_field_type_; | 
 |  | 
 |   // Data specific to kDescriptor location. | 
 |   Handle<Object> new_value_; | 
 | }; | 
 |  | 
 | }  // namespace internal | 
 | }  // namespace v8 | 
 |  | 
 | #endif  // V8_OBJECTS_MAP_UPDATER_H_ |