map.h 47 KB
Newer Older
1 2 3 4 5 6 7 8
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_OBJECTS_MAP_H_
#define V8_OBJECTS_MAP_H_

#include "src/objects.h"
9
#include "src/objects/code.h"
10 11 12 13 14 15 16 17 18

#include "src/globals.h"

// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"

namespace v8 {
namespace internal {

19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
#define VISITOR_ID_LIST(V)               \
  V(AllocationSite)                      \
  V(BigInt)                              \
  V(ByteArray)                           \
  V(BytecodeArray)                       \
  V(Cell)                                \
  V(Code)                                \
  V(CodeDataContainer)                   \
  V(ConsString)                          \
  V(DataHandler)                         \
  V(DataObject)                          \
  V(EphemeronHashTable)                  \
  V(FeedbackCell)                        \
  V(FeedbackVector)                      \
  V(FixedArray)                          \
  V(FixedDoubleArray)                    \
  V(FixedFloat64Array)                   \
  V(FixedTypedArrayBase)                 \
  V(FreeSpace)                           \
  V(JSApiObject)                         \
  V(JSArrayBuffer)                       \
  V(JSFunction)                          \
  V(JSObject)                            \
  V(JSObjectFast)                        \
  V(JSWeakCollection)                    \
  V(Map)                                 \
  V(NativeContext)                       \
  V(Oddball)                             \
  V(PreParsedScopeData)                  \
  V(PropertyArray)                       \
  V(PropertyCell)                        \
  V(PrototypeInfo)                       \
  V(SeqOneByteString)                    \
  V(SeqTwoByteString)                    \
  V(SharedFunctionInfo)                  \
  V(ShortcutCandidate)                   \
  V(SlicedString)                        \
  V(SmallOrderedHashMap)                 \
  V(SmallOrderedHashSet)                 \
  V(Struct)                              \
  V(Symbol)                              \
  V(ThinString)                          \
  V(TransitionArray)                     \
  V(UncompiledDataWithoutPreParsedScope) \
  V(UncompiledDataWithPreParsedScope)    \
  V(WasmInstanceObject)                  \
  V(WeakCell)                            \
66
  V(WeakArray)
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83

// For data objects, JS objects and structs along with generic visitor which
// can visit object of any size we provide visitors specialized by
// object size in words.
// Ids of specialized visitors are declared in a linear order (without
// holes) starting from the id of visitor specialized for 2 words objects
// (base visitor id) and ending with the id of generic visitor.
// Method GetVisitorIdForSize depends on this ordering to calculate visitor
// id of specialized visitor from given instance size, base visitor id and
// generic visitor's id.
enum VisitorId {
#define VISITOR_ID_ENUM_DECL(id) kVisit##id,
  VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL)
#undef VISITOR_ID_ENUM_DECL
      kVisitorIdCount
};

84 85 86 87 88 89
typedef std::vector<Handle<Map>> MapHandles;

// All heap objects have a Map that describes their structure.
//  A Map contains information about:
//  - Size information about the object
//  - How to iterate over an object (for garbage collection)
90 91 92 93 94 95 96
//
// Map layout:
// +---------------+---------------------------------------------+
// |   _ Type _    | _ Description _                             |
// +---------------+---------------------------------------------+
// | TaggedPointer | map - Always a pointer to the MetaMap root  |
// +---------------+---------------------------------------------+
97
// | Int           | The first int field                         |
98 99 100 101 102 103
//  `---+----------+---------------------------------------------+
//      | Byte     | [instance_size]                             |
//      +----------+---------------------------------------------+
//      | Byte     | If Map for a primitive type:                |
//      |          |   native context index for constructor fn   |
//      |          | If Map for an Object type:                  |
104
//      |          |   inobject properties start offset in words |
105
//      +----------+---------------------------------------------+
106
//      | Byte     | [used_or_unused_instance_size_in_words]     |
107 108
//      |          | For JSObject in fast mode this byte encodes |
//      |          | the size of the object that includes only   |
109 110
//      |          | the used property fields or the slack size  |
//      |          | in properties backing store.                |
111 112 113
//      +----------+---------------------------------------------+
//      | Byte     | [visitor_id]                                |
// +----+----------+---------------------------------------------+
114
// | Int           | The second int field                        |
115
//  `---+----------+---------------------------------------------+
116
//      | Short    | [instance_type]                             |
117 118
//      +----------+---------------------------------------------+
//      | Byte     | [bit_field]                                 |
119 120 121 122 123 124 125
//      |          |   - has_non_instance_prototype (bit 0)      |
//      |          |   - is_callable (bit 1)                     |
//      |          |   - has_named_interceptor (bit 2)           |
//      |          |   - has_indexed_interceptor (bit 3)         |
//      |          |   - is_undetectable (bit 4)                 |
//      |          |   - is_access_check_needed (bit 5)          |
//      |          |   - is_constructor (bit 6)                  |
126
//      |          |   - has_prototype_slot (bit 7)              |
127 128 129
//      +----------+---------------------------------------------+
//      | Byte     | [bit_field2]                                |
//      |          |   - is_extensible (bit 0)                   |
130 131
//      |          |   - is_prototype_map (bit 1)                |
//      |          |   - is_in_retained_map_list (bit 2)         |
132 133
//      |          |   - elements_kind (bits 3..7)               |
// +----+----------+---------------------------------------------+
134
// | Int           | [bit_field3]                                |
135 136
// |               |   - enum_length (bit 0..9)                  |
// |               |   - number_of_own_descriptors (bit 10..19)  |
137 138 139 140 141 142 143 144 145 146 147
// |               |   - is_dictionary_map (bit 20)              |
// |               |   - owns_descriptors (bit 21)               |
// |               |   - has_hidden_prototype (bit 22)           |
// |               |   - is_deprecated (bit 23)                  |
// |               |   - is_unstable (bit 24)                    |
// |               |   - is_migration_target (bit 25)            |
// |               |   - is_immutable_proto (bit 26)             |
// |               |   - new_target_is_base (bit 27)             |
// |               |   - may_have_interesting_symbols (bit 28)   |
// |               |   - construction_counter (bit 29..31)       |
// |               |                                             |
148 149
// +*************************************************************+
// | Int           | On systems with 64bit pointer types, there  |
150
// |               | is an unused 32bits after bit_field3        |
151
// +*************************************************************+
152 153 154 155 156 157 158 159 160 161 162 163
// | TaggedPointer | [prototype]                                 |
// +---------------+---------------------------------------------+
// | TaggedPointer | [constructor_or_backpointer]                |
// +---------------+---------------------------------------------+
// | TaggedPointer | If Map is a prototype map:                  |
// |               |   [prototype_info]                          |
// |               | Else:                                       |
// |               |   [raw_transitions]                         |
// +---------------+---------------------------------------------+
// | TaggedPointer | [instance_descriptors]                      |
// +*************************************************************+
// ! TaggedPointer ! [layout_descriptors]                        !
164 165 166
// !               ! Field is only present if compile-time flag  !
// !               ! FLAG_unbox_double_fields is enabled         !
// !               ! (basically on 64 bit architectures)         !
167 168 169 170
// +*************************************************************+
// | TaggedPointer | [dependent_code]                            |
// +---------------+---------------------------------------------+

171 172 173 174 175
class Map : public HeapObject {
 public:
  // Instance size.
  // Size in bytes or kVariableSizeSentinel if instances do not have
  // a fixed size.
176
  DECL_INT_ACCESSORS(instance_size)
177 178 179
  // Size in words or kVariableSizeSentinel if instances do not have
  // a fixed size.
  DECL_INT_ACCESSORS(instance_size_in_words)
180

181 182 183 184
  // [inobject_properties_start_or_constructor_function_index]:
  // Provides access to the inobject properties start offset in words in case of
  // JSObject maps, or the constructor function index in case of primitive maps.
  DECL_INT_ACCESSORS(inobject_properties_start_or_constructor_function_index)
185

186 187 188
  // Get/set the in-object property area start offset in words in the object.
  inline int GetInObjectPropertiesStartInWords() const;
  inline void SetInObjectPropertiesStartInWords(int value);
189
  // Count of properties allocated in the object (JSObject only).
190
  inline int GetInObjectProperties() const;
191 192 193 194
  // Index of the constructor function in the native context (primitives only),
  // or the special sentinel value to indicate that there is no object wrapper
  // for the primitive (i.e. in case of null or undefined).
  static const int kNoConstructorFunctionIndex = 0;
195
  inline int GetConstructorFunctionIndex() const;
196 197 198 199 200 201 202 203 204
  inline void SetConstructorFunctionIndex(int value);
  static MaybeHandle<JSFunction> GetConstructorFunction(
      Handle<Map> map, Handle<Context> native_context);

