/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/objects/map.h
1 193 строки
55 KB
Michaël Zasso
deps: update V8 to 14.6.202.33
24 апр 2026, 19:01
Не верифицирован
24 апр 2026, 19:01
f1e0b83
Код
Авторство
О чём код?
// Copyright 2017 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_OBJECTS_MAP_H_ #define V8_OBJECTS_MAP_H_ #include <optional> #include "include/v8-memory-span.h" #include "src/base/bit-field.h" #include "src/base/small-vector.h" #include "src/common/globals.h" #include "src/objects/code.h" #include "src/objects/fixed-array.h" #include "src/objects/heap-object.h" #include "src/objects/instance-type-checker.h" #include "src/objects/internal-index.h" #include "src/objects/objects.h" #include "src/objects/prototype-info.h" #include "src/roots/roots.h" #include "torque-generated/bit-fields.h" #include "torque-generated/visitor-lists.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" namespace v8::internal { class WasmTypeInfo; enum InstanceType : uint16_t; #define DATA_ONLY_VISITOR_ID_LIST(V) \ V(BigInt) \ V(CoverageInfo) \ V(FeedbackMetadata) \ V(Filler) \ V(HeapNumber) \ V(Hole) \ V(SeqOneByteString) \ V(SeqTwoByteString) \ IF_WASM(V, WasmNull) #define POINTER_VISITOR_ID_LIST(V) \ V(AccessorInfo) \ V(AllocationSite) \ V(BytecodeWrapper) \ V(CallSiteInfo) \ V(Cell) \ V(CodeWrapper) \ V(ConsString) \ V(ContextCell) \ V(CppHeapExternalObject) \ V(DataHandler) \ V(DebugInfo) \ V(DoubleStringCache) \ V(EmbedderDataArray) \ V(EphemeronHashTable) \ V(ExternalString) \ V(FeedbackCell) \ V(Foreign) \ V(FreeSpace) \ V(FunctionTemplateInfo) \ V(InterceptorInfo) \ V(JSApiObject) \ V(JSArrayBuffer) \ V(JSDataViewOrRabGsabDataView) \ V(JSDate) \ V(JSExternalObject) \ V(JSFinalizationRegistry) \ V(JSFunction) \ V(JSObject) \ V(JSObjectFast) \ V(JSRegExp) \ V(JSSynchronizationPrimitive) \ V(JSTypedArray) \ V(JSWeakCollection) \ V(JSWeakRef) \ V(Map) \ V(NativeContext) \ V(Oddball) \ V(PreparseData) \ V(PropertyArray) \ V(PropertyCell) \ V(PrototypeInfo) \ V(PrototypeSharedClosureInfo) \ V(RegExpBoilerplateDescription) \ V(RegExpDataWrapper) \ V(SharedFunctionInfo) \ V(ShortcutCandidate) \ V(SlicedString) \ V(SloppyArgumentsElements) \ V(SmallOrderedHashMap) \ V(SmallOrderedHashSet) \ V(SmallOrderedNameDictionary) \ V(SourceTextModule) \ V(Struct) \ V(SwissNameDictionary) \ V(Symbol) \ V(SyntheticModule) \ V(ThinString) \ V(TransitionArray) \ IF_WASM(V, WasmArray) \ IF_WASM(V, WasmFuncRef) \ IF_WASM(V, WasmGlobalObject) \ IF_WASM(V, WasmInstanceObject) \ IF_WASM(V, WasmMemoryMapDescriptor) \ IF_WASM(V, WasmMemoryObject) \ IF_WASM(V, WasmResumeData) \ IF_WASM(V, WasmStruct) \ IF_WASM(V, WasmSuspendingObject) \ IF_WASM(V, WasmContinuationObject) \ IF_WASM(V, WasmTableObject) \ IF_WASM(V, WasmTagObject) \ IF_WASM(V, WasmTypeInfo) \ V(WeakCell) \ SIMPLE_HEAP_OBJECT_LIST1(V) #define TORQUE_VISITOR_ID_LIST(V) \ TORQUE_DATA_ONLY_VISITOR_ID_LIST(V) \ TORQUE_POINTER_VISITOR_ID_LIST(V) #define TRUSTED_VISITOR_ID_LIST(V) CONCRETE_TRUSTED_OBJECT_TYPE_LIST1(V) // Objects with the same visitor id are processed in the same way by // the heap visitors. The visitor ids for data only objects must precede // other visitor ids. We rely on kDataOnlyVisitorIdCount for quick check // of whether an object contains only data or may contain pointers. enum VisitorId { #define VISITOR_ID_ENUM_DECL(id) kVisit##id, // clang-format off DATA_ONLY_VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL) TORQUE_DATA_ONLY_VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL) kDataOnlyVisitorIdCount, POINTER_VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL) TORQUE_POINTER_VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL) TRUSTED_VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL) kVisitorIdCount // clang-format on #undef VISITOR_ID_ENUM_DECL }; enum class ObjectFields { kDataOnly, kMaybePointers, }; using MapHandles = DirectHandleSmallVector<Map, DEFAULT_MAX_POLYMORPHIC_MAP_COUNT>; using MapHandlesSpan = v8::MemorySpan<DirectHandle<Map>>; #include "torque-generated/src/objects/map-tq.inc" // All heap objects have a Map that describes their structure. // A Map contains information about: // - Size information about the object // - How to iterate over an object (for garbage collection) // // Map layout: // +---------------+-------------------------------------------------+ // | _ Type _ | _ Description _ | // +---------------+-------------------------------------------------+ // | TaggedPointer | map - Always a pointer to the MetaMap root | // +---------------+-------------------------------------------------+ // | Int | The first int field | // `---+----------+-------------------------------------------------+ // | Byte | [instance_size] | // +----------+-------------------------------------------------+ // | Byte | If Map for a primitive type: | // | | native context index for constructor fn | // | | If Map for an Object type: | // | | inobject properties start offset in words | // +----------+-------------------------------------------------+ // | Byte | [used_or_unused_instance_size_in_words] | // | | For JSObject in fast mode this byte encodes | // | | the size of the object that includes only | // | | the used property fields or the slack size | // | | in properties backing store. | // +----------+-------------------------------------------------+ // | Byte | [visitor_id] | // +----+----------+-------------------------------------------------+ // | Int | The second int field | // `---+----------+-------------------------------------------------+ // | Short | [instance_type] | // +----------+-------------------------------------------------+ // | Byte | [bit_field] | // | | - has_non_instance_prototype (bit 0) | // | | - is_callable (bit 1) | // | | - has_named_interceptor (bit 2) | // | | - has_indexed_interceptor (bit 3) | // | | - is_undetectable (bit 4) | // | | - is_access_check_needed (bit 5) | // | | - is_constructor (bit 6) | // | | - has_prototype_slot (bit 7) | // +----------+-------------------------------------------------+ // | Byte | [bit_field2] | // | | - new_target_is_base (bit 0) | // | | - is_immutable_proto (bit 1) | // | | - elements_kind (bits 2..7) | // +----+----------+-------------------------------------------------+ // | Int | [bit_field3] | // | | - enum_length (bit 0..9) | // | | - number_of_own_descriptors (bit 10..19) | // | | - is_prototype_map (bit 20) | // | | - is_dictionary_map (bit 21) | // | | - owns_descriptors (bit 22) | // | | - is_in_retained_map_list (bit 23) | // | | - is_deprecated (bit 24) | // | | - is_unstable (bit 25) | // | | - is_migration_target (bit 26) | // | | - is_extensible (bit 27) | // | | - may_have_interesting_properties (bit 28) | // | | - construction_counter (bit 29..31) | // | | | // +*****************************************************************+ // | Int | On systems with 64bit pointer types, there | // | | is an unused 32bits after bit_field3 | // +*****************************************************************+ // | TaggedPointer | [prototype] | // +---------------+-------------------------------------------------+ // | TaggedPointer | [constructor_or_back_pointer_or_native_context] | // | | [WasmTypeInfo] (if Wasm map) | // +---------------+-------------------------------------------------+ // | TaggedPointer | [instance_descriptors] (if JS object) | // | | [custom_descriptor] (if WasmStruct) | // +---------------+-------------------------------------------------+ // | TaggedPointer | [immediate_supertype_map] (if WasmStruct with | // | | custom descriptor) | // | | [dependent_code] (all other maps) | // +---------------+-------------------------------------------------+ // | TaggedPointer | [prototype_validity_cell] | // +---------------+-------------------------------------------------+ // | TaggedPointer | If Map is a prototype map: | // | | [prototype_info] | // | | Else: | // | | [raw_transitions] | // +---------------+-------------------------------------------------+ class Map : public TorqueGeneratedMap<Map, HeapObject> { public: // Instance size. // Size in bytes or kVariableSizeSentinel if instances do not have // a fixed size. DECL_INT_ACCESSORS(instance_size) // Size in words or kVariableSizeSentinel if instances do not have // a fixed size. DECL_INT_ACCESSORS(instance_size_in_words) // [inobject_properties_start_or_constructor_function_index]: // Provides access to the inobject properties start offset in words in case of // JSObject maps, or the constructor function index in case of primitive maps. DECL_INT_ACCESSORS(inobject_properties_start_or_constructor_function_index) // Get/set the in-object property area start offset in words in the object. inline int GetInObjectPropertiesStartInWords() const; inline void SetInObjectPropertiesStartInWords(int value); // Count of properties allocated in the object (JSObject only). inline int GetInObjectProperties() const; // Index of the constructor function in the native context (primitives only), // or the special sentinel value to indicate that there is no object wrapper // for the primitive (i.e. in case of null or undefined). static const int kNoConstructorFunctionIndex = 0; inline int GetConstructorFunctionIndex() const; inline void SetConstructorFunctionIndex(int value); static std::optional<Tagged<JSFunction>> GetConstructorFunction( Tagged<Map> map, Tagged<Context> native_context); // Retrieve interceptors. DECL_GETTER(GetNamedInterceptor, Tagged<InterceptorInfo>) DECL_GETTER(GetIndexedInterceptor, Tagged<InterceptorInfo>) // Instance type. // Inline definition here to avoid a circular dependency in map-inl.h // with instance-types-inl.h inline InstanceType instance_type() const { // TODO(solanes, v8:7790, v8:11353, v8:11945): Make this and the setter // non-atomic when TSAN sees the map's store synchronization. return static_cast<InstanceType>( RELAXED_READ_UINT16_FIELD(*this, kInstanceTypeOffset)); } inline void set_instance_type(InstanceType value); // Returns the size of the used in-object area including object header // (only used for JSObject in fast mode, for the other kinds of objects it // is equal to the instance size). inline int UsedInstanceSize() const; inline bool HasOutOfObjectProperties() const; // Tells how many unused property fields (in-object or out-of object) are // available in the instance (only used for JSObject in fast mode). inline int UnusedPropertyFields() const; // Tells how many unused in-object property words are present. inline int UnusedInObjectProperties() const; // Updates the counters tracking unused fields in the object. inline void SetInObjectUnusedPropertyFields(int unused_property_fields); // Updates the counters tracking unused fields in the property array. inline void SetOutOfObjectUnusedPropertyFields(int unused_property_fields); inline void CopyUnusedPropertyFields(Tagged<Map> map); inline void CopyUnusedPropertyFieldsAdjustedForInstanceSize(Tagged<Map> map); inline void AccountAddedPropertyField(); inline void AccountAddedOutOfObjectPropertyField( int unused_in_property_array); // // Bit field. // // The setter in this pair calls the relaxed setter if concurrent marking is // on, or performs the write non-atomically if it's off. The read is always // non-atomically. This is done to have wider TSAN coverage on the cases where // it's possible. DECL_PRIMITIVE_ACCESSORS(bit_field, uint8_t) // Atomic accessors, used for allowlisting legitimate concurrent accesses. DECL_PRIMITIVE_ACCESSORS(relaxed_bit_field, uint8_t) // Bit positions for |bit_field|. struct Bits1 { DEFINE_TORQUE_GENERATED_MAP_BIT_FIELDS1() }; // // Bit field 2. // DECL_PRIMITIVE_ACCESSORS(bit_field2, uint8_t) // Bit positions for |bit_field2|. struct Bits2 { DEFINE_TORQUE_GENERATED_MAP_BIT_FIELDS2() }; // // Bit field 3. // // {bit_field3} calls the relaxed accessors if concurrent marking is on, or // performs the read/write non-atomically if it's off. This is done to have // wider TSAN coverage on the cases where it's possible. DECL_PRIMITIVE_ACCESSORS(bit_field3, uint32_t) DECL_PRIMITIVE_ACCESSORS(relaxed_bit_field3, uint32_t) DECL_PRIMITIVE_ACCESSORS(release_acquire_bit_field3, uint32_t) // Clear uninitialized padding space. This ensures that the snapshot content // is deterministic. Depending on the V8 build mode there could be no padding. V8_INLINE void clear_padding(); // Bit positions for |bit_field3|. struct Bits3 { DEFINE_TORQUE_GENERATED_MAP_BIT_FIELDS3() }; // Ensure that Torque-defined bit widths for |bit_field3| are as expected. static_assert(Bits3::EnumLengthBits::kSize == kDescriptorIndexBitCount); static_assert(Bits3::NumberOfOwnDescriptorsBits::kSize == kDescriptorIndexBitCount); static_assert(Bits3::NumberOfOwnDescriptorsBits::kMax >= kMaxNumberOfDescriptors); static const int kSlackTrackingCounterStart = 7; static const int kSlackTrackingCounterEnd = 1; static const int kNoSlackTracking = 0; static_assert(kSlackTrackingCounterStart <= Bits3::ConstructionCounterBits::kMax); // Inobject slack tracking is the way to reclaim unused inobject space. // // The instance size is initially determined by adding some slack to // expected_nof_properties (to allow for a few extra properties added // after the constructor). There is no guarantee that the extra space // will not be wasted. // // Here is the algorithm to reclaim the unused inobject space: // - Detect the first constructor call for this JSFunction. // When it happens enter the "in progress" state: initialize construction // counter in the initial_map. // - While the tracking is in progress initialize unused properties of a new // object with one_pointer_filler_map instead of undefined_value (the "used" // part is initialized with undefined_value as usual). This way they can // be resized quickly and safely. // - Once enough objects have been created compute the 'slack' // (traverse the map transition tree starting from the // initial_map and find the lowest value of unused_property_fields). // - Traverse the transition tree again and decrease the instance size // of every map. Existing objects will resize automatically (they are // filled with one_pointer_filler_map). All further allocations will // use the adjusted instance size. // - SharedFunctionInfo's expected_nof_properties left unmodified since // allocations made using different closures could actually create different // kind of objects (see prototype inheritance pattern). // // Important: inobject slack tracking is not attempted during the snapshot // creation. static const int kGenerousAllocationCount = kSlackTrackingCounterStart - kSlackTrackingCounterEnd + 1; // Starts the tracking by initializing object constructions countdown counter. void StartInobjectSlackTracking(); // True if the object constructions countdown counter is a range // [kSlackTrackingCounterEnd, kSlackTrackingCounterStart]. inline bool IsInobjectSlackTrackingInProgress() const; // Does the tracking step. inline void InobjectSlackTrackingStep(Isolate* isolate); // Computes inobject slack for the transition tree starting at this initial // map. int ComputeMinObjectSlack(Isolate* isolate); inline int InstanceSizeFromSlack(int slack) const; // Tells whether the object in the prototype property will be used // for instances created from this function. If the prototype // property is set to a value that is not a JSObject, the prototype // property will not be used to create instances of the function. // See ECMA-262, 13.2.2. DECL_BOOLEAN_ACCESSORS(has_non_instance_prototype) // Tells whether the instance has a [[Construct]] internal method. // This property is implemented according to ES6, section 7.2.4. DECL_BOOLEAN_ACCESSORS(is_constructor) // Tells whether the instance with this map may have properties for // interesting symbols on it. // An "interesting symbol" is one for which Name::IsInteresting() // returns true, i.e. a well-known symbol like @@toStringTag. DECL_BOOLEAN_ACCESSORS(may_have_interesting_properties) DECL_BOOLEAN_ACCESSORS(has_prototype_slot) // Records and queries whether the instance has a named interceptor. DECL_BOOLEAN_ACCESSORS(has_named_interceptor) // Records and queries whether the instance has an indexed interceptor. DECL_BOOLEAN_ACCESSORS(has_indexed_interceptor) // Tells whether the instance is undetectable. // An undetectable object is a special class of JSObject: 'typeof' operator // returns undefined, ToBoolean returns false. Otherwise it behaves like // a normal JS object. It is useful for implementing undetectable // document.all in Firefox & Safari. // See https://bugzilla.mozilla.org/show_bug.cgi?id=248549. DECL_BOOLEAN_ACCESSORS(is_undetectable) // Tells whether the instance has a [[Call]] internal method. // This property is implemented according to ES6, section 7.2.3. DECL_BOOLEAN_ACCESSORS(is_callable) DECL_BOOLEAN_ACCESSORS(new_target_is_base) DECL_BOOLEAN_ACCESSORS(is_extensible) DECL_BOOLEAN_ACCESSORS(is_prototype_map) inline bool is_abandoned_prototype_map() const; inline bool has_prototype_info() const; inline bool TryGetPrototypeInfo(Tagged<PrototypeInfo>* result) const; inline bool TryGetPrototypeSharedClosureInfo( Tagged<PrototypeSharedClosureInfo>* result) const; inline void SetPrototypeSharedClosureInfo( Tagged<PrototypeSharedClosureInfo> closure_infos); // Whether the instance has been added to the retained map list by // Heap::AddRetainedMap. DECL_BOOLEAN_ACCESSORS(is_in_retained_map_list) DECL_PRIMITIVE_ACCESSORS(elements_kind, ElementsKind) // Tells whether the instance has fast elements that are only Smis. inline bool has_fast_smi_elements() const; // Tells whether the instance has fast elements. inline bool has_fast_object_elements() const; inline bool has_fast_smi_or_object_elements() const; inline bool has_fast_double_elements() const; inline bool has_fast_elements() const; inline bool has_fast_packed_elements() const; inline bool has_sloppy_arguments_elements() const; inline bool has_fast_sloppy_arguments_elements() const; inline bool has_fast_string_wrapper_elements() const; inline bool has_typed_array_or_rab_gsab_typed_array_elements() const; inline bool has_any_typed_array_or_wasm_array_elements() const; inline bool has_dictionary_elements() const; inline bool has_any_nonextensible_elements() const; inline bool has_nonextensible_elements() const; inline bool has_sealed_elements() const; inline bool has_frozen_elements() const; inline bool has_shared_array_elements() const; // Weakly checks whether a map is detached from all transition trees. If this // returns true, the map is guaranteed to be detached. If it returns false, // there is no guarantee it is attached. inline bool IsDetached(Isolate* isolate) const; // Returns true if there is an object with potentially read-only elements // in the prototype chain. It could be a Proxy, a string wrapper, // an object with DICTIONARY_ELEMENTS potentially containing read-only // elements or an object with any frozen elements, or a slow arguments object. bool ShouldCheckForReadOnlyElementsInPrototypeChain(Isolate* isolate); inline Tagged<Map> ElementsTransitionMap(Isolate* isolate, ConcurrencyMode cmode); inline Tagged<FixedArrayBase> GetInitialElements() const; // [raw_transitions]: Provides access to the transitions storage field. // Don't call set_raw_transitions() directly to overwrite transitions, use // the TransitionArray::ReplaceTransitions() wrapper instead! DECL_ACCESSORS(raw_transitions, Tagged<UnionOf<Smi, MaybeWeak<Map>, TransitionArray>>) DECL_RELEASE_ACQUIRE_ACCESSORS( raw_transitions, Tagged<UnionOf<Smi, MaybeWeak<Map>, TransitionArray>>) // [prototype_info]: Per-prototype metadata. Aliased with transitions // (which prototype maps don't have). DECL_GETTER(prototype_info, Tagged<UnionOf<Smi, PrototypeInfo, PrototypeSharedClosureInfo>>) DECL_RELEASE_ACQUIRE_ACCESSORS( prototype_info, Tagged<UnionOf<Smi, PrototypeInfo, PrototypeSharedClosureInfo>>) // PrototypeInfo is created lazily using this helper (which installs it on // the given prototype's map). static DirectHandle<PrototypeInfo> GetOrCreatePrototypeInfo( DirectHandle<JSReceiver> prototype, Isolate* isolate); static DirectHandle<PrototypeInfo> GetOrCreatePrototypeInfo( DirectHandle<Map> prototype_map, Isolate* isolate); inline bool should_be_fast_prototype_map() const; static void SetShouldBeFastPrototypeMap(DirectHandle<Map> map, bool value, Isolate* isolate); static inline bool TryGetValidityCellHolderMap( Tagged<Map> map, Isolate* isolate, Tagged<Map>* out_validity_cell_holder_map); // [prototype chain validity cell]: Associated with a prototype object, // stored in that object's map, indicates that prototype chains through this // object are currently valid. The cell will be invalidated and replaced when // the prototype chain changes. When there's nothing to guard (for example, // when direct prototype is null or Proxy) this function returns Smi // |kNoValidityCellSentinel| value. // If |out_prototype_info| is provided then the function sets it to // the PrototypeInfo object that corresponds to validity cell's owner. static Handle<UnionOf<Smi, Cell>> GetOrCreatePrototypeChainValidityCell( DirectHandle<Map> map, Isolate* isolate, DirectHandle<PrototypeInfo>* out_prototype_info = nullptr); // Invalid state for prototype validity cell. Everything else is considered // as valid state. static constexpr Tagged<ClearedWeakValue> kPrototypeChainInvalid = kClearedWeakValue; // This sentinel is used in IC data handlers instead of actual validity cell // when there's nothing to guard against (when direct prototype is null or // Proxy). static constexpr Tagged<Smi> kNoValidityCellSentinel = Smi::zero(); // Return the map of the root of object's prototype chain. Tagged<Map> GetPrototypeChainRootMap(Isolate* isolate) const; V8_EXPORT_PRIVATE Tagged<Map> FindRootMap(PtrComprCageBase cage_base) const; V8_EXPORT_PRIVATE Tagged<Map> FindFieldOwner(PtrComprCageBase cage_base, InternalIndex descriptor) const; inline int GetInObjectPropertyOffset(int index) const; class FieldCounts { public: FieldCounts(int mutable_count, int const_count) : mutable_count_(mutable_count), const_count_(const_count) {} int GetTotal() const { return mutable_count() + const_count(); } int mutable_count() const { return mutable_count_; } int const_count() const { return const_count_; } private: int mutable_count_; int const_count_; }; FieldCounts GetFieldCounts() const; int NumberOfFields(ConcurrencyMode cmode) const; // TODO(ishell): candidate with JSObject::MigrateToMap(). bool InstancesNeedRewriting(Tagged<Map> target, ConcurrencyMode cmode) const; bool InstancesNeedRewriting(Tagged<Map> target, int target_number_of_fields, int target_inobject, int target_unused, int* old_number_of_fields, ConcurrencyMode cmode) const; // Returns true if the |field_type| is the most general one for // given |representation|. static inline bool IsMostGeneralFieldType(Representation representation, Tagged<FieldType> field_type); // Generalizes representation and field_type if objects with given // instance type can have fast elements that can be transitioned by // stubs or optimized code to more general elements kind. // This generalization is necessary in order to ensure that elements kind // transitions performed by stubs / optimized code don't silently transition // fields with representation "Tagged" back to "Smi" or "HeapObject" or // fields with HeapObject representation and "Any" type back to "Class" type. static inline void GeneralizeIfCanHaveTransitionableFastElementsKind( Isolate* isolate, InstanceType instance_type, Representation* representation, DirectHandle<FieldType>* field_type); V8_EXPORT_PRIVATE static DirectHandle<Map> PrepareForDataProperty( Isolate* isolate, DirectHandle<Map> old_map, InternalIndex descriptor_number, PropertyConstness constness, DirectHandle<Object> value); V8_EXPORT_PRIVATE static Handle<Map> Normalize( Isolate* isolate, DirectHandle<Map> map, InstanceType new_instance_type, ElementsKind new_elements_kind, DirectHandle<JSPrototype> new_prototype, PropertyNormalizationMode mode, bool use_cache, const char* reason); V8_EXPORT_PRIVATE static Handle<Map> Normalize( Isolate* isolate, DirectHandle<Map> map, ElementsKind new_elements_kind, DirectHandle<JSPrototype> new_prototype, PropertyNormalizationMode mode, bool use_cache, const char* reason) { return Normalize(isolate, map, map->instance_type(), new_elements_kind, new_prototype, mode, use_cache, reason); } V8_EXPORT_PRIVATE static Handle<Map> Normalize( Isolate* isolate, DirectHandle<Map> map, InstanceType new_instance_type, ElementsKind new_elements_kind, DirectHandle<JSPrototype> new_prototype, PropertyNormalizationMode mode, const char* reason) { const bool kUseCache = true; return Normalize(isolate, map, new_instance_type, new_elements_kind, new_prototype, mode, kUseCache, reason); } V8_EXPORT_PRIVATE static Handle<Map> Normalize( Isolate* isolate, DirectHandle<Map> map, ElementsKind new_elements_kind, DirectHandle<JSPrototype> new_prototype, PropertyNormalizationMode mode, const char* reason) { const bool kUseCache = true; return Normalize(isolate, map, new_elements_kind, new_prototype, mode, kUseCache, reason); } inline static Handle<Map> Normalize(Isolate* isolate, DirectHandle<Map> fast_map, PropertyNormalizationMode mode, const char* reason); // Tells whether the map is used for JSObjects in dictionary mode (ie // normalized objects, ie objects for which HasFastProperties returns false). // A map can never be used for both dictionary mode and fast mode JSObjects. // False by default and for HeapObjects that are not JSObjects. DECL_BOOLEAN_ACCESSORS(is_dictionary_map) // Tells whether the instance needs security checks when accessing its // properties. DECL_BOOLEAN_ACCESSORS(is_access_check_needed) // [prototype]: implicit prototype object. DECL_ACCESSORS(prototype, Tagged<JSPrototype>) // TODO(jkummerow): make set_prototype private. // {enable_prototype_setup_mode}: Switch the prototype to dictionary mode, // which is faster for adding multiple properties to it. V8_EXPORT_PRIVATE static void SetPrototype( Isolate* isolate, DirectHandle<Map> map, DirectHandle<JSPrototype> prototype, bool enable_prototype_setup_mode = true); // Sets prototype and constructor fields to null. Can be called during // bootstrapping. inline void init_prototype_and_constructor_or_back_pointer( ReadOnlyRoots roots); // [constructor]: points back to the function or FunctionTemplateInfo // responsible for this map. // The field overlaps with the back pointer. All maps in a transition tree // have the same constructor, so maps with back pointers can walk the // back pointer chain until they find the map holding their constructor. // Returns null_value if there's neither a constructor function nor a // FunctionTemplateInfo available. // The field also overlaps with the native context pointer for context maps, // and with the Wasm type info for WebAssembly object maps. DECL_ACCESSORS(constructor_or_back_pointer, Tagged<Object>) DECL_RELAXED_ACCESSORS(constructor_or_back_pointer, Tagged<Object>) DECL_ACCESSORS(native_context, Tagged<NativeContext>) DECL_ACCESSORS(native_context_or_null, Tagged<Object>) DECL_GETTER(raw_native_context_or_null, Tagged<Object>) DECL_ACCESSORS(wasm_type_info, Tagged<WasmTypeInfo>) // Gets |constructor_or_back_pointer| field value from the root map. // The result might be null, JSFunction, FunctionTemplateInfo or a Tuple2 // for JSFunctions with non-instance prototypes. DECL_GETTER(GetConstructorRaw, Tagged<Object>) // Gets constructor value from the root map. Unwraps Tuple2 in case of // JSFunction map with non-instance prototype. // The result returned might be null, JSFunction or FunctionTemplateInfo. DECL_GETTER(GetConstructor, Tagged<Object>) DECL_GETTER(GetFunctionTemplateInfo, Tagged<FunctionTemplateInfo>) inline void SetConstructor(Tagged<Object> constructor, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); // Constructor getter that performs at most the given number of steps // in the transition tree. Returns either the constructor or the map at // which the walk has stopped. inline Tagged<Object> TryGetConstructor(PtrComprCageBase cage_base, int max_steps); // Gets non-instance prototype value which is stored in Tuple2 in a // root map's |constructor_or_back_pointer| field. DECL_GETTER(GetNonInstancePrototype, Tagged<Object>) // [back pointer]: points back to the parent map from which a transition // leads to this map. The field overlaps with the constructor (see above). DECL_GETTER(GetBackPointer, Tagged<HeapObject>) inline void SetBackPointer(Tagged<HeapObject> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline bool TryGetBackPointer(PtrComprCageBase cage_base, Tagged<Map>* back_pointer) const; // [instance descriptors]: describes the object. DECL_ACCESSORS(instance_descriptors, Tagged<DescriptorArray>) DECL_ACQUIRE_GETTER(instance_descriptors, Tagged<DescriptorArray>) V8_EXPORT_PRIVATE void SetInstanceDescriptors( Isolate* isolate, Tagged<DescriptorArray> descriptors, int number_of_own_descriptors, WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER); #if V8_ENABLE_WEBASSEMBLY // Only for WasmStructs: custom descriptor instead of instance_descriptors. DECL_ACCESSORS(custom_descriptor, Tagged<WasmStruct>) #endif // V8_ENABLE_WEBASSEMBLY inline void UpdateDescriptors(Isolate* isolate, Tagged<DescriptorArray> descriptors, int number_of_own_descriptors); inline void InitializeDescriptors(Isolate* isolate, Tagged<DescriptorArray> descriptors); // [dependent code]: list of optimized codes that weakly embed this map. DECL_ACCESSORS(dependent_code, Tagged<DependentCode>) #if V8_ENABLE_WEBASSEMBLY // [immediate_supertype_map]: overlaid onto the "dependent_code" field, // Wasm maps with custom descriptors store their immediate supertype map // (i.e. the canonical RTT for their static type) here, for fast access // from type checks in generated code. DECL_ACCESSORS(immediate_supertype_map, Tagged<Map>) static constexpr int kImmediateSupertypeOffset = kDependentCodeOffset; #endif // V8_ENABLE_WEBASSEMBLY // [prototype_validity_cell]: Cell containing the validity bit for prototype // chains or Tagged<Smi>(0) if uninitialized. // The meaning of this validity cell is different for prototype maps and // non-prototype maps. // For prototype maps the validity bit "guards" modifications of prototype // chains going through this object. When a prototype object changes, both its // own validity cell and those of all "downstream" prototypes are invalidated; // handlers for a given receiver embed the currently valid cell for that // receiver's prototype during their creation and check it on execution. // For non-prototype maps which are used as transitioning store handlers this // field contains the validity cell which guards modifications of this map's // prototype. DECL_RELAXED_ACCESSORS(prototype_validity_cell, Tagged<UnionOf<Smi, Cell>>) // Returns true if prototype validity cell value represents "valid" prototype // chain state. inline bool IsPrototypeValidityCellValid() const; // Returns true if this map belongs to the same native context as given map, // i.e. this map's meta map is equal to other_map's meta map. // Returns false if this map is contextless (in case of JSObject map this // means that the object is remote). inline bool BelongsToSameNativeContextAs(Tagged<Map> other_map) const; inline bool BelongsToSameNativeContextAs(Tagged<Context> context) const; inline Tagged<Name> GetLastDescriptorName(Isolate* isolate) const; inline PropertyDetails GetLastDescriptorDetails(Isolate* isolate) const; inline InternalIndex LastAdded() const; inline int NumberOfOwnDescriptors() const; inline void SetNumberOfOwnDescriptors(int number); inline InternalIndex::Range IterateOwnDescriptors() const; inline Tagged<Cell> RetrieveDescriptorsPointer(); // Checks whether all properties are stored either in the map or on the object // (inobject, properties, or elements backing store), requiring no special // checks. bool OnlyHasSimpleProperties() const; inline int EnumLength() const; inline void SetEnumLength(int length); DECL_BOOLEAN_ACCESSORS(owns_descriptors) inline void mark_unstable(); inline bool is_stable() const; DECL_BOOLEAN_ACCESSORS(is_migration_target) DECL_BOOLEAN_ACCESSORS(is_immutable_proto) // This counter is used for in-object slack tracking. // The in-object slack tracking is considered enabled when the counter is // non zero. The counter only has a valid count for initial maps. For // transitioned maps only kNoSlackTracking has a meaning, namely that inobject // slack tracking already finished for the transition tree. Any other value // indicates that either inobject slack tracking is still in progress, or that // the map isn't part of the transition tree anymore. DECL_INT_ACCESSORS(construction_counter) DECL_BOOLEAN_ACCESSORS(is_deprecated) inline bool CanBeDeprecated() const; // Returns a non-deprecated version of the input. If the input was not // deprecated, it is directly returned. Otherwise, the non-deprecated version // is found by re-transitioning from the root of the transition tree using the // descriptor array of the map. Returns MaybeHandle<Map>() if no updated map // is found. V8_EXPORT_PRIVATE static MaybeHandle<Map> TryUpdate( Isolate* isolate, Handle<Map> map) V8_WARN_UNUSED_RESULT; // Returns a non-deprecated version of the input. This method may deprecate // existing maps along the way if encodings conflict. Not for use while // gathering type feedback. Use TryUpdate in those cases instead. V8_EXPORT_PRIVATE static DirectHandle<Map> Update(Isolate* isolate, DirectHandle<Map> map); static inline Handle<Map> CopyInitialMap(Isolate* isolate, DirectHandle<Map> map); V8_EXPORT_PRIVATE static Handle<Map> CopyInitialMap( Isolate* isolate, DirectHandle<Map> map, int instance_size, int in_object_properties, int unused_property_fields); static DirectHandle<Map> CopyInitialMapNormalized( Isolate* isolate, DirectHandle<Map> map, PropertyNormalizationMode mode = CLEAR_INOBJECT_PROPERTIES); static Handle<Map> CopyDropDescriptors(Isolate* isolate, DirectHandle<Map> map); V8_EXPORT_PRIVATE static Handle<Map> CopyInsertDescriptor( Isolate* isolate, DirectHandle<Map> map, Descriptor* descriptor, TransitionFlag flag); static MaybeObjectDirectHandle WrapFieldType(DirectHandle<FieldType> type); V8_EXPORT_PRIVATE static Tagged<FieldType> UnwrapFieldType( Tagged<MaybeObject> wrapped_type); V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static MaybeHandle<Map> CopyWithField( Isolate* isolate, DirectHandle<Map> map, DirectHandle<Name> name, DirectHandle<FieldType> type, PropertyAttributes attributes, PropertyConstness constness, Representation representation, TransitionFlag flag); V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static MaybeHandle<Map> CopyWithConstant(Isolate* isolate, DirectHandle<Map> map, DirectHandle<Name> name, DirectHandle<Object> constant, PropertyAttributes attributes, TransitionFlag flag); // Returns a new map with all transitions dropped from the given map and // the ElementsKind set. static DirectHandle<Map> TransitionElementsTo(Isolate* isolate, DirectHandle<Map> map, ElementsKind to_kind); static std::optional<Tagged<Map>> TryAsElementsKind(Isolate* isolate, DirectHandle<Map> map, ElementsKind kind, ConcurrencyMode cmode); V8_EXPORT_PRIVATE static Handle<Map> AsElementsKind(Isolate* isolate, DirectHandle<Map> map, ElementsKind kind); static Handle<Map> CopyAsElementsKind(Isolate* isolate, DirectHandle<Map> map, ElementsKind kind, TransitionFlag flag); V8_EXPORT_PRIVATE static Handle<Map> AsDetachedTypedArray( Isolate* isolate, DirectHandle<Map> map); static DirectHandle<Map> AsLanguageMode( Isolate* isolate, DirectHandle<Map> initial_map, DirectHandle<SharedFunctionInfo> shared_info); V8_EXPORT_PRIVATE static Handle<Map> CopyForPreventExtensions( Isolate* isolate, DirectHandle<Map> map, PropertyAttributes attrs_to_add, DirectHandle<Symbol> transition_marker, const char* reason, bool old_map_is_dictionary_elements_kind = false); // Maximal number of fast properties. Used to restrict the number of map // transitions to avoid an explosion in the number of maps for objects used as // dictionaries. inline bool TooManyFastProperties(StoreOrigin store_origin) const; V8_EXPORT_PRIVATE static DirectHandle<Map> TransitionToDataProperty( Isolate* isolate, DirectHandle<Map> map, DirectHandle<Name> name, DirectHandle<Object> value, PropertyAttributes attributes, PropertyConstness constness, StoreOrigin store_origin); V8_EXPORT_PRIVATE static DirectHandle<Map> TransitionToAccessorProperty( Isolate* isolate, DirectHandle<Map> map, DirectHandle<Name> name, InternalIndex descriptor, DirectHandle<Object> getter, DirectHandle<Object> setter, PropertyAttributes attributes); inline void AppendDescriptor(Isolate* isolate, Descriptor* desc); // Returns a copy of the map, prepared for inserting into the transition // tree (if the |map| owns descriptors then the new one will share // descriptors with |map|). static Handle<Map> CopyForElementsTransition(Isolate* isolate, DirectHandle<Map> map); // Returns a copy of the map, prepared for inserting into the transition // tree as a prototype transition. static Handle<Map> CopyForPrototypeTransition( Isolate* isolate, DirectHandle<Map> map, DirectHandle<JSPrototype> prototype); // Returns a copy of the map, with all transitions dropped from the // instance descriptors. static Handle<Map> Copy(Isolate* isolate, DirectHandle<Map> map, const char* reason, TransitionKindFlag kind = SPECIAL_TRANSITION); V8_EXPORT_PRIVATE static Handle<Map> Create(Isolate* isolate, int inobject_properties); // Returns the next free property index (only valid for FAST MODE). int NextFreePropertyIndex() const; // Returns the number of enumerable properties. int NumberOfEnumerableProperties() const; static inline int SlackForArraySize(int old_size, int size_limit); V8_EXPORT_PRIVATE static void EnsureDescriptorSlack(Isolate* isolate, DirectHandle<Map> map, int slack); // Returns the map to be used for instances when the given {prototype} is // passed to an Object.create call. Might transition the given {prototype}. static DirectHandle<Map> GetObjectCreateMap( Isolate* isolate, DirectHandle<JSPrototype> prototype); // Returns the map to be used for instances when the given {prototype} is // passed to Reflect.construct or proxy constructors. static Handle<Map> GetDerivedMap(Isolate* isolate, DirectHandle<Map> from, DirectHandle<JSReceiver> prototype); // Computes a hash value for this map, to be used e.g. in HashTables. The // prototype value should be either the Map's prototype or another prototype // in case the hash is supposed to be computed for a copy of this map with a // changed prototype value. int Hash(Isolate* isolate, Tagged<HeapObject> prototype); // Returns the transitioned map for this map with the most generic // elements_kind that's found in |candidates|, or |nullptr| if no match is // found at all. V8_EXPORT_PRIVATE Tagged<Map> FindElementsKindTransitionedMap( Isolate* isolate, MapHandlesSpan candidates, ConcurrencyMode cmode); inline bool CanTransition() const; static constexpr std::optional<RootIndex> TryGetMapRootIdxFor( InstanceType type) { switch (type) { #define MAKE_CASE(TYPE, Name, name) \ case TYPE: \ return RootIndex::k##Name##Map; STRUCT_LIST(MAKE_CASE) TORQUE_DEFINED_INSTANCE_TYPE_LIST(MAKE_CASE) #undef MAKE_CASE default: break; } return {}; } static inline Tagged<Map> GetMapFor(ReadOnlyRoots roots, InstanceType type); bool IsMapInArrayPrototypeChain(Isolate* isolate) const; // Dispatched behavior. void MapPrint(std::ostream& os); DECL_VERIFIER(Map) #ifdef VERIFY_HEAP void DictionaryMapVerify(Isolate* isolate); #endif DECL_PRIMITIVE_ACCESSORS(visitor_id, VisitorId) static constexpr ObjectFields ObjectFieldsFrom(VisitorId visitor_id) { return (visitor_id < kDataOnlyVisitorIdCount) ? ObjectFields::kDataOnly : ObjectFields::kMaybePointers; } V8_EXPORT_PRIVATE static Handle<Map> TransitionRootMapToPrototypeForNewObject( Isolate* isolate, DirectHandle<Map> map, DirectHandle<JSPrototype> prototype); V8_EXPORT_PRIVATE static Handle<Map> TransitionToUpdatePrototype( Isolate* isolate, DirectHandle<Map> map, DirectHandle<JSPrototype> prototype); static DirectHandle<Map> TransitionToImmutableProto(Isolate* isolate, DirectHandle<Map> map); static_assert(kInstanceTypeOffset == Internals::kMapInstanceTypeOffset); class BodyDescriptor; // Compares this map to another to see if they describe equivalent objects, // up to the given |elements_kind| and |prototype|. If |mode| is set to // CLEAR_INOBJECT_PROPERTIES, |other| is treated as if it had exactly zero // inobject properties. The "shared" flags of both this map and |other| are // ignored. bool EquivalentToForNormalization(const Tagged<Map> other, ElementsKind elements_kind, Tagged<HeapObject> prototype, PropertyNormalizationMode mode) const; inline bool EquivalentToForNormalization( const Tagged<Map> other, PropertyNormalizationMode mode) const; void PrintMapDetails(std::ostream& os); static inline DirectHandle<Map> AddMissingTransitionsForTesting( Isolate* isolate, DirectHandle<Map> split_map, DirectHandle<DescriptorArray> descriptors); // Fires when the layout of an object with a leaf map changes. // This includes adding transitions to the leaf map or changing // the descriptor array. inline void NotifyLeafMapLayoutChange(Isolate* isolate); V8_EXPORT_PRIVATE static VisitorId GetVisitorId(Tagged<Map> map); // Returns true if objects with given instance type are allowed to have // fast transitionable elements kinds. This predicate is used to ensure // that objects that can have transitionable fast elements kind will not // get in-place generalizable fields because the elements kind transition // performed by stubs or optimized code can't properly generalize such // fields. static inline bool CanHaveFastTransitionableElementsKind( InstanceType instance_type); inline bool CanHaveFastTransitionableElementsKind() const; // Maps for Wasm objects can use certain fields for other purposes. inline uint8_t WasmByte1() const; inline uint8_t WasmByte2() const; inline void SetWasmByte1(uint8_t value); inline void SetWasmByte2(uint8_t value); private: // This byte encodes either the instance size without the in-object slack or // the slack size in properties backing store. // Let H be JSObject::kHeaderSize / kTaggedSize. // If value >= H then: // - all field properties are stored in the object. // - there is no property array. // - value * kTaggedSize is the actual object size without the slack. // Otherwise: // - there is no slack in the object. // - the property array has value slack slots. // Note that this encoding requires that H = JSObject::kFieldsAdded. DECL_INT_ACCESSORS(used_or_unused_instance_size_in_words) // Returns the map that this (root) map transitions to if its elements_kind // is changed to |elements_kind|, or |nullptr| if no such map is cached yet. Tagged<Map> LookupElementsTransitionMap(Isolate* isolate, ElementsKind elements_kind, ConcurrencyMode cmode); // Tries to replay property transitions starting from this (root) map using // the descriptor array of the |map|. The |root_map| is expected to have // proper elements kind and therefore elements kinds transitions are not // taken by this function. Returns |nullptr| if matching transition map is // not found. Tagged<Map> TryReplayPropertyTransitions(Isolate* isolate, Tagged<Map> map, ConcurrencyMode cmode); static void ConnectTransition(Isolate* isolate, DirectHandle<Map> parent, DirectHandle<Map> child, DirectHandle<Name> name, TransitionKindFlag transition_kind, bool force_connect = false); bool EquivalentToForTransition( const Tagged<Map> other, ConcurrencyMode cmode, DirectHandle<HeapObject> new_prototype = {}, std::optional<InstanceType> new_instance_type = {}) const; bool EquivalentToForElementsKindTransition(const Tagged<Map> other, ConcurrencyMode cmode) const; static Handle<Map> RawCopy(Isolate* isolate, DirectHandle<Map> map, int instance_size, int inobject_properties); static Handle<Map> ShareDescriptor(Isolate* isolate, DirectHandle<Map> map, DirectHandle<DescriptorArray> descriptors, Descriptor* descriptor); V8_EXPORT_PRIVATE static Handle<Map> AddMissingTransitions( Isolate* isolate, DirectHandle<Map> map, DirectHandle<DescriptorArray> descriptors); static void InstallDescriptors(Isolate* isolate, DirectHandle<Map> parent_map, DirectHandle<Map> child_map, InternalIndex new_descriptor, DirectHandle<DescriptorArray> descriptors, // force_connect is used when copying a map // tree to enforce transitions being added even // for (still) seemingly detached maps. bool force_connect = false); static Handle<Map> CopyAddDescriptor(Isolate* isolate, DirectHandle<Map> map, Descriptor* descriptor, TransitionFlag flag); template <typename InitMapCb> static Handle<Map> CopyReplaceDescriptors( Isolate* isolate, DirectHandle<Map> map, DirectHandle<DescriptorArray> descriptors, TransitionFlag flag, const InitMapCb& InitMap, MaybeDirectHandle<Name> maybe_name, const char* reason, TransitionKindFlag transition_kind); static Handle<Map> CopyReplaceDescriptors( Isolate* isolate, DirectHandle<Map> map, DirectHandle<DescriptorArray> descriptors, TransitionFlag flag, MaybeDirectHandle<Name> maybe_name, const char* reason, TransitionKindFlag transition_kind); static Handle<Map> CopyReplaceDescriptor( Isolate* isolate, DirectHandle<Map> map, DirectHandle<DescriptorArray> descriptors, Descriptor* descriptor, InternalIndex index, TransitionFlag flag); static Handle<Map> CopyNormalized(Isolate* isolate, DirectHandle<Map> map, PropertyNormalizationMode mode); void DeprecateTransitionTree(Isolate* isolate); void DeprecateTransitionTreeImpl(Isolate* isolate); void ReplaceDescriptors(Isolate* isolate, Tagged<DescriptorArray> new_descriptors); // This is the replacement for IsMap() which avoids reading the instance type // but compares the object's map against given meta_map, so it can be used // concurrently without acquire load. V8_INLINE static bool ConcurrentIsHeapObjectWithMap( PtrComprCageBase cage_base, Tagged<Object> object, Tagged<Map> meta_map); // Use the high-level instance_descriptors/SetInstanceDescriptors instead. DECL_RELEASE_SETTER(instance_descriptors, Tagged<DescriptorArray>) // Hide inherited accessors from the generated superclass. DECL_ACCESSORS(constructor_or_back_pointer_or_native_context, Tagged<Object>) DECL_ACCESSORS(transitions_or_prototype_info, Tagged<Object>) friend class MapUpdater; template <typename ConcreteVisitor> friend class MarkingVisitorBase; TQ_OBJECT_CONSTRUCTORS(Map) }; // The cache for maps used by normalized (dictionary mode) objects. // Such maps do not have property descriptors, so a typical program // needs very limited number of distinct normalized maps. class NormalizedMapCache : public WeakFixedArray { public: static DirectHandle<NormalizedMapCache> New(Isolate* isolate); V8_WARN_UNUSED_RESULT MaybeHandle<Map> Get(Isolate* isolate, DirectHandle<Map> fast_map, ElementsKind elements_kind, Tagged<HeapObject> prototype, PropertyNormalizationMode mode); void Set(Isolate* isolate, DirectHandle<Map> fast_map, DirectHandle<Map> normalized_map); DECL_VERIFIER(NormalizedMapCache) private: friend bool IsNormalizedMapCache(Tagged<HeapObject> obj, PtrComprCageBase cage_base); static const int kEntries = 64; static inline int GetIndex(Isolate* isolate, Tagged<Map> map, Tagged<HeapObject> prototype); // The following declarations hide base class methods. Tagged<Object> get(int index); void set(int index, Tagged<Object> value); }; #define DECL_TESTER(Type, ...) inline bool Is##Type##Map(Tagged<Map> map); INSTANCE_TYPE_CHECKERS(DECL_TESTER) #undef DECL_TESTER inline bool IsNullMap(Tagged<Map> map); inline bool IsUndefinedMap(Tagged<Map> map); inline bool IsBooleanMap(Tagged<Map> map); inline bool IsNullOrUndefinedMap(Tagged<Map> map); inline bool IsPrimitiveMap(Tagged<Map> map); inline bool IsSpecialReceiverMap(Tagged<Map> map); inline bool IsCustomElementsReceiverMap(Tagged<Map> map); } // namespace v8::internal #include "src/objects/object-macros-undef.h" #endif // V8_OBJECTS_MAP_H_