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