  // Retrieve interceptors.
  inline InterceptorInfo* GetNamedInterceptor();
  inline InterceptorInfo* GetIndexedInterceptor();

  // Instance type.
205
  DECL_PRIMITIVE_ACCESSORS(instance_type, InstanceType)
206

207 208 209
  // Returns the size of the used in-object area including object header
  // (only used for JSObject in fast mode, for the other kinds of objects it
  // is equal to the instance size).
210
  inline int UsedInstanceSize() const;
211

212 213
  // Tells how many unused property fields (in-object or out-of object) are
  // available in the instance (only used for JSObject in fast mode).
214
  inline int UnusedPropertyFields() const;
215 216
  // Tells how many unused in-object property words are present.
  inline int UnusedInObjectProperties() const;
217 218 219 220 221
  // Updates the counters tracking unused fields in the object.
  inline void SetInObjectUnusedPropertyFields(int unused_property_fields);
  // Updates the counters tracking unused fields in the property array.
  inline void SetOutOfObjectUnusedPropertyFields(int unused_property_fields);
  inline void CopyUnusedPropertyFields(Map* map);
222
  inline void CopyUnusedPropertyFieldsAdjustedForInstanceSize(Map* map);
223 224 225 226
  inline void AccountAddedPropertyField();
  inline void AccountAddedOutOfObjectPropertyField(
      int unused_in_property_array);

227
  //
228
  // Bit field.
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
  //
  DECL_PRIMITIVE_ACCESSORS(bit_field, byte)

// Bit positions for |bit_field|.
#define MAP_BIT_FIELD_FIELDS(V, _)          \
  V(HasNonInstancePrototypeBit, bool, 1, _) \
  V(IsCallableBit, bool, 1, _)              \
  V(HasNamedInterceptorBit, bool, 1, _)     \
  V(HasIndexedInterceptorBit, bool, 1, _)   \
  V(IsUndetectableBit, bool, 1, _)          \
  V(IsAccessCheckNeededBit, bool, 1, _)     \
  V(IsConstructorBit, bool, 1, _)           \
  V(HasPrototypeSlotBit, bool, 1, _)

  DEFINE_BIT_FIELDS(MAP_BIT_FIELD_FIELDS)
#undef MAP_BIT_FIELD_FIELDS
245

246
  //
247
  // Bit field 2.
248 249
  //
  DECL_PRIMITIVE_ACCESSORS(bit_field2, byte)
250

251
// Bit positions for |bit_field2|.
252 253 254 255
#define MAP_BIT_FIELD2_FIELDS(V, _)     \
  V(IsExtensibleBit, bool, 1, _)        \
  V(IsPrototypeMapBit, bool, 1, _)      \
  V(IsInRetainedMapListBit, bool, 1, _) \
256 257 258 259 260 261
  V(ElementsKindBits, ElementsKind, 5, _)

  DEFINE_BIT_FIELDS(MAP_BIT_FIELD2_FIELDS)
#undef MAP_BIT_FIELD2_FIELDS

