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