v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
map-updater.h
Go to the documentation of this file.
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#ifndef V8_OBJECTS_MAP_UPDATER_H_
6#define V8_OBJECTS_MAP_UPDATER_H_
7
8#include <optional>
9
10#include "src/common/globals.h"
11#include "src/handles/handles.h"
14#include "src/objects/map.h"
16
17namespace v8::internal {
18
19// The |MapUpdater| class implements all sorts of map reconfigurations
20// including changes of elements kind, property attributes, property kind,
21// property location and field representations/type changes. It ensures that
22// the reconfigured map and all the intermediate maps are properly integrated
23// into the existing transition tree.
24//
25// To avoid high degrees over polymorphism, and to stabilize quickly, on every
26// rewrite the new type is deduced by merging the current type with any
27// potential new (partial) version of the type in the transition tree.
28// To do this, on each rewrite:
29// - Search the root of the transition tree using FindRootMap, remember
30// the integrity level (preventExtensions/seal/freeze) of transitions.
31// - Find/create a |root_map| with the requested |new_elements_kind|.
32// - Find |target_map|, the newest matching version of this map using the
33// "updated" |old_map|'s descriptor array (i.e. whose entry at |modify_index|
34// is considered to be of |new_kind| and having |new_attributes|) to walk
35// the transition tree. If there was an integrity level transition on the path
36// to the old map, use the descriptor array of the map preceding the first
37// integrity level transition (|integrity_source_map|), and try to replay
38// the integrity level transition afterwards.
39// - Merge/generalize the "updated" descriptor array of the |old_map| and
40// descriptor array of the |target_map|.
41// - Generalize the |modify_index| descriptor using |new_representation| and
42// |new_field_type|.
43// - Walk the tree again starting from the root towards |target_map|. Stop at
44// |split_map|, the first map whose descriptor array does not match the merged
45// descriptor array.
46// - If |target_map| == |split_map|, and there are no integrity level
47// transitions, |target_map| is in the expected state. Return it.
48// - Otherwise, invalidate the outdated transition target from |target_map|, and
49// replace its transition tree with a new branch for the updated descriptors.
50// - If the |old_map| had integrity level transition, create the new map for it.
52 public:
53 MapUpdater(Isolate* isolate, DirectHandle<Map> old_map);
54
55 // Prepares for reconfiguring of a property at |descriptor| to data field
56 // with given |attributes| and |representation|/|field_type| and
57 // performs the steps 1-6.
58 Handle<Map> ReconfigureToDataField(InternalIndex descriptor,
59 PropertyAttributes attributes,
60 PropertyConstness constness,
61 Representation representation,
62 DirectHandle<FieldType> field_type);
63
64 // Prepares for reconfiguring elements kind and performs the steps 1-6.
65 DirectHandle<Map> ReconfigureElementsKind(ElementsKind elements_kind);
66
67 // Prepares for an UpdatePrototype. Similar to reconfigure elements kind,
68 // prototype transitions are put first. I.e., a prototype transition for
69 // `{__proto__: foo, a: 1}.__proto__ = bar` produces the following graph:
70 //
71 // foo {} -- foo {a}
72 // \
73 // bar {} -- bar {a}
74 //
75 // and JSObject::UpdatePrototype performs a map update and instance migration.
76 Handle<Map> ApplyPrototypeTransition(DirectHandle<JSPrototype> prototype);
77
78 // Prepares for updating deprecated map to most up-to-date non-deprecated
79 // version and performs the steps 1-6.
80 Handle<Map> Update();
81
82 // As above but does not mutate maps; instead, we attempt to replay existing
83 // transitions to find an updated map. No lock is taken.
84 static std::optional<Tagged<Map>> TryUpdateNoLock(
85 Isolate* isolate, Tagged<Map> old_map,
87
88 static Handle<Map> ReconfigureExistingProperty(Isolate* isolate,
90 InternalIndex descriptor,
92 PropertyAttributes attributes,
93 PropertyConstness constness);
94
95 static void GeneralizeField(Isolate* isolate, DirectHandle<Map> map,
96 InternalIndex modify_index,
97 PropertyConstness new_constness,
98 Representation new_representation,
99 DirectHandle<FieldType> new_field_type);
100
101 // Completes inobject slack tracking for the transition tree starting at the
102 // initial map.
103 static void CompleteInobjectSlackTracking(Isolate* isolate,
104 Tagged<Map> initial_map);
105
106 private:
114
115 // Updates map to the most up-to-date non-deprecated version.
116 static inline DirectHandle<Map> UpdateMapNoLock(Isolate* isolate,
117 DirectHandle<Map> old_map);
118
119 // Prepares for updating deprecated map to most up-to-date non-deprecated
120 // version and performs the steps 1-6.
121 // Unlike the Update() entry point it doesn't lock the map_updater_access
122 // mutex.
123 Handle<Map> UpdateImpl();
124
125 // Try to reconfigure property in-place without rebuilding transition tree
126 // and creating new maps. See implementation for details.
127 State TryReconfigureToDataFieldInplace();
128
129 // Step 1.
130 // - Search the root of the transition tree using FindRootMap.
131 // - Find/create a |root_map_| with requested |new_elements_kind_|.
132 State FindRootMap();
133
134 // Step 2.
135 // - Find |target_map|, the newest matching version of this map using the
136 // "updated" |old_map|'s descriptor array (i.e. whose entry at
137 // |modify_index| is considered to be of |new_kind| and having
138 // |new_attributes|) to walk the transition tree. If there was an integrity
139 // level transition on the path to the old map, use the descriptor array
140 // of the map preceding the first integrity level transition
141 // (|integrity_source_map|), and try to replay the integrity level
142 // transition afterwards.
143 State FindTargetMap();
144
145 // Step 3.
146 // - Merge/generalize the "updated" descriptor array of the |old_map_| and
147 // descriptor array of the |target_map_|.
148 // - Generalize the |modified_descriptor_| using |new_representation| and
149 // |new_field_type_|.
150 DirectHandle<DescriptorArray> BuildDescriptorArray();
151
152 // Step 4.
153 // - Walk the tree again starting from the root towards |target_map|. Stop at
154 // |split_map|, the first map whose descriptor array does not match the
155 // merged descriptor array.
156 DirectHandle<Map> FindSplitMap(DirectHandle<DescriptorArray> descriptors);
157
158 // Step 5.
159 // - If |target_map| == |split_map|, |target_map| is in the expected state.
160 // Return it.
161 // - Otherwise, invalidate the outdated transition target from |target_map|,
162 // and replace its transition tree with a new branch for the updated
163 // descriptors.
164 State ConstructNewMap();
165
166 // Step 6.
167 // - If the |old_map| had integrity level transition, create the new map
168 // for it.
169 State ConstructNewMapWithIntegrityLevelTransition();
170
171 // When a requested reconfiguration can not be done the result is a copy
172 // of |old_map_| in dictionary mode.
173 State Normalize(const char* reason);
174
175 // Returns name of a |descriptor| property.
176 inline Tagged<Name> GetKey(InternalIndex descriptor) const;
177
178 // Returns property details of a |descriptor| in "updated" |old_descriptors_|
179 // array.
180 inline PropertyDetails GetDetails(InternalIndex descriptor) const;
181
182 // Returns value of a |descriptor| with kDescriptor location in "updated"
183 // |old_descriptors_| array.
184 inline Tagged<Object> GetValue(InternalIndex descriptor) const;
185
186 // Returns field type for a |descriptor| with kField location in "updated"
187 // |old_descriptors_| array.
188 inline Tagged<FieldType> GetFieldType(InternalIndex descriptor) const;
189
190 // If a |descriptor| property in "updated" |old_descriptors_| has kField
191 // location then returns its field type, otherwise computes the optimal field
192 // type for the descriptor's value and |representation|. The |location|
193 // value must be a pre-fetched location for |descriptor|.
194 inline DirectHandle<FieldType> GetOrComputeFieldType(
195 InternalIndex descriptor, PropertyLocation location,
196 Representation representation) const;
197
198 // If a |descriptor| property in given |descriptors| array has kField
199 // location then returns its field type, otherwise computes the optimal field
200 // type for the descriptor's value and |representation|.
201 // The |location| value must be a pre-fetched location for |descriptor|.
202 inline DirectHandle<FieldType> GetOrComputeFieldType(
203 DirectHandle<DescriptorArray> descriptors, InternalIndex descriptor,
204 PropertyLocation location, Representation representation);
205
206 // Update field type of the given descriptor to new representation and new
207 // type. The type must be prepared for storing in descriptor array:
208 // it must be either a simple type or a map wrapped in a weak cell.
209 static void UpdateFieldType(Isolate* isolate, DirectHandle<Map> map,
210 InternalIndex descriptor_number,
212 PropertyConstness new_constness,
213 Representation new_representation,
214 DirectHandle<FieldType> new_type);
215
216 void GeneralizeField(DirectHandle<Map> map, InternalIndex modify_index,
217 PropertyConstness new_constness,
218 Representation new_representation,
219 DirectHandle<FieldType> new_field_type);
220
221 bool TrySaveIntegrityLevelTransitions();
222
230
231 // Information about integrity level transitions.
232 bool has_integrity_level_transition_ = false;
233 PropertyAttributes integrity_level_ = NONE;
236
237 State state_ = kInitialized;
240
242
243 // If |modified_descriptor_.is_found()|, then the fields below form
244 // an "update" of the |old_map_|'s descriptors.
245 InternalIndex modified_descriptor_ = InternalIndex::NotFound();
246 PropertyKind new_kind_ = PropertyKind::kData;
247 PropertyAttributes new_attributes_ = NONE;
248 PropertyConstness new_constness_ = PropertyConstness::kMutable;
249 PropertyLocation new_location_ = PropertyLocation::kField;
250 Representation new_representation_ = Representation::None();
251
252 // Data specific to kField location.
254};
255
256} // namespace v8::internal
257
258#endif // V8_OBJECTS_MAP_UPDATER_H_
Builtins::Kind kind
Definition builtins.cc:40
DirectHandle< FieldType > new_field_type_
Handle< Map > target_map_
DirectHandle< Map > old_map_
Handle< Map > result_map_
ElementsKind new_elements_kind_
DirectHandle< Symbol > integrity_level_symbol_
DirectHandle< Map > integrity_source_map_
DirectHandle< DescriptorArray > old_descriptors_
DirectHandle< JSPrototype > new_prototype_
enum v8::internal::@1270::DeoptimizableCodeIterator::@67 state_
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define V8_WARN_UNUSED_RESULT
Definition v8config.h:671