  //
262
  // Bit field 3.
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
  //
  DECL_PRIMITIVE_ACCESSORS(bit_field3, uint32_t)

// Bit positions for |bit_field3|.
#define MAP_BIT_FIELD3_FIELDS(V, _)                               \
  V(EnumLengthBits, int, kDescriptorIndexBitCount, _)             \
  V(NumberOfOwnDescriptorsBits, int, kDescriptorIndexBitCount, _) \
  V(IsDictionaryMapBit, bool, 1, _)                               \
  V(OwnsDescriptorsBit, bool, 1, _)                               \
  V(HasHiddenPrototypeBit, bool, 1, _)                            \
  V(IsDeprecatedBit, bool, 1, _)                                  \
  V(IsUnstableBit, bool, 1, _)                                    \
  V(IsMigrationTargetBit, bool, 1, _)                             \
  V(IsImmutablePrototypeBit, bool, 1, _)                          \
  V(NewTargetIsBaseBit, bool, 1, _)                               \
  V(MayHaveInterestingSymbolsBit, bool, 1, _)                     \
  V(ConstructionCounterBits, int, 3, _)

  DEFINE_BIT_FIELDS(MAP_BIT_FIELD3_FIELDS)
#undef MAP_BIT_FIELD3_FIELDS

284 285
  STATIC_ASSERT(NumberOfOwnDescriptorsBits::kMax >= kMaxNumberOfDescriptors);

286 287 288
  static const int kSlackTrackingCounterStart = 7;
  static const int kSlackTrackingCounterEnd = 1;
  static const int kNoSlackTracking = 0;
289
  STATIC_ASSERT(kSlackTrackingCounterStart <= ConstructionCounterBits::kMax);
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327

  // Inobject slack tracking is the way to reclaim unused inobject space.
  //
  // The instance size is initially determined by adding some slack to
  // expected_nof_properties (to allow for a few extra properties added
  // after the constructor). There is no guarantee that the extra space
  // will not be wasted.
  //
  // Here is the algorithm to reclaim the unused inobject space:
  // - Detect the first constructor call for this JSFunction.
  //   When it happens enter the "in progress" state: initialize construction
  //   counter in the initial_map.
  // - While the tracking is in progress initialize unused properties of a new
  //   object with one_pointer_filler_map instead of undefined_value (the "used"
  //   part is initialized with undefined_value as usual). This way they can
  //   be resized quickly and safely.
  // - Once enough objects have been created  compute the 'slack'
  //   (traverse the map transition tree starting from the
  //   initial_map and find the lowest value of unused_property_fields).
  // - Traverse the transition tree again and decrease the instance size
  //   of every map. Existing objects will resize automatically (they are
  //   filled with one_pointer_filler_map). All further allocations will
  //   use the adjusted instance size.
  // - SharedFunctionInfo's expected_nof_properties left unmodified since
  //   allocations made using different closures could actually create different
  //   kind of objects (see prototype inheritance pattern).
  //
  //  Important: inobject slack tracking is not attempted during the snapshot
  //  creation.

  static const int kGenerousAllocationCount =
      kSlackTrackingCounterStart - kSlackTrackingCounterEnd + 1;

  // Starts the tracking by initializing object constructions countdown counter.
  void StartInobjectSlackTracking();

  // True if the object constructions countdown counter is a range
  // [kSlackTrackingCounterEnd, kSlackTrackingCounterStart].
328
  inline bool IsInobjectSlackTrackingInProgress() const;
329 330

  // Does the tracking step.
331
  inline void InobjectSlackTrackingStep(Isolate* isolate);
332 333 334

  // Completes inobject slack tracking for the transition tree starting at this
  // initial map.
335
  void CompleteInobjectSlackTracking(Isolate* isolate);
336 337 338 339 340 341

  // Tells whether the object in the prototype property will be used
  // for instances created from this function.  If the prototype
  // property is set to a value that is not a JSObject, the prototype
  // property will not be used to create instances of the function.
  // See ECMA-262, 13.2.2.
342
  DECL_BOOLEAN_ACCESSORS(has_non_instance_prototype)
343 344 345

  // Tells whether the instance has a [[Construct]] internal method.
  // This property is implemented according to ES6, section 7.2.4.
346
  DECL_BOOLEAN_ACCESSORS(is_constructor)
347

348 349 350 351
  // Tells whether the instance with this map may have properties for
  // interesting symbols on it.
  // An "interesting symbol" is one for which Name::IsInterestingSymbol()
  // returns true, i.e. a well-known symbol like @@toStringTag.
352
  DECL_BOOLEAN_ACCESSORS(may_have_interesting_symbols)
353

354 355
  DECL_BOOLEAN_ACCESSORS(has_prototype_slot)

356
  // Tells whether the instance with this map has a hidden prototype.
357
  DECL_BOOLEAN_ACCESSORS(has_hidden_prototype)
358 359

  // Records and queries whether the instance has a named interceptor.
360
  DECL_BOOLEAN_ACCESSORS(has_named_interceptor)
361 362

  // Records and queries whether the instance has an indexed interceptor.
363
  DECL_BOOLEAN_ACCESSORS(has_indexed_interceptor)
364 365 366 367 368 369 370

  // Tells whether the instance is undetectable.
  // An undetectable object is a special class of JSObject: 'typeof' operator
  // returns undefined, ToBoolean returns false. Otherwise it behaves like
  // a normal JS object.  It is useful for implementing undetectable
  // document.all in Firefox & Safari.
  // See https://bugzilla.mozilla.org/show_bug.cgi?id=248549.
371
  DECL_BOOLEAN_ACCESSORS(is_undetectable)
372 373 374

  // Tells whether the instance has a [[Call]] internal method.
  // This property is implemented according to ES6, section 7.2.3.
375
  DECL_BOOLEAN_ACCESSORS(is_callable)
376

377 378 379
  DECL_BOOLEAN_ACCESSORS(new_target_is_base)
  DECL_BOOLEAN_ACCESSORS(is_extensible)
  DECL_BOOLEAN_ACCESSORS(is_prototype_map)
380
  inline bool is_abandoned_prototype_map() const;
381

382 383 384 385
  // Whether the instance has been added to the retained map list by
  // Heap::AddRetainedMap.
  DECL_BOOLEAN_ACCESSORS(is_in_retained_map_list)

386
  DECL_PRIMITIVE_ACCESSORS(elements_kind, ElementsKind)
387 388

  // Tells whether the instance has fast elements that are only Smis.
389
  inline bool has_fast_smi_elements() const;
390 391

