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