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