  // Tells whether the instance has fast elements.
392 393 394 395 396 397 398 399 400
  inline bool has_fast_object_elements() const;
  inline bool has_fast_smi_or_object_elements() const;
  inline bool has_fast_double_elements() const;
  inline bool has_fast_elements() const;
  inline bool has_sloppy_arguments_elements() const;
  inline bool has_fast_sloppy_arguments_elements() const;
  inline bool has_fast_string_wrapper_elements() const;
  inline bool has_fixed_typed_array_elements() const;
  inline bool has_dictionary_elements() const;
401 402 403 404 405 406

  static bool IsValidElementsTransition(ElementsKind from_kind,
                                        ElementsKind to_kind);

  // Returns true if the current map doesn't have DICTIONARY_ELEMENTS but if a
  // map with DICTIONARY_ELEMENTS was found in the prototype chain.
407
  bool DictionaryElementsInPrototypeChainOnly(Isolate* isolate);
408

409
  inline Map* ElementsTransitionMap();
410

411
  inline FixedArrayBase* GetInitialElements() const;
412 413 414 415

  // [raw_transitions]: Provides access to the transitions storage field.
  // Don't call set_raw_transitions() directly to overwrite transitions, use
  // the TransitionArray::ReplaceTransitions() wrapper instead!
416
  DECL_ACCESSORS(raw_transitions, MaybeObject)
417 418 419 420 421 422 423 424 425 426 427 428 429 430
  // [prototype_info]: Per-prototype metadata. Aliased with transitions
  // (which prototype maps don't have).
  DECL_ACCESSORS(prototype_info, Object)
  // PrototypeInfo is created lazily using this helper (which installs it on
  // the given prototype's map).
  static Handle<PrototypeInfo> GetOrCreatePrototypeInfo(
      Handle<JSObject> prototype, Isolate* isolate);
  static Handle<PrototypeInfo> GetOrCreatePrototypeInfo(
      Handle<Map> prototype_map, Isolate* isolate);
  inline bool should_be_fast_prototype_map() const;
  static void SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
                                          Isolate* isolate);

  // [prototype chain validity cell]: Associated with a prototype object,
431 432 433 434 435 436 437
  // stored in that object's map, indicates that prototype chains through this
  // object are currently valid. The cell will be invalidated and replaced when
  // the prototype chain changes. When there's nothing to guard (for example,
  // when direct prototype is null or Proxy) this function returns Smi with
  // |kPrototypeChainValid| sentinel value.
  static Handle<Object> GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
                                                              Isolate* isolate);
438 439 440
  static const int kPrototypeChainValid = 0;
  static const int kPrototypeChainInvalid = 1;

441 442
  static bool IsPrototypeChainInvalidated(Map* map);

443
  // Return the map of the root of object's prototype chain.
444
  Map* GetPrototypeChainRootMap(Isolate* isolate) const;
445 446 447 448

  // Returns a WeakCell object containing given prototype. The cell is cached
  // in PrototypeInfo which is created lazily.
  static Handle<WeakCell> GetOrCreatePrototypeWeakCell(
449
      Handle<JSReceiver> prototype, Isolate* isolate);
450

451 452
  Map* FindRootMap(Isolate* isolate) const;
  Map* FindFieldOwner(Isolate* isolate, int descriptor) const;
453

454
  inline int GetInObjectPropertyOffset(int index) const;
455

456
  int NumberOfFields() const;
457

458 459
  bool HasOutOfObjectProperties() const;

460 461
  // Returns true if transition to the given map requires special
  // synchronization with the concurrent marker.
462
  bool TransitionRequiresSynchronizationWithGC(Map* target) const;
463 464
  // Returns true if transition to the given map removes a tagged in-object
  // field.
465
  bool TransitionRemovesTaggedField(Map* target) const;
466 467
  // Returns true if transition to the given map replaces a tagged in-object
  // field with an untagged in-object field.
468
  bool TransitionChangesTaggedFieldToUntaggedField(Map* target) const;
469 470

  // TODO(ishell): candidate with JSObject::MigrateToMap().
471
  bool InstancesNeedRewriting(Map* target) const;
472 473
  bool InstancesNeedRewriting(Map* target, int target_number_of_fields,
                              int target_inobject, int target_unused,
474
                              int* old_number_of_fields) const;
475
  // TODO(ishell): moveit!
476
  static Handle<Map> GeneralizeAllFields(Isolate* isolate, Handle<Map> map);
477
  V8_WARN_UNUSED_RESULT static Handle<FieldType> GeneralizeFieldType(
478 479
      Representation rep1, Handle<FieldType> type1, Representation rep2,
      Handle<FieldType> type2, Isolate* isolate);
480 481
  static void GeneralizeField(Isolate* isolate, Handle<Map> map,
                              int modify_index, PropertyConstness new_constness,
482 483
                              Representation new_representation,
                              Handle<FieldType> new_field_type);
484 485
  // Returns true if |descriptor|'th property is a field that may be generalized
  // by just updating current map.
486 487 488
  static inline bool IsInplaceGeneralizableField(PropertyConstness constness,
                                                 Representation representation,
                                                 FieldType* field_type);
489

490 491 492
  // Generalizes constness, representation and field_type if objects with given
  // instance type can have fast elements that can be transitioned by stubs or
  // optimized code to more general elements kind.
493 494
  // This generalization is necessary in order to ensure that elements kind
  // transitions performed by stubs / optimized code don't silently transition
495 496
  // PropertyConstness::kMutable fields back to VariableMode::kConst state or
  // fields with HeapObject representation and "Any" type back to "Class" type.
497 498
  static inline void GeneralizeIfCanHaveTransitionableFastElementsKind(
      Isolate* isolate, InstanceType instance_type,
499 500 501
      PropertyConstness* constness, Representation* representation,
      Handle<FieldType>* field_type);

502 503
  static Handle<Map> ReconfigureProperty(Isolate* isolate, Handle<Map> map,
                                         int modify_index,
504 505 506 507
                                         PropertyKind new_kind,
                                         PropertyAttributes new_attributes,
                                         Representation new_representation,
                                         Handle<FieldType> new_field_type);
508

509
  static Handle<Map> ReconfigureElementsKind(Isolate* isolate, Handle<Map> map,
510 511
                                             ElementsKind new_elements_kind);

