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