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_H_
6 #define V8_OBJECTS_MAP_H_
7 
8 #include "src/objects.h"
9 #include "src/objects/code.h"
10 
11 #include "src/globals.h"
12 
13 // Has to be the last include (doesn't have include guards):
14 #include "src/objects/object-macros.h"
15 
16 namespace v8 {
17 namespace internal {
18 
19 #define VISITOR_ID_LIST(V) \
20   V(AllocationSite)        \
21   V(BigInt)                \
22   V(ByteArray)             \
23   V(BytecodeArray)         \
24   V(Cell)                  \
25   V(Code)                  \
26   V(CodeDataContainer)     \
27   V(ConsString)            \
28   V(DataObject)            \
29   V(FeedbackCell)          \
30   V(FeedbackVector)        \
31   V(FixedArray)            \
32   V(FixedDoubleArray)      \
33   V(FixedFloat64Array)     \
34   V(FixedTypedArrayBase)   \
35   V(FreeSpace)             \
36   V(JSApiObject)           \
37   V(JSArrayBuffer)         \
38   V(JSFunction)            \
39   V(JSObject)              \
40   V(JSObjectFast)          \
41   V(JSWeakCollection)      \
42   V(Map)                   \
43   V(NativeContext)         \
44   V(Oddball)               \
45   V(PropertyArray)         \
46   V(PropertyCell)          \
47   V(SeqOneByteString)      \
48   V(SeqTwoByteString)      \
49   V(SharedFunctionInfo)    \
50   V(ShortcutCandidate)     \
51   V(SlicedString)          \
52   V(SmallOrderedHashMap)   \
53   V(SmallOrderedHashSet)   \
54   V(Struct)                \
55   V(Symbol)                \
56   V(ThinString)            \
57   V(TransitionArray)       \
58   V(WasmInstanceObject)    \
59   V(WeakCell)              \
60   V(WeakArray)
61 
62 // For data objects, JS objects and structs along with generic visitor which
63 // can visit object of any size we provide visitors specialized by
64 // object size in words.
65 // Ids of specialized visitors are declared in a linear order (without
66 // holes) starting from the id of visitor specialized for 2 words objects
67 // (base visitor id) and ending with the id of generic visitor.
68 // Method GetVisitorIdForSize depends on this ordering to calculate visitor
69 // id of specialized visitor from given instance size, base visitor id and
70 // generic visitor's id.
71 enum VisitorId {
72 #define VISITOR_ID_ENUM_DECL(id) kVisit##id,
73   VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL)
74 #undef VISITOR_ID_ENUM_DECL
75       kVisitorIdCount
76 };
77 
78 typedef std::vector<Handle<Map>> MapHandles;
79 
80 // All heap objects have a Map that describes their structure.
81 //  A Map contains information about:
82 //  - Size information about the object
83 //  - How to iterate over an object (for garbage collection)
84 //
85 // Map layout:
86 // +---------------+---------------------------------------------+
87 // |   _ Type _    | _ Description _                             |
88 // +---------------+---------------------------------------------+
89 // | TaggedPointer | map - Always a pointer to the MetaMap root  |
90 // +---------------+---------------------------------------------+
91 // | Int           | The first int field                         |
92 //  `---+----------+---------------------------------------------+
93 //      | Byte     | [instance_size]                             |
94 //      +----------+---------------------------------------------+
95 //      | Byte     | If Map for a primitive type:                |
96 //      |          |   native context index for constructor fn   |
97 //      |          | If Map for an Object type:                  |
98 //      |          |   inobject properties start offset in words |
99 //      +----------+---------------------------------------------+
100 //      | Byte     | [used_or_unused_instance_size_in_words]     |
101 //      |          | For JSObject in fast mode this byte encodes |
102 //      |          | the size of the object that includes only   |
103 //      |          | the used property fields or the slack size  |
104 //      |          | in properties backing store.                |
105 //      +----------+---------------------------------------------+
106 //      | Byte     | [visitor_id]                                |
107 // +----+----------+---------------------------------------------+
108 // | Int           | The second int field                        |
109 //  `---+----------+---------------------------------------------+
110 //      | Short    | [instance_type]                             |
111 //      +----------+---------------------------------------------+
112 //      | Byte     | [bit_field]                                 |
113 //      |          |   - has_non_instance_prototype (bit 0)      |
114 //      |          |   - is_callable (bit 1)                     |
115 //      |          |   - has_named_interceptor (bit 2)           |
116 //      |          |   - has_indexed_interceptor (bit 3)         |
117 //      |          |   - is_undetectable (bit 4)                 |
118 //      |          |   - is_access_check_needed (bit 5)          |
119 //      |          |   - is_constructor (bit 6)                  |
120 //      |          |   - has_prototype_slot (bit 7)              |
121 //      +----------+---------------------------------------------+
122 //      | Byte     | [bit_field2]                                |
123 //      |          |   - is_extensible (bit 0)                   |
124 //      |          |   - is_prototype_map (bit 1)                |
125 //      |          |   - is_in_retained_map_list (bit 2)         |
126 //      |          |   - elements_kind (bits 3..7)               |
127 // +----+----------+---------------------------------------------+
128 // | Int           | [bit_field3]                                |
129 // |               |   - enum_length (bit 0..9)                  |
130 // |               |   - number_of_own_descriptors (bit 10..19)  |
131 // |               |   - is_dictionary_map (bit 20)              |
132 // |               |   - owns_descriptors (bit 21)               |
133 // |               |   - has_hidden_prototype (bit 22)           |
134 // |               |   - is_deprecated (bit 23)                  |
135 // |               |   - is_unstable (bit 24)                    |
136 // |               |   - is_migration_target (bit 25)            |
137 // |               |   - is_immutable_proto (bit 26)             |
138 // |               |   - new_target_is_base (bit 27)             |
139 // |               |   - may_have_interesting_symbols (bit 28)   |
140 // |               |   - construction_counter (bit 29..31)       |
141 // |               |                                             |
142 // +*************************************************************+
143 // | Int           | On systems with 64bit pointer types, there  |
144 // |               | is an unused 32bits after bit_field3        |
145 // +*************************************************************+
146 // | TaggedPointer | [prototype]                                 |
147 // +---------------+---------------------------------------------+
148 // | TaggedPointer | [constructor_or_backpointer]                |
149 // +---------------+---------------------------------------------+
150 // | TaggedPointer | If Map is a prototype map:                  |
151 // |               |   [prototype_info]                          |
152 // |               | Else:                                       |
153 // |               |   [raw_transitions]                         |
154 // +---------------+---------------------------------------------+
155 // | TaggedPointer | [instance_descriptors]                      |
156 // +*************************************************************+
157 // ! TaggedPointer ! [layout_descriptors]                        !
158 // !               ! Field is only present if compile-time flag  !
159 // !               ! FLAG_unbox_double_fields is enabled         !
160 // !               ! (basically on 64 bit architectures)         !
161 // +*************************************************************+
162 // | TaggedPointer | [dependent_code]                            |
163 // +---------------+---------------------------------------------+
164 // | TaggedPointer | [weak_cell_cache]                           |
165 // +---------------+---------------------------------------------+
166 
167 class Map : public HeapObject {
168  public:
169   // Instance size.
170   // Size in bytes or kVariableSizeSentinel if instances do not have
171   // a fixed size.
172   DECL_INT_ACCESSORS(instance_size)
173   // Size in words or kVariableSizeSentinel if instances do not have
174   // a fixed size.
175   DECL_INT_ACCESSORS(instance_size_in_words)
176 
177   // [inobject_properties_start_or_constructor_function_index]:
178   // Provides access to the inobject properties start offset in words in case of
179   // JSObject maps, or the constructor function index in case of primitive maps.
180   DECL_INT_ACCESSORS(inobject_properties_start_or_constructor_function_index)
181 
182   // Get/set the in-object property area start offset in words in the object.
183   inline int GetInObjectPropertiesStartInWords() const;
184   inline void SetInObjectPropertiesStartInWords(int value);
185   // Count of properties allocated in the object (JSObject only).
186   inline int GetInObjectProperties() const;
187   // Index of the constructor function in the native context (primitives only),
188   // or the special sentinel value to indicate that there is no object wrapper
189   // for the primitive (i.e. in case of null or undefined).
190   static const int kNoConstructorFunctionIndex = 0;
191   inline int GetConstructorFunctionIndex() const;
192   inline void SetConstructorFunctionIndex(int value);
193   static MaybeHandle<JSFunction> GetConstructorFunction(
194       Handle<Map> map, Handle<Context> native_context);
195 
196   // Retrieve interceptors.
197   inline InterceptorInfo* GetNamedInterceptor();
198   inline InterceptorInfo* GetIndexedInterceptor();
199 
200   // Instance type.
201   DECL_PRIMITIVE_ACCESSORS(instance_type, InstanceType)
202 
203   // Returns the size of the used in-object area including object header
204   // (only used for JSObject in fast mode, for the other kinds of objects it
205   // is equal to the instance size).
206   inline int UsedInstanceSize() const;
207 
208   // Tells how many unused property fields (in-object or out-of object) are
209   // available in the instance (only used for JSObject in fast mode).
210   inline int UnusedPropertyFields() const;
211   // Updates the counters tracking unused fields in the object.
212   inline void SetInObjectUnusedPropertyFields(int unused_property_fields);
213   // Updates the counters tracking unused fields in the property array.
214   inline void SetOutOfObjectUnusedPropertyFields(int unused_property_fields);
215   inline void CopyUnusedPropertyFields(Map* map);
216   inline void AccountAddedPropertyField();
217   inline void AccountAddedOutOfObjectPropertyField(
218       int unused_in_property_array);
219 
220   //
221   // Bit field.
222   //
223   DECL_PRIMITIVE_ACCESSORS(bit_field, byte)
224 
225 // Bit positions for |bit_field|.
226 #define MAP_BIT_FIELD_FIELDS(V, _)          \
227   V(HasNonInstancePrototypeBit, bool, 1, _) \
228   V(IsCallableBit, bool, 1, _)              \
229   V(HasNamedInterceptorBit, bool, 1, _)     \
230   V(HasIndexedInterceptorBit, bool, 1, _)   \
231   V(IsUndetectableBit, bool, 1, _)          \
232   V(IsAccessCheckNeededBit, bool, 1, _)     \
233   V(IsConstructorBit, bool, 1, _)           \
234   V(HasPrototypeSlotBit, bool, 1, _)
235 
236   DEFINE_BIT_FIELDS(MAP_BIT_FIELD_FIELDS)
237 #undef MAP_BIT_FIELD_FIELDS
238 
239   //
240   // Bit field 2.
241   //
242   DECL_PRIMITIVE_ACCESSORS(bit_field2, byte)
243 
244 // Bit positions for |bit_field2|.
245 #define MAP_BIT_FIELD2_FIELDS(V, _)     \
246   V(IsExtensibleBit, bool, 1, _)        \
247   V(IsPrototypeMapBit, bool, 1, _)      \
248   V(IsInRetainedMapListBit, bool, 1, _) \
249   V(ElementsKindBits, ElementsKind, 5, _)
250 
251   DEFINE_BIT_FIELDS(MAP_BIT_FIELD2_FIELDS)
252 #undef MAP_BIT_FIELD2_FIELDS
253 
254   //
255   // Bit field 3.
256   //
257   DECL_PRIMITIVE_ACCESSORS(bit_field3, uint32_t)
258 
259 // Bit positions for |bit_field3|.
260 #define MAP_BIT_FIELD3_FIELDS(V, _)                               \
261   V(EnumLengthBits, int, kDescriptorIndexBitCount, _)             \
262   V(NumberOfOwnDescriptorsBits, int, kDescriptorIndexBitCount, _) \
263   V(IsDictionaryMapBit, bool, 1, _)                               \
264   V(OwnsDescriptorsBit, bool, 1, _)                               \
265   V(HasHiddenPrototypeBit, bool, 1, _)                            \
266   V(IsDeprecatedBit, bool, 1, _)                                  \
267   V(IsUnstableBit, bool, 1, _)                                    \
268   V(IsMigrationTargetBit, bool, 1, _)                             \
269   V(IsImmutablePrototypeBit, bool, 1, _)                          \
270   V(NewTargetIsBaseBit, bool, 1, _)                               \
271   V(MayHaveInterestingSymbolsBit, bool, 1, _)                     \
272   V(ConstructionCounterBits, int, 3, _)
273 
274   DEFINE_BIT_FIELDS(MAP_BIT_FIELD3_FIELDS)
275 #undef MAP_BIT_FIELD3_FIELDS
276 
277   STATIC_ASSERT(NumberOfOwnDescriptorsBits::kMax >= kMaxNumberOfDescriptors);
278 
279   static const int kSlackTrackingCounterStart = 7;
280   static const int kSlackTrackingCounterEnd = 1;
281   static const int kNoSlackTracking = 0;
282   STATIC_ASSERT(kSlackTrackingCounterStart <= ConstructionCounterBits::kMax);
283 
284   // Inobject slack tracking is the way to reclaim unused inobject space.
285   //
286   // The instance size is initially determined by adding some slack to
287   // expected_nof_properties (to allow for a few extra properties added
288   // after the constructor). There is no guarantee that the extra space
289   // will not be wasted.
290   //
291   // Here is the algorithm to reclaim the unused inobject space:
292   // - Detect the first constructor call for this JSFunction.
293   //   When it happens enter the "in progress" state: initialize construction
294   //   counter in the initial_map.
295   // - While the tracking is in progress initialize unused properties of a new
296   //   object with one_pointer_filler_map instead of undefined_value (the "used"
297   //   part is initialized with undefined_value as usual). This way they can
298   //   be resized quickly and safely.
299   // - Once enough objects have been created  compute the 'slack'
300   //   (traverse the map transition tree starting from the
301   //   initial_map and find the lowest value of unused_property_fields).
302   // - Traverse the transition tree again and decrease the instance size
303   //   of every map. Existing objects will resize automatically (they are
304   //   filled with one_pointer_filler_map). All further allocations will
305   //   use the adjusted instance size.
306   // - SharedFunctionInfo's expected_nof_properties left unmodified since
307   //   allocations made using different closures could actually create different
308   //   kind of objects (see prototype inheritance pattern).
309   //
310   //  Important: inobject slack tracking is not attempted during the snapshot
311   //  creation.
312 
313   static const int kGenerousAllocationCount =
314       kSlackTrackingCounterStart - kSlackTrackingCounterEnd + 1;
315 
316   // Starts the tracking by initializing object constructions countdown counter.
317   void StartInobjectSlackTracking();
318 
319   // True if the object constructions countdown counter is a range
320   // [kSlackTrackingCounterEnd, kSlackTrackingCounterStart].
321   inline bool IsInobjectSlackTrackingInProgress() const;
322 
323   // Does the tracking step.
324   inline void InobjectSlackTrackingStep();
325 
326   // Completes inobject slack tracking for the transition tree starting at this
327   // initial map.
328   void CompleteInobjectSlackTracking();
329 
330   // Tells whether the object in the prototype property will be used
331   // for instances created from this function.  If the prototype
332   // property is set to a value that is not a JSObject, the prototype
333   // property will not be used to create instances of the function.
334   // See ECMA-262, 13.2.2.
335   DECL_BOOLEAN_ACCESSORS(has_non_instance_prototype)
336 
337   // Tells whether the instance has a [[Construct]] internal method.
338   // This property is implemented according to ES6, section 7.2.4.
339   DECL_BOOLEAN_ACCESSORS(is_constructor)
340 
341   // Tells whether the instance with this map may have properties for
342   // interesting symbols on it.
343   // An "interesting symbol" is one for which Name::IsInterestingSymbol()
344   // returns true, i.e. a well-known symbol like @@toStringTag.
345   DECL_BOOLEAN_ACCESSORS(may_have_interesting_symbols)
346 
347   DECL_BOOLEAN_ACCESSORS(has_prototype_slot)
348 
349   // Tells whether the instance with this map has a hidden prototype.
350   DECL_BOOLEAN_ACCESSORS(has_hidden_prototype)
351 
352   // Records and queries whether the instance has a named interceptor.
353   DECL_BOOLEAN_ACCESSORS(has_named_interceptor)
354 
355   // Records and queries whether the instance has an indexed interceptor.
356   DECL_BOOLEAN_ACCESSORS(has_indexed_interceptor)
357 
358   // Tells whether the instance is undetectable.
359   // An undetectable object is a special class of JSObject: 'typeof' operator
360   // returns undefined, ToBoolean returns false. Otherwise it behaves like
361   // a normal JS object.  It is useful for implementing undetectable
362   // document.all in Firefox & Safari.
363   // See https://bugzilla.mozilla.org/show_bug.cgi?id=248549.
364   DECL_BOOLEAN_ACCESSORS(is_undetectable)
365 
366   // Tells whether the instance has a [[Call]] internal method.
367   // This property is implemented according to ES6, section 7.2.3.
368   DECL_BOOLEAN_ACCESSORS(is_callable)
369 
370   DECL_BOOLEAN_ACCESSORS(new_target_is_base)
371   DECL_BOOLEAN_ACCESSORS(is_extensible)
372   DECL_BOOLEAN_ACCESSORS(is_prototype_map)
373   inline bool is_abandoned_prototype_map() const;
374 
375   // Whether the instance has been added to the retained map list by
376   // Heap::AddRetainedMap.
377   DECL_BOOLEAN_ACCESSORS(is_in_retained_map_list)
378 
379   DECL_PRIMITIVE_ACCESSORS(elements_kind, ElementsKind)
380 
381   // Tells whether the instance has fast elements that are only Smis.
382   inline bool has_fast_smi_elements() const;
383 
384   // Tells whether the instance has fast elements.
385   inline bool has_fast_object_elements() const;
386   inline bool has_fast_smi_or_object_elements() const;
387   inline bool has_fast_double_elements() const;
388   inline bool has_fast_elements() const;
389   inline bool has_sloppy_arguments_elements() const;
390   inline bool has_fast_sloppy_arguments_elements() const;
391   inline bool has_fast_string_wrapper_elements() const;
392   inline bool has_fixed_typed_array_elements() const;
393   inline bool has_dictionary_elements() const;
394 
395   static bool IsValidElementsTransition(ElementsKind from_kind,
396                                         ElementsKind to_kind);
397 
398   // Returns true if the current map doesn't have DICTIONARY_ELEMENTS but if a
399   // map with DICTIONARY_ELEMENTS was found in the prototype chain.
400   bool DictionaryElementsInPrototypeChainOnly();
401 
402   inline Map* ElementsTransitionMap();
403 
404   inline FixedArrayBase* GetInitialElements() const;
405 
406   // [raw_transitions]: Provides access to the transitions storage field.
407   // Don't call set_raw_transitions() directly to overwrite transitions, use
408   // the TransitionArray::ReplaceTransitions() wrapper instead!
409   DECL_ACCESSORS(raw_transitions, MaybeObject)
410   // [prototype_info]: Per-prototype metadata. Aliased with transitions
411   // (which prototype maps don't have).
412   DECL_ACCESSORS(prototype_info, Object)
413   // PrototypeInfo is created lazily using this helper (which installs it on
414   // the given prototype's map).
415   static Handle<PrototypeInfo> GetOrCreatePrototypeInfo(
416       Handle<JSObject> prototype, Isolate* isolate);
417   static Handle<PrototypeInfo> GetOrCreatePrototypeInfo(
418       Handle<Map> prototype_map, Isolate* isolate);
419   inline bool should_be_fast_prototype_map() const;
420   static void SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
421                                           Isolate* isolate);
422 
423   // [prototype chain validity cell]: Associated with a prototype object,
424   // stored in that object's map, indicates that prototype chains through this
425   // object are currently valid. The cell will be invalidated and replaced when
426   // the prototype chain changes. When there's nothing to guard (for example,
427   // when direct prototype is null or Proxy) this function returns Smi with
428   // |kPrototypeChainValid| sentinel value.
429   static Handle<Object> GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
430                                                               Isolate* isolate);
431   static const int kPrototypeChainValid = 0;
432   static const int kPrototypeChainInvalid = 1;
433 
434   static bool IsPrototypeChainInvalidated(Map* map);
435 
436   // Return the map of the root of object's prototype chain.
437   Map* GetPrototypeChainRootMap(Isolate* isolate) const;
438 
439   // Returns a WeakCell object containing given prototype. The cell is cached
440   // in PrototypeInfo which is created lazily.
441   static Handle<WeakCell> GetOrCreatePrototypeWeakCell(
442       Handle<JSReceiver> prototype, Isolate* isolate);
443 
444   Map* FindRootMap() const;
445   Map* FindFieldOwner(int descriptor) const;
446 
447   inline int GetInObjectPropertyOffset(int index) const;
448 
449   int NumberOfFields() const;
450 
451   bool HasOutOfObjectProperties() const;
452 
453   // Returns true if transition to the given map requires special
454   // synchronization with the concurrent marker.
455   bool TransitionRequiresSynchronizationWithGC(Map* target) const;
456   // Returns true if transition to the given map removes a tagged in-object
457   // field.
458   bool TransitionRemovesTaggedField(Map* target) const;
459   // Returns true if transition to the given map replaces a tagged in-object
460   // field with an untagged in-object field.
461   bool TransitionChangesTaggedFieldToUntaggedField(Map* target) const;
462 
463   // TODO(ishell): candidate with JSObject::MigrateToMap().
464   bool InstancesNeedRewriting(Map* target) const;
465   bool InstancesNeedRewriting(Map* target, int target_number_of_fields,
466                               int target_inobject, int target_unused,
467                               int* old_number_of_fields) const;
468   // TODO(ishell): moveit!
469   static Handle<Map> GeneralizeAllFields(Handle<Map> map);
470   V8_WARN_UNUSED_RESULT static Handle<FieldType> GeneralizeFieldType(
471       Representation rep1, Handle<FieldType> type1, Representation rep2,
472       Handle<FieldType> type2, Isolate* isolate);
473   static void GeneralizeField(Handle<Map> map, int modify_index,
474                               PropertyConstness new_constness,
475                               Representation new_representation,
476                               Handle<FieldType> new_field_type);
477   // Returns true if |descriptor|'th property is a field that may be generalized
478   // by just updating current map.
479   static inline bool IsInplaceGeneralizableField(PropertyConstness constness,
480                                                  Representation representation,
481                                                  FieldType* field_type);
482 
483   // Generalizes constness, representation and field_type if objects with given
484   // instance type can have fast elements that can be transitioned by stubs or
485   // optimized code to more general elements kind.
486   // This generalization is necessary in order to ensure that elements kind
487   // transitions performed by stubs / optimized code don't silently transition
488   // kMutable fields back to kConst state or fields with HeapObject
489   // representation and "Any" type back to "Class" type.
490   static inline void GeneralizeIfCanHaveTransitionableFastElementsKind(
491       Isolate* isolate, InstanceType instance_type,
492       PropertyConstness* constness, Representation* representation,
493       Handle<FieldType>* field_type);
494 
495   static Handle<Map> ReconfigureProperty(Handle<Map> map, int modify_index,
496                                          PropertyKind new_kind,
497                                          PropertyAttributes new_attributes,
498                                          Representation new_representation,
499                                          Handle<FieldType> new_field_type);
500 
501   static Handle<Map> ReconfigureElementsKind(Handle<Map> map,
502                                              ElementsKind new_elements_kind);
503 
504   static Handle<Map> PrepareForDataProperty(Handle<Map> old_map,
505                                             int descriptor_number,
506                                             PropertyConstness constness,
507                                             Handle<Object> value);
508 
509   static Handle<Map> Normalize(Handle<Map> map, PropertyNormalizationMode mode,
510                                const char* reason);
511 
512   // Tells whether the map is used for JSObjects in dictionary mode (ie
513   // normalized objects, ie objects for which HasFastProperties returns false).
514   // A map can never be used for both dictionary mode and fast mode JSObjects.
515   // False by default and for HeapObjects that are not JSObjects.
516   DECL_BOOLEAN_ACCESSORS(is_dictionary_map)
517 
518   // Tells whether the instance needs security checks when accessing its
519   // properties.
520   DECL_BOOLEAN_ACCESSORS(is_access_check_needed)
521 
522   // [prototype]: implicit prototype object.
523   DECL_ACCESSORS(prototype, Object)
524   // TODO(jkummerow): make set_prototype private.
525   static void SetPrototype(Handle<Map> map, Handle<Object> prototype,
526                            bool enable_prototype_setup_mode = true);
527 
528   // [constructor]: points back to the function or FunctionTemplateInfo
529   // responsible for this map.
530   // The field overlaps with the back pointer. All maps in a transition tree
531   // have the same constructor, so maps with back pointers can walk the
532   // back pointer chain until they find the map holding their constructor.
533   // Returns null_value if there's neither a constructor function nor a
534   // FunctionTemplateInfo available.
535   DECL_ACCESSORS(constructor_or_backpointer, Object)
536   inline Object* GetConstructor() const;
537   inline FunctionTemplateInfo* GetFunctionTemplateInfo() const;
538   inline void SetConstructor(Object* constructor,
539                              WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
540   // [back pointer]: points back to the parent map from which a transition
541   // leads to this map. The field overlaps with the constructor (see above).
542   inline Object* GetBackPointer() const;
543   inline void SetBackPointer(Object* value,
544                              WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
545 
546   // [instance descriptors]: describes the object.
547   DECL_ACCESSORS(instance_descriptors, DescriptorArray)
548 
549   // [layout descriptor]: describes the object layout.
550   DECL_ACCESSORS(layout_descriptor, LayoutDescriptor)
551   // |layout descriptor| accessor which can be used from GC.
552   inline LayoutDescriptor* layout_descriptor_gc_safe() const;
553   inline bool HasFastPointerLayout() const;
554 
555   // |layout descriptor| accessor that is safe to call even when
556   // FLAG_unbox_double_fields is disabled (in this case Map does not contain
557   // |layout_descriptor| field at all).
558   inline LayoutDescriptor* GetLayoutDescriptor() const;
559 
560   inline void UpdateDescriptors(DescriptorArray* descriptors,
561                                 LayoutDescriptor* layout_descriptor);
562   inline void InitializeDescriptors(DescriptorArray* descriptors,
563                                     LayoutDescriptor* layout_descriptor);
564 
565   // [dependent code]: list of optimized codes that weakly embed this map.
566   DECL_ACCESSORS(dependent_code, DependentCode)
567 
568   // [weak cell cache]: cache that stores a weak cell pointing to this map.
569   DECL_ACCESSORS(weak_cell_cache, Object)
570 
571   // [prototype_validity_cell]: Cell containing the validity bit for prototype
572   // chains or Smi(0) if uninitialized.
573   // The meaning of this validity cell is different for prototype maps and
574   // non-prototype maps.
575   // For prototype maps the validity bit "guards" modifications of prototype
576   // chains going through this object. When a prototype object changes, both its
577   // own validity cell and those of all "downstream" prototypes are invalidated;
578   // handlers for a given receiver embed the currently valid cell for that
579   // receiver's prototype during their creation and check it on execution.
580   // For non-prototype maps which are used as transitioning store handlers this
581   // field contains the validity cell which guards modifications of this map's
582   // prototype.
583   DECL_ACCESSORS(prototype_validity_cell, Object)
584 
585   // Returns true if prototype validity cell value represents "valid" prototype
586   // chain state.
587   inline bool IsPrototypeValidityCellValid() const;
588 
589   inline PropertyDetails GetLastDescriptorDetails() const;
590 
591   inline int LastAdded() const;
592 
593   inline int NumberOfOwnDescriptors() const;
594   inline void SetNumberOfOwnDescriptors(int number);
595 
596   inline Cell* RetrieveDescriptorsPointer();
597 
598   // Checks whether all properties are stored either in the map or on the object
599   // (inobject, properties, or elements backing store), requiring no special
600   // checks.
601   bool OnlyHasSimpleProperties() const;
602   inline int EnumLength() const;
603   inline void SetEnumLength(int length);
604 
605   DECL_BOOLEAN_ACCESSORS(owns_descriptors)
606 
607   inline void mark_unstable();
608   inline bool is_stable() const;
609 
610   DECL_BOOLEAN_ACCESSORS(is_migration_target)
611 
612   DECL_BOOLEAN_ACCESSORS(is_immutable_proto)
613 
614   // This counter is used for in-object slack tracking.
615   // The in-object slack tracking is considered enabled when the counter is
616   // non zero. The counter only has a valid count for initial maps. For
617   // transitioned maps only kNoSlackTracking has a meaning, namely that inobject
618   // slack tracking already finished for the transition tree. Any other value
619   // indicates that either inobject slack tracking is still in progress, or that
620   // the map isn't part of the transition tree anymore.
621   DECL_INT_ACCESSORS(construction_counter)
622 
623   DECL_BOOLEAN_ACCESSORS(is_deprecated)
624   inline bool CanBeDeprecated() const;
625   // Returns a non-deprecated version of the input. If the input was not
626   // deprecated, it is directly returned. Otherwise, the non-deprecated version
627   // is found by re-transitioning from the root of the transition tree using the
628   // descriptor array of the map. Returns MaybeHandle<Map>() if no updated map
629   // is found.
630   static MaybeHandle<Map> TryUpdate(Handle<Map> map) V8_WARN_UNUSED_RESULT;
631 
632   // Returns a non-deprecated version of the input. This method may deprecate
633   // existing maps along the way if encodings conflict. Not for use while
634   // gathering type feedback. Use TryUpdate in those cases instead.
635   static Handle<Map> Update(Handle<Map> map);
636 
637   static inline Handle<Map> CopyInitialMap(Handle<Map> map);
638   static Handle<Map> CopyInitialMap(Handle<Map> map, int instance_size,
639                                     int in_object_properties,
640                                     int unused_property_fields);
641   static Handle<Map> CopyInitialMapNormalized(
642       Handle<Map> map,
643       PropertyNormalizationMode mode = CLEAR_INOBJECT_PROPERTIES);
644   static Handle<Map> CopyDropDescriptors(Handle<Map> map);
645   static Handle<Map> CopyInsertDescriptor(Handle<Map> map,
646                                           Descriptor* descriptor,
647                                           TransitionFlag flag);
648 
649   static Handle<Object> WrapFieldType(Handle<FieldType> type);
650   static FieldType* UnwrapFieldType(Object* wrapped_type);
651 
652   V8_WARN_UNUSED_RESULT static MaybeHandle<Map> CopyWithField(
653       Handle<Map> map, Handle<Name> name, Handle<FieldType> type,
654       PropertyAttributes attributes, PropertyConstness constness,
655       Representation representation, TransitionFlag flag);
656 
657   V8_WARN_UNUSED_RESULT static MaybeHandle<Map> CopyWithConstant(
658       Handle<Map> map, Handle<Name> name, Handle<Object> constant,
659       PropertyAttributes attributes, TransitionFlag flag);
660 
661   // Returns a new map with all transitions dropped from the given map and
662   // the ElementsKind set.
663   static Handle<Map> TransitionElementsTo(Handle<Map> map,
664                                           ElementsKind to_kind);
665 
666   static Handle<Map> AsElementsKind(Handle<Map> map, ElementsKind kind);
667 
668   static Handle<Map> CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
669                                         TransitionFlag flag);
670 
671   static Handle<Map> AsLanguageMode(Handle<Map> initial_map,
672                                     Handle<SharedFunctionInfo> shared_info);
673 
674   static Handle<Map> CopyForPreventExtensions(Handle<Map> map,
675                                               PropertyAttributes attrs_to_add,
676                                               Handle<Symbol> transition_marker,
677                                               const char* reason);
678 
679   static Handle<Map> FixProxy(Handle<Map> map, InstanceType type, int size);
680 
681   // Maximal number of fast properties. Used to restrict the number of map
682   // transitions to avoid an explosion in the number of maps for objects used as
683   // dictionaries.
684   inline bool TooManyFastProperties(StoreFromKeyed store_mode) const;
685   static Handle<Map> TransitionToDataProperty(Handle<Map> map,
686                                               Handle<Name> name,
687                                               Handle<Object> value,
688                                               PropertyAttributes attributes,
689                                               PropertyConstness constness,
690                                               StoreFromKeyed store_mode);
691   static Handle<Map> TransitionToAccessorProperty(
692       Isolate* isolate, Handle<Map> map, Handle<Name> name, int descriptor,
693       Handle<Object> getter, Handle<Object> setter,
694       PropertyAttributes attributes);
695   static Handle<Map> ReconfigureExistingProperty(Handle<Map> map,
696                                                  int descriptor,
697                                                  PropertyKind kind,
698                                                  PropertyAttributes attributes);
699 
700   inline void AppendDescriptor(Descriptor* desc);
701 
702   // Returns a copy of the map, prepared for inserting into the transition
703   // tree (if the |map| owns descriptors then the new one will share
704   // descriptors with |map|).
705   static Handle<Map> CopyForTransition(Handle<Map> map, const char* reason);
706 
707   // Returns a copy of the map, with all transitions dropped from the
708   // instance descriptors.
709   static Handle<Map> Copy(Handle<Map> map, const char* reason);
710   static Handle<Map> Create(Isolate* isolate, int inobject_properties);
711 
712   // Returns the next free property index (only valid for FAST MODE).
713   int NextFreePropertyIndex() const;
714 
715   // Returns the number of enumerable properties.
716   int NumberOfEnumerableProperties() const;
717 
718   DECL_CAST(Map)
719 
720   static inline int SlackForArraySize(int old_size, int size_limit);
721 
722   static void EnsureDescriptorSlack(Handle<Map> map, int slack);
723 
724   // Returns the map to be used for instances when the given {prototype} is
725   // passed to an Object.create call. Might transition the given {prototype}.
726   static Handle<Map> GetObjectCreateMap(Handle<HeapObject> prototype);
727 
728   // Similar to {GetObjectCreateMap} but does not transition {prototype} and
729   // fails gracefully by returning an empty handle instead.
730   static MaybeHandle<Map> TryGetObjectCreateMap(Handle<HeapObject> prototype);
731 
732   // Computes a hash value for this map, to be used in HashTables and such.
733   int Hash();
734 
735   // Returns the transitioned map for this map with the most generic
736   // elements_kind that's found in |candidates|, or |nullptr| if no match is
737   // found at all.
738   Map* FindElementsKindTransitionedMap(MapHandles const& candidates);
739 
740   inline static bool IsJSObject(InstanceType type);
741 
742   inline bool CanTransition() const;
743 
744   inline bool IsBooleanMap() const;
745   inline bool IsPrimitiveMap() const;
746   inline bool IsJSReceiverMap() const;
747   inline bool IsJSObjectMap() const;
748   inline bool IsJSPromiseMap() const;
749   inline bool IsJSArrayMap() const;
750   inline bool IsJSFunctionMap() const;
751   inline bool IsStringMap() const;
752   inline bool IsJSProxyMap() const;
753   inline bool IsModuleMap() const;
754   inline bool IsJSGlobalProxyMap() const;
755   inline bool IsJSGlobalObjectMap() const;
756   inline bool IsJSTypedArrayMap() const;
757   inline bool IsJSDataViewMap() const;
758 
759   inline bool IsSpecialReceiverMap() const;
760 
761   inline bool IsCustomElementsReceiverMap() const;
762 
763   static void AddDependentCode(Handle<Map> map,
764                                DependentCode::DependencyGroup group,
765                                Handle<Code> code);
766 
767   bool IsMapInArrayPrototypeChain() const;
768 
769   static Handle<WeakCell> WeakCellForMap(Handle<Map> map);
770 
771   // Dispatched behavior.
772   DECL_PRINTER(Map)
773   DECL_VERIFIER(Map)
774 
775 #ifdef VERIFY_HEAP
776   void DictionaryMapVerify();
777 #endif
778 
779   DECL_PRIMITIVE_ACCESSORS(visitor_id, VisitorId)
780 
781   static Handle<Map> TransitionToPrototype(Handle<Map> map,
782                                            Handle<Object> prototype);
783 
784   static Handle<Map> TransitionToImmutableProto(Handle<Map> map);
785 
786   static const int kMaxPreAllocatedPropertyFields = 255;
787 
788   // Layout description.
789 #define MAP_FIELDS(V)                                                       \
790   /* Raw data fields. */                                                    \
791   V(kInstanceSizeInWordsOffset, kUInt8Size)                                 \
792   V(kInObjectPropertiesStartOrConstructorFunctionIndexOffset, kUInt8Size)   \
793   V(kUsedOrUnusedInstanceSizeInWordsOffset, kUInt8Size)                     \
794   V(kVisitorIdOffset, kUInt8Size)                                           \
795   V(kInstanceTypeOffset, kUInt16Size)                                       \
796   V(kBitFieldOffset, kUInt8Size)                                            \
797   V(kBitField2Offset, kUInt8Size)                                           \
798   V(kBitField3Offset, kUInt32Size)                                          \
799   V(k64BitArchPaddingOffset, kPointerSize == kUInt32Size ? 0 : kUInt32Size) \
800   /* Pointer fields. */                                                     \
801   V(kPointerFieldsBeginOffset, 0)                                           \
802   V(kPrototypeOffset, kPointerSize)                                         \
803   V(kConstructorOrBackPointerOffset, kPointerSize)                          \
804   V(kTransitionsOrPrototypeInfoOffset, kPointerSize)                        \
805   V(kDescriptorsOffset, kPointerSize)                                       \
806   V(kLayoutDescriptorOffset, FLAG_unbox_double_fields ? kPointerSize : 0)   \
807   V(kDependentCodeOffset, kPointerSize)                                     \
808   V(kWeakCellCacheOffset, kPointerSize)                                     \
809   V(kPrototypeValidityCellOffset, kPointerSize)                             \
810   V(kPointerFieldsEndOffset, 0)                                             \
811   /* Total size. */                                                         \
812   V(kSize, 0)
813 
814   DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, MAP_FIELDS)
815 #undef MAP_FIELDS
816 
817   STATIC_ASSERT(kInstanceTypeOffset == Internals::kMapInstanceTypeOffset);
818 
819   class BodyDescriptor;
820 
821   // Compares this map to another to see if they describe equivalent objects.
822   // If |mode| is set to CLEAR_INOBJECT_PROPERTIES, |other| is treated as if
823   // it had exactly zero inobject properties.
824   // The "shared" flags of both this map and |other| are ignored.
825   bool EquivalentToForNormalization(const Map* other,
826                                     PropertyNormalizationMode mode) const;
827 
828   // Returns true if given field is unboxed double.
829   inline bool IsUnboxedDoubleField(FieldIndex index) const;
830 
831   void PrintMapDetails(std::ostream& os, JSObject* holder = nullptr);
832 
833   static inline Handle<Map> AddMissingTransitionsForTesting(
834       Handle<Map> split_map, Handle<DescriptorArray> descriptors,
835       Handle<LayoutDescriptor> full_layout_descriptor);
836 
837   // Fires when the layout of an object with a leaf map changes.
838   // This includes adding transitions to the leaf map or changing
839   // the descriptor array.
840   inline void NotifyLeafMapLayoutChange();
841 
842   static VisitorId GetVisitorId(Map* map);
843 
844   // Returns true if objects with given instance type are allowed to have
845   // fast transitionable elements kinds. This predicate is used to ensure
846   // that objects that can have transitionable fast elements kind will not
847   // get in-place generalizable fields because the elements kind transition
848   // performed by stubs or optimized code can't properly generalize such
849   // fields.
850   static inline bool CanHaveFastTransitionableElementsKind(
851       InstanceType instance_type);
852   inline bool CanHaveFastTransitionableElementsKind() const;
853 
854  private:
855   // This byte encodes either the instance size without the in-object slack or
856   // the slack size in properties backing store.
857   // Let H be JSObject::kHeaderSize / kPointerSize.
858   // If value >= H then:
859   //     - all field properties are stored in the object.
860   //     - there is no property array.
861   //     - value * kPointerSize is the actual object size without the slack.
862   // Otherwise:
863   //     - there is no slack in the object.
864   //     - the property array has value slack slots.
865   // Note that this encoding requires that H = JSObject::kFieldsAdded.
866   DECL_INT_ACCESSORS(used_or_unused_instance_size_in_words)
867 
868   // Returns the map that this (root) map transitions to if its elements_kind
869   // is changed to |elements_kind|, or |nullptr| if no such map is cached yet.
870   Map* LookupElementsTransitionMap(ElementsKind elements_kind);
871 
872   // Tries to replay property transitions starting from this (root) map using
873   // the descriptor array of the |map|. The |root_map| is expected to have
874   // proper elements kind and therefore elements kinds transitions are not
875   // taken by this function. Returns |nullptr| if matching transition map is
876   // not found.
877   Map* TryReplayPropertyTransitions(Map* map);
878 
879   static void ConnectTransition(Handle<Map> parent, Handle<Map> child,
880                                 Handle<Name> name, SimpleTransitionFlag flag);
881 
882   bool EquivalentToForTransition(const Map* other) const;
883   bool EquivalentToForElementsKindTransition(const Map* other) const;
884   static Handle<Map> RawCopy(Handle<Map> map, int instance_size,
885                              int inobject_properties);
886   static Handle<Map> ShareDescriptor(Handle<Map> map,
887                                      Handle<DescriptorArray> descriptors,
888                                      Descriptor* descriptor);
889   static Handle<Map> AddMissingTransitions(
890       Handle<Map> map, Handle<DescriptorArray> descriptors,
891       Handle<LayoutDescriptor> full_layout_descriptor);
892   static void InstallDescriptors(
893       Handle<Map> parent_map, Handle<Map> child_map, int new_descriptor,
894       Handle<DescriptorArray> descriptors,
895       Handle<LayoutDescriptor> full_layout_descriptor);
896   static Handle<Map> CopyAddDescriptor(Handle<Map> map, Descriptor* descriptor,
897                                        TransitionFlag flag);
898   static Handle<Map> CopyReplaceDescriptors(
899       Handle<Map> map, Handle<DescriptorArray> descriptors,
900       Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
901       MaybeHandle<Name> maybe_name, const char* reason,
902       SimpleTransitionFlag simple_flag);
903 
904   static Handle<Map> CopyReplaceDescriptor(Handle<Map> map,
905                                            Handle<DescriptorArray> descriptors,
906                                            Descriptor* descriptor, int index,
907                                            TransitionFlag flag);
908   static V8_WARN_UNUSED_RESULT MaybeHandle<Map> TryReconfigureExistingProperty(
909       Handle<Map> map, int descriptor, PropertyKind kind,
910       PropertyAttributes attributes, const char** reason);
911 
912   static Handle<Map> CopyNormalized(Handle<Map> map,
913                                     PropertyNormalizationMode mode);
914 
915   // TODO(ishell): Move to MapUpdater.
916   static Handle<Map> CopyGeneralizeAllFields(
917       Handle<Map> map, ElementsKind elements_kind, int modify_index,
918       PropertyKind kind, PropertyAttributes attributes, const char* reason);
919 
920   void DeprecateTransitionTree();
921 
922   void ReplaceDescriptors(DescriptorArray* new_descriptors,
923                           LayoutDescriptor* new_layout_descriptor);
924 
925   // Update field type of the given descriptor to new representation and new
926   // type. The type must be prepared for storing in descriptor array:
927   // it must be either a simple type or a map wrapped in a weak cell.
928   void UpdateFieldType(int descriptor_number, Handle<Name> name,
929                        PropertyConstness new_constness,
930                        Representation new_representation,
931                        Handle<Object> new_wrapped_type);
932 
933   // TODO(ishell): Move to MapUpdater.
934   void PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
935                             PropertyAttributes attributes);
936   // TODO(ishell): Move to MapUpdater.
937   void PrintGeneralization(FILE* file, const char* reason, int modify_index,
938                            int split, int descriptors, bool constant_to_field,
939                            Representation old_representation,
940                            Representation new_representation,
941                            MaybeHandle<FieldType> old_field_type,
942                            MaybeHandle<Object> old_value,
943                            MaybeHandle<FieldType> new_field_type,
944                            MaybeHandle<Object> new_value);
945   static const int kFastPropertiesSoftLimit = 12;
946   static const int kMaxFastProperties = 128;
947 
948   friend class MapUpdater;
949 
950   DISALLOW_IMPLICIT_CONSTRUCTORS(Map);
951 };
952 
953 // The cache for maps used by normalized (dictionary mode) objects.
954 // Such maps do not have property descriptors, so a typical program
955 // needs very limited number of distinct normalized maps.
956 class NormalizedMapCache : public FixedArray {
957  public:
958   static Handle<NormalizedMapCache> New(Isolate* isolate);
959 
960   V8_WARN_UNUSED_RESULT MaybeHandle<Map> Get(Handle<Map> fast_map,
961                                              PropertyNormalizationMode mode);
962   void Set(Handle<Map> fast_map, Handle<Map> normalized_map,
963            Handle<WeakCell> normalized_map_weak_cell);
964 
965   void Clear();
966 
967   DECL_CAST(NormalizedMapCache)
968 
969   static inline bool IsNormalizedMapCache(const HeapObject* obj);
970 
971   DECL_VERIFIER(NormalizedMapCache)
972  private:
973   static const int kEntries = 64;
974 
975   static inline int GetIndex(Handle<Map> map);
976 
977   // The following declarations hide base class methods.
978   Object* get(int index);
979   void set(int index, Object* value);
980 };
981 
982 }  // namespace internal
983 }  // namespace v8
984 
985 #include "src/objects/object-macros-undef.h"
986 
987 #endif  // V8_OBJECTS_MAP_H_
988