512 513
  static Handle<Map> PrepareForDataProperty(Isolate* isolate,
                                            Handle<Map> old_map,
514 515 516 517
                                            int descriptor_number,
                                            PropertyConstness constness,
                                            Handle<Object> value);

518 519
  static Handle<Map> Normalize(Isolate* isolate, Handle<Map> map,
                               PropertyNormalizationMode mode,
520 521 522 523 524 525
                               const char* reason);

  // Tells whether the map is used for JSObjects in dictionary mode (ie
  // normalized objects, ie objects for which HasFastProperties returns false).
  // A map can never be used for both dictionary mode and fast mode JSObjects.
  // False by default and for HeapObjects that are not JSObjects.
526
  DECL_BOOLEAN_ACCESSORS(is_dictionary_map)
527 528 529

  // Tells whether the instance needs security checks when accessing its
  // properties.
530
  DECL_BOOLEAN_ACCESSORS(is_access_check_needed)
531 532 533 534

  // [prototype]: implicit prototype object.
  DECL_ACCESSORS(prototype, Object)
  // TODO(jkummerow): make set_prototype private.
535 536
  static void SetPrototype(Isolate* isolate, Handle<Map> map,
                           Handle<Object> prototype,
537
                           bool enable_prototype_setup_mode = true);
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552

  // [constructor]: points back to the function or FunctionTemplateInfo
  // responsible for this map.
  // The field overlaps with the back pointer. All maps in a transition tree
  // have the same constructor, so maps with back pointers can walk the
  // back pointer chain until they find the map holding their constructor.
  // Returns null_value if there's neither a constructor function nor a
  // FunctionTemplateInfo available.
  DECL_ACCESSORS(constructor_or_backpointer, Object)
  inline Object* GetConstructor() const;
  inline FunctionTemplateInfo* GetFunctionTemplateInfo() const;
  inline void SetConstructor(Object* constructor,
                             WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
  // [back pointer]: points back to the parent map from which a transition
  // leads to this map. The field overlaps with the constructor (see above).
553
  inline Object* GetBackPointer() const;
554 555 556 557 558 559 560 561 562
  inline void SetBackPointer(Object* value,
                             WriteBarrierMode mode = UPDATE_WRITE_BARRIER);

  // [instance descriptors]: describes the object.
  DECL_ACCESSORS(instance_descriptors, DescriptorArray)

  // [layout descriptor]: describes the object layout.
  DECL_ACCESSORS(layout_descriptor, LayoutDescriptor)
  // |layout descriptor| accessor which can be used from GC.
563
  inline LayoutDescriptor* layout_descriptor_gc_safe() const;
564 565 566 567 568
  inline bool HasFastPointerLayout() const;

  // |layout descriptor| accessor that is safe to call even when
  // FLAG_unbox_double_fields is disabled (in this case Map does not contain
  // |layout_descriptor| field at all).
569
  inline LayoutDescriptor* GetLayoutDescriptor() const;
570 571 572 573 574 575 576 577 578

  inline void UpdateDescriptors(DescriptorArray* descriptors,
                                LayoutDescriptor* layout_descriptor);
  inline void InitializeDescriptors(DescriptorArray* descriptors,
                                    LayoutDescriptor* layout_descriptor);

  // [dependent code]: list of optimized codes that weakly embed this map.
  DECL_ACCESSORS(dependent_code, DependentCode)

579 580 581 582 583 584 585 586 587 588 589 590 591 592
  // [prototype_validity_cell]: Cell containing the validity bit for prototype
  // chains or Smi(0) if uninitialized.
  // The meaning of this validity cell is different for prototype maps and
  // non-prototype maps.
  // For prototype maps the validity bit "guards" modifications of prototype
  // chains going through this object. When a prototype object changes, both its
  // own validity cell and those of all "downstream" prototypes are invalidated;
  // handlers for a given receiver embed the currently valid cell for that
  // receiver's prototype during their creation and check it on execution.
  // For non-prototype maps which are used as transitioning store handlers this
  // field contains the validity cell which guards modifications of this map's
  // prototype.
  DECL_ACCESSORS(prototype_validity_cell, Object)

593 594 595 596
  // Returns true if prototype validity cell value represents "valid" prototype
  // chain state.
  inline bool IsPrototypeValidityCellValid() const;

597
  inline PropertyDetails GetLastDescriptorDetails() const;
598

599
  inline int LastAdded() const;
600

601
  inline int NumberOfOwnDescriptors() const;
602 603 604 605 606 607 608
  inline void SetNumberOfOwnDescriptors(int number);

  inline Cell* RetrieveDescriptorsPointer();

  // Checks whether all properties are stored either in the map or on the object
  // (inobject, properties, or elements backing store), requiring no special
  // checks.
609 610
  bool OnlyHasSimpleProperties() const;
  inline int EnumLength() const;
611 612
  inline void SetEnumLength(int length);

613
  DECL_BOOLEAN_ACCESSORS(owns_descriptors)
614

615
  inline void mark_unstable();
616
  inline bool is_stable() const;
617 618 619 620 621 622 623 624 625 626 627 628

  DECL_BOOLEAN_ACCESSORS(is_migration_target)

  DECL_BOOLEAN_ACCESSORS(is_immutable_proto)

  // This counter is used for in-object slack tracking.
  // The in-object slack tracking is considered enabled when the counter is
  // non zero. The counter only has a valid count for initial maps. For
  // transitioned maps only kNoSlackTracking has a meaning, namely that inobject
  // slack tracking already finished for the transition tree. Any other value
  // indicates that either inobject slack tracking is still in progress, or that
  // the map isn't part of the transition tree anymore.
629
  DECL_INT_ACCESSORS(construction_counter)
630 631

  DECL_BOOLEAN_ACCESSORS(is_deprecated)
632
  inline bool CanBeDeprecated() const;
633 634 635 636 637
  // Returns a non-deprecated version of the input. If the input was not
  // deprecated, it is directly returned. Otherwise, the non-deprecated version
  // is found by re-transitioning from the root of the transition tree using the
  // descriptor array of the map. Returns MaybeHandle<Map>() if no updated map
  // is found.
638 639
  static MaybeHandle<Map> TryUpdate(Isolate* isolate,
                                    Handle<Map> map) V8_WARN_UNUSED_RESULT;
640 641 642 643

  // Returns a non-deprecated version of the input. This method may deprecate
  // existing maps along the way if encodings conflict. Not for use while
  // gathering type feedback. Use TryUpdate in those cases instead.
644
  static Handle<Map> Update(Isolate* isolate, Handle<Map> map);
645

646 647 648
  static inline Handle<Map> CopyInitialMap(Isolate* isolate, Handle<Map> map);
  static Handle<Map> CopyInitialMap(Isolate* isolate, Handle<Map> map,
                                    int instance_size, int in_object_properties,
649 650
                                    int unused_property_fields);
  static Handle<Map> CopyInitialMapNormalized(
651
      Isolate* isolate, Handle<Map> map,
652
      PropertyNormalizationMode mode = CLEAR_INOBJECT_PROPERTIES);
653
  static Handle<Map> CopyDropDescriptors(Isolate* isolate, Handle<Map> map);
654
  static Handle<Map> CopyInsertDescriptor(Isolate* isolate, Handle<Map> map,
655 656 657
                                          Descriptor* descriptor,
                                          TransitionFlag flag);

658 659
  static MaybeObjectHandle WrapFieldType(Isolate* isolate,
                                         Handle<FieldType> type);
660
  static FieldType* UnwrapFieldType(MaybeObject* wrapped_type);
661

662
  V8_WARN_UNUSED_RESULT static MaybeHandle<Map> CopyWithField(
663 664 665 666
      Isolate* isolate, Handle<Map> map, Handle<Name> name,
      Handle<FieldType> type, PropertyAttributes attributes,
      PropertyConstness constness, Representation representation,
      TransitionFlag flag);
667

668
  V8_WARN_UNUSED_RESULT static MaybeHandle<Map> CopyWithConstant(
669 670 671
      Isolate* isolate, Handle<Map> map, Handle<Name> name,
      Handle<Object> constant, PropertyAttributes attributes,
      TransitionFlag flag);
672 673 674

  // Returns a new map with all transitions dropped from the given map and
  // the ElementsKind set.
675
  static Handle<Map> TransitionElementsTo(Isolate* isolate, Handle<Map> map,
676 677
                                          ElementsKind to_kind);

678 679
  static Handle<Map> AsElementsKind(Isolate* isolate, Handle<Map> map,
                                    ElementsKind kind);
680

681 682
  static Handle<Map> CopyAsElementsKind(Isolate* isolate, Handle<Map> map,
                                        ElementsKind kind, TransitionFlag flag);
683

684
  static Handle<Map> AsLanguageMode(Isolate* isolate, Handle<Map> initial_map,
685
                                    Handle<SharedFunctionInfo> shared_info);
686

687
  static Handle<Map> CopyForPreventExtensions(Isolate* isolate, Handle<Map> map,
688 689 690 691 692 693 694 695 696
                                              PropertyAttributes attrs_to_add,
                                              Handle<Symbol> transition_marker,
                                              const char* reason);

  static Handle<Map> FixProxy(Handle<Map> map, InstanceType type, int size);

  // Maximal number of fast properties. Used to restrict the number of map
  // transitions to avoid an explosion in the number of maps for objects used as
  // dictionaries.
697
  inline bool TooManyFastProperties(StoreFromKeyed store_mode) const;
698
  static Handle<Map> TransitionToDataProperty(Isolate* isolate, Handle<Map> map,
699 700 701 702 703
                                              Handle<Name> name,
                                              Handle<Object> value,
                                              PropertyAttributes attributes,
                                              PropertyConstness constness,
                                              StoreFromKeyed store_mode);
704 705 706 707
  static Handle<Map> TransitionToAccessorProperty(
      Isolate* isolate, Handle<Map> map, Handle<Name> name, int descriptor,
      Handle<Object> getter, Handle<Object> setter,
      PropertyAttributes attributes);
708 709
  static Handle<Map> ReconfigureExistingProperty(Isolate* isolate,
                                                 Handle<Map> map,
710 711 712 713 714 715 716 717 718
                                                 int descriptor,
                                                 PropertyKind kind,
                                                 PropertyAttributes attributes);

  inline void AppendDescriptor(Descriptor* desc);

  // Returns a copy of the map, prepared for inserting into the transition
  // tree (if the |map| owns descriptors then the new one will share
  // descriptors with |map|).
719 720
  static Handle<Map> CopyForTransition(Isolate* isolate, Handle<Map> map,
                                       const char* reason);
721 722 723

  // Returns a copy of the map, with all transitions dropped from the
  // instance descriptors.
724 725
  static Handle<Map> Copy(Isolate* isolate, Handle<Map> map,
                          const char* reason);
726 727 728
  static Handle<Map> Create(Isolate* isolate, int inobject_properties);

  // Returns the next free property index (only valid for FAST MODE).
729
  int NextFreePropertyIndex() const;
730

731
  // Returns the number of enumerable properties.
732
  int NumberOfEnumerableProperties() const;
733

734
  DECL_CAST(Map)
735 736 737

  static inline int SlackForArraySize(int old_size, int size_limit);

738 739
  static void EnsureDescriptorSlack(Isolate* isolate, Handle<Map> map,
                                    int slack);
740

741 742
  // Returns the map to be used for instances when the given {prototype} is
  // passed to an Object.create call. Might transition the given {prototype}.
743 744
  static Handle<Map> GetObjectCreateMap(Isolate* isolate,
                                        Handle<HeapObject> prototype);
745 746 747

  // Similar to {GetObjectCreateMap} but does not transition {prototype} and
  // fails gracefully by returning an empty handle instead.
748 749
  static MaybeHandle<Map> TryGetObjectCreateMap(Isolate* isolate,
                                                Handle<HeapObject> prototype);
750 751 752 753 754 755 756

  // Computes a hash value for this map, to be used in HashTables and such.
  int Hash();

  // Returns the transitioned map for this map with the most generic
  // elements_kind that's found in |candidates|, or |nullptr| if no match is
  // found at all.
757 758
  Map* FindElementsKindTransitionedMap(Isolate* isolate,
                                       MapHandles const& candidates);
759

760 761
  inline static bool IsJSObject(InstanceType type);

762
  inline bool CanTransition() const;
763

764
  inline bool IsBooleanMap() const;
765 766 767
  inline bool IsNullMap() const;
  inline bool IsUndefinedMap() const;
  inline bool IsNullOrUndefinedMap() const;
768 769 770
  inline bool IsPrimitiveMap() const;
  inline bool IsJSReceiverMap() const;
  inline bool IsJSObjectMap() const;
771
  inline bool IsJSPromiseMap() const;
772 773 774 775 776 777 778 779 780 781
  inline bool IsJSArrayMap() const;
  inline bool IsJSFunctionMap() const;
  inline bool IsStringMap() const;
  inline bool IsJSProxyMap() const;
  inline bool IsModuleMap() const;
  inline bool IsJSGlobalProxyMap() const;
  inline bool IsJSGlobalObjectMap() const;
  inline bool IsJSTypedArrayMap() const;
  inline bool IsJSDataViewMap() const;
  inline bool IsSpecialReceiverMap() const;
782 783
  inline bool IsCustomElementsReceiverMap() const;

784
  bool IsMapInArrayPrototypeChain(Isolate* isolate) const;
785 786

  // Dispatched behavior.
787
  DECL_PRINTER(Map)
788
  DECL_VERIFIER(Map)
789 790

#ifdef VERIFY_HEAP
791
  void DictionaryMapVerify(Isolate* isolate);
792 793
#endif

794
  DECL_PRIMITIVE_ACCESSORS(visitor_id, VisitorId)
795

796
  static Handle<Map> TransitionToPrototype(Isolate* isolate, Handle<Map> map,
797
                                           Handle<Object> prototype);
798

799 800
  static Handle<Map> TransitionToImmutableProto(Isolate* isolate,
                                                Handle<Map> map);
801 802 803 804

  static const int kMaxPreAllocatedPropertyFields = 255;

  // Layout description.
805 806
#define MAP_FIELDS(V)                                                       \
  /* Raw data fields. */                                                    \
807 808
  V(kInstanceSizeInWordsOffset, kUInt8Size)                                 \
  V(kInObjectPropertiesStartOrConstructorFunctionIndexOffset, kUInt8Size)   \
809
  V(kUsedOrUnusedInstanceSizeInWordsOffset, kUInt8Size)                     \
810
  V(kVisitorIdOffset, kUInt8Size)                                           \
811
  V(kInstanceTypeOffset, kUInt16Size)                                       \
812 813 814 815
  V(kBitFieldOffset, kUInt8Size)                                            \
  V(kBitField2Offset, kUInt8Size)                                           \
  V(kBitField3Offset, kUInt32Size)                                          \
  V(k64BitArchPaddingOffset, kPointerSize == kUInt32Size ? 0 : kUInt32Size) \
816 817 818 819 820 821
  /* Pointer fields. */                                                     \
  V(kPointerFieldsBeginOffset, 0)                                           \
  V(kPrototypeOffset, kPointerSize)                                         \
  V(kConstructorOrBackPointerOffset, kPointerSize)                          \
  V(kTransitionsOrPrototypeInfoOffset, kPointerSize)                        \
  V(kDescriptorsOffset, kPointerSize)                                       \
822
  V(kLayoutDescriptorOffset, FLAG_unbox_double_fields ? kPointerSize : 0)   \
823
  V(kDependentCodeOffset, kPointerSize)                                     \
824
  V(kPrototypeValidityCellOffset, kPointerSize)                             \
825 826 827 828 829 830
  V(kPointerFieldsEndOffset, 0)                                             \
  /* Total size. */                                                         \
  V(kSize, 0)

  DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, MAP_FIELDS)
