Line data Source code
1 : // Copyright 2012 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_TRANSITIONS_H_
6 : #define V8_TRANSITIONS_H_
7 :
8 : #include "src/checks.h"
9 : #include "src/elements-kind.h"
10 : #include "src/objects.h"
11 : #include "src/objects/descriptor-array.h"
12 : #include "src/objects/map.h"
13 : #include "src/objects/maybe-object.h"
14 : #include "src/objects/name.h"
15 :
16 : // Has to be the last include (doesn't have include guards):
17 : #include "src/objects/object-macros.h"
18 :
19 : namespace v8 {
20 : namespace internal {
21 :
22 : // TransitionsAccessor is a helper class to encapsulate access to the various
23 : // ways a Map can store transitions to other maps in its respective field at
24 : // Map::kTransitionsOrPrototypeInfo.
25 : // It caches state information internally, which becomes stale when a Map's
26 : // transitions storage changes or when a GC cycle clears dead transitions;
27 : // so while a TransitionsAccessor instance can be used for several read-only
28 : // operations in a row (provided no GC happens between them), it must be
29 : // discarded and recreated after "Insert" and "UpdateHandler" operations.
30 : //
31 : // Internal details: a Map's field either holds an in-place weak reference to a
32 : // transition target, or a StoreIC handler for a transitioning store (which in
33 : // turn points to its target map), or a TransitionArray for several target maps
34 : // and/or handlers as well as prototype and ElementsKind transitions. Property
35 : // details (and in case of inline target storage, the key) are retrieved from
36 : // the target map's descriptor array. Stored transitions are weak in the GC
37 : // sense: both single transitions stored inline and TransitionArray fields are
38 : // cleared when the map they refer to is not otherwise reachable.
39 : class V8_EXPORT_PRIVATE TransitionsAccessor {
40 : public:
41 : TransitionsAccessor(Isolate* isolate, Map map, DisallowHeapAllocation* no_gc)
42 87845246 : : isolate_(isolate), map_(map) {
43 43922623 : Initialize();
44 : USE(no_gc);
45 : }
46 : TransitionsAccessor(Isolate* isolate, Handle<Map> map)
47 101519299 : : isolate_(isolate), map_handle_(map), map_(*map) {
48 58541038 : Initialize();
49 : }
50 :
51 : // Insert a new transition into |map|'s transition array, extending it
52 : // as necessary.
53 : // Requires the constructor that takes a Handle<Map> to have been used.
54 : // This TransitionsAccessor instance is unusable after this operation.
55 : void Insert(Handle<Name> name, Handle<Map> target, SimpleTransitionFlag flag);
56 :
57 : Map SearchTransition(Name name, PropertyKind kind,
58 : PropertyAttributes attributes);
59 :
60 : Map SearchSpecial(Symbol name);
61 : // Returns true for non-property transitions like elements kind, or
62 : // or frozen/sealed transitions.
63 : static bool IsSpecialTransition(ReadOnlyRoots roots, Name name);
64 :
65 : enum RequestedLocation { kAnyLocation, kFieldOnly };
66 : MaybeHandle<Map> FindTransitionToDataProperty(
67 : Handle<Name> name, RequestedLocation requested_location = kAnyLocation);
68 :
69 : MaybeHandle<Map> FindTransitionToField(Handle<Name> name) {
70 11565791 : return FindTransitionToDataProperty(name, kFieldOnly);
71 : }
72 :
73 : Handle<String> ExpectedTransitionKey();
74 : Handle<Map> ExpectedTransitionTarget();
75 :
76 : int NumberOfTransitions();
77 : // The size of transition arrays are limited so they do not end up in large
78 : // object space. Otherwise ClearNonLiveReferences would leak memory while
79 : // applying in-place right trimming.
80 : static const int kMaxNumberOfTransitions = 1024 + 512;
81 : bool CanHaveMoreTransitions();
82 : inline Name GetKey(int transition_number);
83 : inline Map GetTarget(int transition_number);
84 : static inline PropertyDetails GetTargetDetails(Name name, Map target);
85 :
86 : static bool IsMatchingMap(Map target, Name name, PropertyKind kind,
87 : PropertyAttributes attributes);
88 :
89 : bool HasIntegrityLevelTransitionTo(
90 : Map to, Symbol* out_symbol = nullptr,
91 : PropertyAttributes* out_integrity_level = nullptr);
92 :
93 : // ===== ITERATION =====
94 : typedef void (*TraverseCallback)(Map map, void* data);
95 :
96 : // Traverse the transition tree in postorder.
97 : void TraverseTransitionTree(TraverseCallback callback, void* data) {
98 : // Make sure that we do not allocate in the callback.
99 : DisallowHeapAllocation no_allocation;
100 264000 : TraverseTransitionTreeInternal(callback, data, &no_allocation);
101 : }
102 :
103 : // ===== PROTOTYPE TRANSITIONS =====
104 : // When you set the prototype of an object using the __proto__ accessor you
105 : // need a new map for the object (the prototype is stored in the map). In
106 : // order not to multiply maps unnecessarily we store these as transitions in
107 : // the original map. That way we can transition to the same map if the same
108 : // prototype is set, rather than creating a new map every time. The
109 : // transitions are in the form of a map where the keys are prototype objects
110 : // and the values are the maps they transition to.
111 : void PutPrototypeTransition(Handle<Object> prototype, Handle<Map> target_map);
112 : Handle<Map> GetPrototypeTransition(Handle<Object> prototype);
113 :
114 : // During the first-time Map::Update and Map::TryUpdate, the migration target
115 : // map could be cached in the raw_transitions slot of the old map that is
116 : // deprecated from the map transition tree. The next time old map is updated,
117 : // we will check this cache slot as a shortcut to get the migration target
118 : // map.
119 : void SetMigrationTarget(Map migration_target);
120 : Map GetMigrationTarget();
121 :
122 : #if DEBUG || OBJECT_PRINT
123 : void PrintTransitions(std::ostream& os);
124 : static void PrintOneTransition(std::ostream& os, Name key, Map target);
125 : void PrintTransitionTree();
126 : void PrintTransitionTree(std::ostream& os, int level,
127 : DisallowHeapAllocation* no_gc);
128 : #endif
129 : #if DEBUG
130 : void CheckNewTransitionsAreConsistent(TransitionArray old_transitions,
131 : Object transitions);
132 : bool IsConsistentWithBackPointers();
133 : bool IsSortedNoDuplicates();
134 : #endif
135 :
136 : protected:
137 : // Allow tests to use inheritance to access internals.
138 : enum Encoding {
139 : kPrototypeInfo,
140 : kUninitialized,
141 : kMigrationTarget,
142 : kWeakRef,
143 : kFullTransitionArray,
144 : };
145 :
146 : void Reload() {
147 : DCHECK(!map_handle_.is_null());
148 810369 : map_ = *map_handle_;
149 810369 : Initialize();
150 : }
151 :
152 : inline Encoding encoding() {
153 : DCHECK(!needs_reload_);
154 : return encoding_;
155 : }
156 :
157 : private:
158 : friend class MarkCompactCollector; // For HasSimpleTransitionTo.
159 : friend class TransitionArray;
160 :
161 : static inline PropertyDetails GetSimpleTargetDetails(Map transition);
162 :
163 : static inline Name GetSimpleTransitionKey(Map transition);
164 :
165 : static inline Map GetTargetFromRaw(MaybeObject raw);
166 :
167 : void MarkNeedsReload() {
168 : #if DEBUG
169 : needs_reload_ = true;
170 : #endif
171 : }
172 :
173 : void Initialize();
174 :
175 : inline Map GetSimpleTransition();
176 : bool HasSimpleTransitionTo(Map map);
177 :
178 : void ReplaceTransitions(MaybeObject new_transitions);
179 :
180 : inline Map GetTargetMapFromWeakRef();
181 :
182 : void EnsureHasFullTransitionArray();
183 : void SetPrototypeTransitions(Handle<WeakFixedArray> proto_transitions);
184 : WeakFixedArray GetPrototypeTransitions();
185 :
186 : void TraverseTransitionTreeInternal(TraverseCallback callback, void* data,
187 : DisallowHeapAllocation* no_gc);
188 :
189 : inline TransitionArray transitions();
190 :
191 : Isolate* isolate_;
192 : Handle<Map> map_handle_;
193 : Map map_;
194 : MaybeObject raw_transitions_;
195 : Encoding encoding_;
196 : #if DEBUG
197 : bool needs_reload_;
198 : #endif
199 :
200 : DISALLOW_IMPLICIT_CONSTRUCTORS(TransitionsAccessor);
201 : };
202 :
203 : // TransitionArrays are fixed arrays used to hold map transitions for property,
204 : // constant, and element changes.
205 : // The TransitionArray class exposes a very low-level interface. Most clients
206 : // should use TransitionsAccessors.
207 : // TransitionArrays have the following format:
208 : // [0] Link to next TransitionArray (for weak handling support) (strong ref)
209 : // [1] Smi(0) or WeakFixedArray of prototype transitions (strong ref)
210 : // [2] Number of transitions (can be zero after trimming)
211 : // [3] First transition key (strong ref)
212 : // [4] First transition target (weak ref)
213 : // ...
214 : // [3 + number of transitions * kTransitionSize]: start of slack
215 : class TransitionArray : public WeakFixedArray {
216 : public:
217 : DECL_CAST(TransitionArray)
218 :
219 : inline WeakFixedArray GetPrototypeTransitions();
220 : inline bool HasPrototypeTransitions();
221 :
222 : // Accessors for fetching instance transition at transition number.
223 : inline void SetKey(int transition_number, Name value);
224 : inline Name GetKey(int transition_number);
225 : inline HeapObjectSlot GetKeySlot(int transition_number);
226 :
227 : inline Map GetTarget(int transition_number);
228 : inline void SetRawTarget(int transition_number, MaybeObject target);
229 : inline MaybeObject GetRawTarget(int transition_number);
230 : inline HeapObjectSlot GetTargetSlot(int transition_number);
231 : inline bool GetTargetIfExists(int transition_number, Isolate* isolate,
232 : Map* target);
233 :
234 : // Required for templatized Search interface.
235 : static constexpr int kNotFound = -1;
236 :
237 : inline Name GetSortedKey(int transition_number);
238 : int GetSortedKeyIndex(int transition_number) { return transition_number; }
239 : inline int number_of_entries() const;
240 : #ifdef DEBUG
241 : V8_EXPORT_PRIVATE bool IsSortedNoDuplicates(int valid_entries = -1);
242 : #endif
243 :
244 : void Sort();
245 :
246 : void PrintInternal(std::ostream& os);
247 :
248 : DECL_PRINTER(TransitionArray)
249 : DECL_VERIFIER(TransitionArray)
250 :
251 : // Layout for full transition arrays.
252 : static const int kPrototypeTransitionsIndex = 0;
253 : static const int kTransitionLengthIndex = 1;
254 : static const int kFirstIndex = 2;
255 :
256 : // Layout of map transition entries in full transition arrays.
257 : static const int kEntryKeyIndex = 0;
258 : static const int kEntryTargetIndex = 1;
259 : static const int kEntrySize = 2;
260 :
261 : // Conversion from transition number to array indices.
262 : static int ToKeyIndex(int transition_number) {
263 100805185 : return kFirstIndex + (transition_number * kEntrySize) + kEntryKeyIndex;
264 : }
265 :
266 : static int ToTargetIndex(int transition_number) {
267 43634199 : return kFirstIndex + (transition_number * kEntrySize) + kEntryTargetIndex;
268 : }
269 :
270 : inline int SearchNameForTesting(Name name,
271 : int* out_insertion_index = nullptr);
272 :
273 : private:
274 : friend class Factory;
275 : friend class MarkCompactCollector;
276 : friend class TransitionsAccessor;
277 :
278 : inline void SetNumberOfTransitions(int number_of_transitions);
279 :
280 : inline int Capacity();
281 :
282 : // ===== PROTOTYPE TRANSITIONS =====
283 : // Cache format:
284 : // 0: finger - index of the first free cell in the cache
285 : // 1 + i: target map
286 : static const int kProtoTransitionHeaderSize = 1;
287 : static const int kMaxCachedPrototypeTransitions = 256;
288 :
289 : inline void SetPrototypeTransitions(WeakFixedArray prototype_transitions);
290 :
291 : static inline int NumberOfPrototypeTransitions(
292 : WeakFixedArray proto_transitions);
293 : static void SetNumberOfPrototypeTransitions(WeakFixedArray proto_transitions,
294 : int value);
295 :
296 : static const int kProtoTransitionNumberOfEntriesOffset = 0;
297 : STATIC_ASSERT(kProtoTransitionHeaderSize == 1);
298 :
299 : // Returns the fixed array length required to hold number_of_transitions
300 : // transitions.
301 : static int LengthFor(int number_of_transitions) {
302 : return ToKeyIndex(number_of_transitions);
303 : }
304 :
305 : // Search a transition for a given kind, property name and attributes.
306 : int Search(PropertyKind kind, Name name, PropertyAttributes attributes,
307 : int* out_insertion_index = nullptr);
308 :
309 : Map SearchAndGetTarget(PropertyKind kind, Name name,
310 : PropertyAttributes attributes);
311 :
312 : // Search a non-property transition (like elements kind, observe or frozen
313 : // transitions).
314 : inline int SearchSpecial(Symbol symbol, int* out_insertion_index = nullptr);
315 : // Search a first transition for a given property name.
316 : inline int SearchName(Name name, int* out_insertion_index = nullptr);
317 : int SearchDetails(int transition, PropertyKind kind,
318 : PropertyAttributes attributes, int* out_insertion_index);
319 : Map SearchDetailsAndGetTarget(int transition, PropertyKind kind,
320 : PropertyAttributes attributes);
321 :
322 : inline int number_of_transitions() const;
323 :
324 : static bool CompactPrototypeTransitionArray(Isolate* isolate,
325 : WeakFixedArray array);
326 :
327 : static Handle<WeakFixedArray> GrowPrototypeTransitionArray(
328 : Handle<WeakFixedArray> array, int new_capacity, Isolate* isolate);
329 :
330 : // Compares two tuples <key, kind, attributes>, returns -1 if
331 : // tuple1 is "less" than tuple2, 0 if tuple1 equal to tuple2 and 1 otherwise.
332 : static inline int CompareKeys(Name key1, uint32_t hash1, PropertyKind kind1,
333 : PropertyAttributes attributes1, Name key2,
334 : uint32_t hash2, PropertyKind kind2,
335 : PropertyAttributes attributes2);
336 :
337 : // Compares keys, returns -1 if key1 is "less" than key2,
338 : // 0 if key1 equal to key2 and 1 otherwise.
339 : static inline int CompareNames(Name key1, uint32_t hash1, Name key2,
340 : uint32_t hash2);
341 :
342 : // Compares two details, returns -1 if details1 is "less" than details2,
343 : // 0 if details1 equal to details2 and 1 otherwise.
344 : static inline int CompareDetails(PropertyKind kind1,
345 : PropertyAttributes attributes1,
346 : PropertyKind kind2,
347 : PropertyAttributes attributes2);
348 :
349 : inline void Set(int transition_number, Name key, MaybeObject target);
350 :
351 : void Zap(Isolate* isolate);
352 :
353 : OBJECT_CONSTRUCTORS(TransitionArray, WeakFixedArray);
354 : };
355 :
356 : } // namespace internal
357 : } // namespace v8
358 :
359 : #include "src/objects/object-macros-undef.h"
360 :
361 : #endif // V8_TRANSITIONS_H_
|