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