#undef MAP_FIELDS
831

832
  STATIC_ASSERT(kInstanceTypeOffset == Internals::kMapInstanceTypeOffset);
833

834
  class BodyDescriptor;
835 836 837 838 839

  // Compares this map to another to see if they describe equivalent objects.
  // If |mode| is set to CLEAR_INOBJECT_PROPERTIES, |other| is treated as if
  // it had exactly zero inobject properties.
  // The "shared" flags of both this map and |other| are ignored.
840 841
  bool EquivalentToForNormalization(const Map* other,
                                    PropertyNormalizationMode mode) const;
842 843

  // Returns true if given field is unboxed double.
844
  inline bool IsUnboxedDoubleField(FieldIndex index) const;
845

846
  void PrintMapDetails(std::ostream& os);
847 848

  static inline Handle<Map> AddMissingTransitionsForTesting(
849 850
      Isolate* isolate, Handle<Map> split_map,
      Handle<DescriptorArray> descriptors,
851 852 853 854 855
      Handle<LayoutDescriptor> full_layout_descriptor);

  // Fires when the layout of an object with a leaf map changes.
  // This includes adding transitions to the leaf map or changing
  // the descriptor array.
856
  inline void NotifyLeafMapLayoutChange(Isolate* isolate);
857

858 859
  static VisitorId GetVisitorId(Map* map);

