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