860 861 862 863 864 865 866 867 868 869
  // Returns true if objects with given instance type are allowed to have
  // fast transitionable elements kinds. This predicate is used to ensure
  // that objects that can have transitionable fast elements kind will not
  // get in-place generalizable fields because the elements kind transition
  // performed by stubs or optimized code can't properly generalize such
  // fields.
  static inline bool CanHaveFastTransitionableElementsKind(
      InstanceType instance_type);
  inline bool CanHaveFastTransitionableElementsKind() const;

870
 private:
871 872 873 874 875 876 877 878 879 880 881 882 883
  // This byte encodes either the instance size without the in-object slack or
  // the slack size in properties backing store.
  // Let H be JSObject::kHeaderSize / kPointerSize.
  // If value >= H then:
  //     - all field properties are stored in the object.
  //     - there is no property array.
  //     - value * kPointerSize is the actual object size without the slack.
  // Otherwise:
  //     - there is no slack in the object.
  //     - the property array has value slack slots.
  // Note that this encoding requires that H = JSObject::kFieldsAdded.
  DECL_INT_ACCESSORS(used_or_unused_instance_size_in_words)

884 885
  // Returns the map that this (root) map transitions to if its elements_kind
  // is changed to |elements_kind|, or |nullptr| if no such map is cached yet.
886 887
  Map* LookupElementsTransitionMap(Isolate* isolate,
                                   ElementsKind elements_kind);
888 889 890 891 892 893

  // Tries to replay property transitions starting from this (root) map using
  // the descriptor array of the |map|. The |root_map| is expected to have
  // proper elements kind and therefore elements kinds transitions are not
  // taken by this function. Returns |nullptr| if matching transition map is
  // not found.
894
  Map* TryReplayPropertyTransitions(Isolate* isolate, Map* map);
895

896 897 898
  static void ConnectTransition(Isolate* isolate, Handle<Map> parent,
                                Handle<Map> child, Handle<Name> name,
                                SimpleTransitionFlag flag);
899

900
  bool EquivalentToForTransition(const Map* other) const;
901
  bool EquivalentToForElementsKindTransition(const Map* other) const;
902 903
  static Handle<Map> RawCopy(Isolate* isolate, Handle<Map> map,
                             int instance_size, int inobject_properties);
904
  static Handle<Map> ShareDescriptor(Isolate* isolate, Handle<Map> map,
905 906 907
                                     Handle<DescriptorArray> descriptors,
                                     Descriptor* descriptor);
  static Handle<Map> AddMissingTransitions(
908
      Isolate* isolate, Handle<Map> map, Handle<DescriptorArray> descriptors,
909 910
      Handle<LayoutDescriptor> full_layout_descriptor);
  static void InstallDescriptors(
911 912
      Isolate* isolate, Handle<Map> parent_map, Handle<Map> child_map,
      int new_descriptor, Handle<DescriptorArray> descriptors,
913
      Handle<LayoutDescriptor> full_layout_descriptor);
914 915
  static Handle<Map> CopyAddDescriptor(Isolate* isolate, Handle<Map> map,
                                       Descriptor* descriptor,
916 917
                                       TransitionFlag flag);
  static Handle<Map> CopyReplaceDescriptors(
918
      Isolate* isolate, Handle<Map> map, Handle<DescriptorArray> descriptors,
919 920 921 922
      Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
      MaybeHandle<Name> maybe_name, const char* reason,
      SimpleTransitionFlag simple_flag);

923
  static Handle<Map> CopyReplaceDescriptor(Isolate* isolate, Handle<Map> map,
924 925 926
                                           Handle<DescriptorArray> descriptors,
                                           Descriptor* descriptor, int index,
                                           TransitionFlag flag);
927
  static Handle<Map> CopyNormalized(Isolate* isolate, Handle<Map> map,
928 929 930
                                    PropertyNormalizationMode mode);

  // TODO(ishell): Move to MapUpdater.
931 932 933 934 935 936
  static Handle<Map> CopyGeneralizeAllFields(Isolate* isolate, Handle<Map> map,
                                             ElementsKind elements_kind,
                                             int modify_index,
                                             PropertyKind kind,
                                             PropertyAttributes attributes,
                                             const char* reason);
937

938
  void DeprecateTransitionTree(Isolate* isolate);
939

940
  void ReplaceDescriptors(Isolate* isolate, DescriptorArray* new_descriptors,
941 942 943 944 945
                          LayoutDescriptor* new_layout_descriptor);

  // Update field type of the given descriptor to new representation and new
  // type. The type must be prepared for storing in descriptor array:
  // it must be either a simple type or a map wrapped in a weak cell.
946 947
  void UpdateFieldType(Isolate* isolate, int descriptor_number,
                       Handle<Name> name, PropertyConstness new_constness,
948
                       Representation new_representation,
949
                       MaybeObjectHandle new_wrapped_type);
950 951

  // TODO(ishell): Move to MapUpdater.
952 953
  void PrintReconfiguration(Isolate* isolate, FILE* file, int modify_index,
                            PropertyKind kind, PropertyAttributes attributes);
954
  // TODO(ishell): Move to MapUpdater.
955 956 957 958 959 960
  void PrintGeneralization(
      Isolate* isolate, FILE* file, const char* reason, int modify_index,
      int split, int descriptors, bool constant_to_field,
      Representation old_representation, Representation new_representation,
      MaybeHandle<FieldType> old_field_type, MaybeHandle<Object> old_value,
      MaybeHandle<FieldType> new_field_type, MaybeHandle<Object> new_value);
961 962 963 964 965 966 967 968 969 970 971
  static const int kFastPropertiesSoftLimit = 12;
  static const int kMaxFastProperties = 128;

  friend class MapUpdater;

  DISALLOW_IMPLICIT_CONSTRUCTORS(Map);
};

// The cache for maps used by normalized (dictionary mode) objects.
// Such maps do not have property descriptors, so a typical program
// needs very limited number of distinct normalized maps.
972 973
class NormalizedMapCache : public WeakFixedArray,
                           public NeverReadOnlySpaceObject {
974
 public:
975 976 977
  using NeverReadOnlySpaceObject::GetHeap;
  using NeverReadOnlySpaceObject::GetIsolate;

978 979
  static Handle<NormalizedMapCache> New(Isolate* isolate);

980 981
  V8_WARN_UNUSED_RESULT MaybeHandle<Map> Get(Handle<Map> fast_map,
                                             PropertyNormalizationMode mode);
982
  void Set(Handle<Map> fast_map, Handle<Map> normalized_map);
983

984
  DECL_CAST(NormalizedMapCache)
985

986
  static inline bool IsNormalizedMapCache(const HeapObject* obj);
987

988
  DECL_VERIFIER(NormalizedMapCache)
989

990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
 private:
  static const int kEntries = 64;

  static inline int GetIndex(Handle<Map> map);

  // The following declarations hide base class methods.
  Object* get(int index);
  void set(int index, Object* value);
};

}  // namespace internal
}  // namespace v8

#include "src/objects/object-macros-undef.h"

#endif  // V8_OBJECTS_MAP_H_