v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
descriptor-array.h
Go to the documentation of this file.
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_DESCRIPTOR_ARRAY_H_
6#define V8_OBJECTS_DESCRIPTOR_ARRAY_H_
7
10// TODO(jkummerow): Consider forward-declaring instead.
11#include "src/base/bit-field.h"
13#include "src/objects/objects.h"
14#include "src/objects/struct.h"
15#include "src/utils/utils.h"
16
17// Has to be the last include (doesn't have include guards):
19
20namespace v8 {
21namespace internal {
22
23class StructBodyDescriptor;
24
25#include "torque-generated/src/objects/descriptor-array-tq.inc"
26
27// An EnumCache is a pair used to hold keys and indices caches.
28class EnumCache : public TorqueGeneratedEnumCache<EnumCache, Struct> {
29 public:
31
33
35};
36
37// A DescriptorArray is a custom array that holds instance descriptors.
38// It has the following layout:
39// Header:
40// [16:0 bits]: number_of_all_descriptors (including slack)
41// [32:16 bits]: number_of_descriptors
42// [64:32 bits]: raw_gc_state (used by GC)
43// [kEnumCacheOffset]: enum cache
44// Elements:
45// [kHeaderSize + 0]: first key (and internalized String)
46// [kHeaderSize + 1]: first descriptor details (see PropertyDetails)
47// [kHeaderSize + 2]: first value for constants / Tagged<Smi>(1) when not
48// used
49// Slack:
50// [kHeaderSize + number of descriptors * 3]: start of slack
51// The "value" fields store either values or field types. A field type is either
52// FieldType::None(), FieldType::Any() or a weak reference to a Map. All other
53// references are strong.
55 : public TorqueGeneratedDescriptorArray<DescriptorArray, HeapObject> {
56 public:
57 DECL_INT16_ACCESSORS(number_of_all_descriptors)
59 inline int16_t number_of_slack_descriptors() const;
60 inline int number_of_entries() const;
61
62 void ClearEnumCache();
63 inline void CopyEnumCacheFrom(Tagged<DescriptorArray> array);
64 static void InitializeOrChangeEnumCache(
65 DirectHandle<DescriptorArray> descriptors, Isolate* isolate,
67 AllocationType allocation_if_initialize);
68
69 // Accessors for fetching instance descriptor at descriptor number.
70 inline Tagged<Name> GetKey(InternalIndex descriptor_number) const;
71 inline Tagged<Name> GetKey(PtrComprCageBase cage_base,
72 InternalIndex descriptor_number) const;
73 inline Tagged<Object> GetStrongValue(InternalIndex descriptor_number);
74 inline Tagged<Object> GetStrongValue(PtrComprCageBase cage_base,
75 InternalIndex descriptor_number);
76 inline Tagged<MaybeObject> GetValue(InternalIndex descriptor_number);
77 inline Tagged<MaybeObject> GetValue(PtrComprCageBase cage_base,
78 InternalIndex descriptor_number);
79 inline PropertyDetails GetDetails(InternalIndex descriptor_number);
80 inline int GetFieldIndex(InternalIndex descriptor_number);
81 inline Tagged<FieldType> GetFieldType(InternalIndex descriptor_number);
82 inline Tagged<FieldType> GetFieldType(PtrComprCageBase cage_base,
83 InternalIndex descriptor_number);
84
85 // Returns true if given entry is already initialized. Useful in cases
86 // when a heap stats collector might see a half-initialized descriptor.
87 inline bool IsInitializedDescriptor(InternalIndex descriptor_number) const;
88
89 inline Tagged<Name> GetSortedKey(int descriptor_number);
90 inline Tagged<Name> GetSortedKey(PtrComprCageBase cage_base,
91 int descriptor_number);
92 inline int GetSortedKeyIndex(int descriptor_number);
93
94 // Accessor for complete descriptor.
95 inline void Set(InternalIndex descriptor_number, Descriptor* desc);
96 inline void Set(InternalIndex descriptor_number, Tagged<Name> key,
98 void Replace(InternalIndex descriptor_number, Descriptor* descriptor);
99
100 // Generalizes constness, representation and field type of all field
101 // descriptors.
102 void GeneralizeAllFields(bool clear_constness);
103
104 // Append automatically sets the enumeration index. This should only be used
105 // to add descriptors in bulk at the end, followed by sorting the descriptor
106 // array.
107 inline void Append(Descriptor* desc);
108
109 static DirectHandle<DescriptorArray> CopyUpTo(
111 int enumeration_index, int slack = 0);
112
113 static DirectHandle<DescriptorArray> CopyUpToAddAttributes(
115 int enumeration_index, PropertyAttributes attributes, int slack = 0);
116
117 // Sort the instance descriptors by the hash codes of their keys.
118 V8_EXPORT_PRIVATE void Sort();
119
120 // Iterate through Name hash collisions in the descriptor array starting from
121 // insertion index checking for Name collisions. Note: If we ever add binary
122 // insertion for large DescriptorArrays it would need to be hardened in a
123 // similar way. This function only expects to be called on Sorted
124 // DescriptorArrays.
125 V8_EXPORT_PRIVATE void CheckNameCollisionDuringInsertion(
126 Descriptor* desc, uint32_t descriptor_hash, int insertion_index);
127
128 // Search the instance descriptors for given name. {concurrent_search} signals
129 // if we are doing the search on a background thread. If so, we will sacrifice
130 // speed for thread-safety.
132 int number_of_own_descriptors,
133 bool concurrent_search = false);
135 bool concurrent_search = false);
136
137 // Search the instance descriptors for given field offset.
138 V8_INLINE InternalIndex Search(int field_offset,
139 int number_of_own_descriptors);
140 V8_INLINE InternalIndex Search(int field_offset, Tagged<Map> map);
141
142 // As the above, but uses DescriptorLookupCache and updates it when
143 // necessary.
144 V8_INLINE InternalIndex SearchWithCache(Isolate* isolate, Tagged<Name> name,
145 Tagged<Map> map);
146
147 bool IsEqualUpTo(Tagged<DescriptorArray> desc, int nof_descriptors);
148
149 // Allocates a DescriptorArray, but returns the singleton
150 // empty descriptor array object if number_of_descriptors is 0.
151 template <typename IsolateT>
153 IsolateT* isolate, int nof_descriptors, int slack,
155
156 void Initialize(Tagged<EnumCache> enum_cache,
157 Tagged<HeapObject> undefined_value, int nof_descriptors,
158 int slack, uint32_t raw_gc_state);
159
160 // Constant for denoting key was not found.
161 static const int kNotFound = -1;
162
163 static_assert(IsAligned(kStartOfWeakFieldsOffset, kTaggedSize));
164 static_assert(IsAligned(kHeaderSize, kTaggedSize));
165
166 // Garbage collection support.
168 static constexpr size_t kSizeOfRawGcState =
169 kRawGcStateOffsetEnd - kRawGcStateOffset + 1;
170
171 static constexpr int SizeFor(int number_of_all_descriptors) {
172 return OffsetOfDescriptorAt(number_of_all_descriptors);
173 }
174 static constexpr int OffsetOfDescriptorAt(int descriptor) {
175 return kDescriptorsOffset + descriptor * kEntrySize * kTaggedSize;
176 }
177 inline ObjectSlot GetFirstPointerSlot();
178 inline ObjectSlot GetDescriptorSlot(int descriptor);
179
180 static_assert(kEndOfStrongFieldsOffset == kStartOfWeakFieldsOffset,
181 "Weak fields follow strong fields.");
182 static_assert(kEndOfWeakFieldsOffset == kHeaderSize,
183 "Weak fields extend up to the end of the header.");
184 static_assert(kDescriptorsOffset == kHeaderSize,
185 "Variable-size array follows header.");
186 class BodyDescriptor;
187
188 // Layout of descriptor.
189 // Naming is consistent with Dictionary classes for easy templating.
190 static const int kEntryKeyIndex = 0;
191 static const int kEntryDetailsIndex = 1;
192 static const int kEntryValueIndex = 2;
193 static const int kEntrySize = 3;
194
195 static const int kEntryKeyOffset = kEntryKeyIndex * kTaggedSize;
196 static const int kEntryDetailsOffset = kEntryDetailsIndex * kTaggedSize;
197 static const int kEntryValueOffset = kEntryValueIndex * kTaggedSize;
198
199 // Print all the descriptors.
200 void PrintDescriptors(std::ostream& os);
201 void PrintDescriptorDetails(std::ostream& os, InternalIndex descriptor,
203
206
207#ifdef DEBUG
208 // Is the descriptor array sorted and without duplicates?
209 V8_EXPORT_PRIVATE bool IsSortedNoDuplicates();
210
211 // Are two DescriptorArrays equal?
212 bool IsEqualTo(Tagged<DescriptorArray> other);
213#endif
214
215 static constexpr int ToDetailsIndex(int descriptor_number) {
216 return (descriptor_number * kEntrySize) + kEntryDetailsIndex;
217 }
218
219 // Conversion from descriptor number to array indices.
220 static constexpr int ToKeyIndex(int descriptor_number) {
221 return (descriptor_number * kEntrySize) + kEntryKeyIndex;
222 }
223
224 static constexpr int ToValueIndex(int descriptor_number) {
225 return (descriptor_number * kEntrySize) + kEntryValueIndex;
226 }
227
231
232 private:
233 inline void SetKey(InternalIndex descriptor_number, Tagged<Name> key);
234 inline void SetValue(InternalIndex descriptor_number,
235 Tagged<MaybeObject> value);
236 inline void SetDetails(InternalIndex descriptor_number,
237 PropertyDetails details);
238
239 V8_INLINE InternalIndex BinarySearch(Tagged<Name> name,
240 int number_of_own_descriptors);
241 V8_INLINE InternalIndex LinearSearch(Tagged<Name> name,
242 int number_of_own_descriptors);
243
244 // Transfer a complete descriptor from the src descriptor array to this
245 // descriptor array.
246 void CopyFrom(InternalIndex index, Tagged<DescriptorArray> src);
247
248 inline void SetSortedKey(int pointer, int descriptor_number);
249
250 // Swap first and second descriptor.
251 inline void SwapSortedKeys(int first, int second);
252
254};
255
256// Custom DescriptorArray marking state for visitors that are allowed to write
257// into the heap. The marking state uses DescriptorArray::raw_gc_state() as
258// storage.
259//
260// The state essentially keeps track of 3 fields:
261// 1. The collector epoch: The rest of the state is only valid if the epoch
262// matches. If the epoch doesn't match, the other fields should be considered
263// invalid. The epoch is necessary, as not all DescriptorArray objects are
264// eventually trimmed in the atomic pause and thus available for resetting
265// the state.
266// 2. Number of already marked descriptors.
267// 3. Delta of to be marked descriptors in this cycle. This must be 0 after
268// marking is done.
270 public:
271#define BIT_FIELD_FIELDS(V, _) \
272 V(Epoch, unsigned, 2, _) \
273 V(Marked, uint16_t, 14, _) \
274 V(Delta, uint16_t, 16, _)
276#undef BIT_FIELD_FIELDS
277 static_assert(Marked::kMax <= Delta::kMax);
278 static_assert(kMaxNumberOfDescriptors <= Marked::kMax);
279
280 using DescriptorIndex = uint16_t;
281 using RawGCStateType = uint32_t;
282
283 static constexpr RawGCStateType kInitialGCState = 0;
284
286 unsigned epoch, DescriptorIndex number_of_descriptors) {
287 return NewState(epoch & Epoch::kMask, number_of_descriptors, 0);
288 }
289
290 // Potentially updates the delta of to be marked descriptors. Returns true if
291 // the update was successful and the object should be processed via a marking
292 // visitor.
293 //
294 // The call issues and Acq/Rel barrier to allow synchronizing other state
295 // (e.g. value of descriptor slots) with it.
296 static inline bool TryUpdateIndicesToMark(unsigned gc_epoch,
298 DescriptorIndex index_to_mark);
299
300 // Used from the visitor when processing a DescriptorArray. Returns a range of
301 // start and end descriptor indices. No processing is required for start ==
302 // end. The method signals the first invocation by returning start == 0, and
303 // end != 0.
304 static inline std::pair<DescriptorIndex, DescriptorIndex>
305 AcquireDescriptorRangeToMark(unsigned gc_epoch,
307
308 private:
309 static constexpr RawGCStateType NewState(unsigned masked_epoch,
310 DescriptorIndex marked,
311 DescriptorIndex delta) {
312 return Epoch::encode(masked_epoch) | Marked::encode(marked) |
313 Delta::encode(delta);
314 }
315
317 RawGCStateType new_state) {
318 return static_cast<RawGCStateType>(base::AcquireRelease_CompareAndSwap(
319 reinterpret_cast<base::Atomic32*>(
320 FIELD_ADDR(array, DescriptorArray::kRawGcStateOffset)),
321 old_state, new_state)) == old_state;
322 }
323};
324
325} // namespace internal
326} // namespace v8
327
329
330#endif // V8_OBJECTS_DESCRIPTOR_ARRAY_H_
#define DEFINE_BIT_FIELDS(LIST_MACRO)
Definition bit-field.h:126
static constexpr RawGCStateType GetFullyMarkedState(unsigned epoch, DescriptorIndex number_of_descriptors)
static constexpr RawGCStateType NewState(unsigned masked_epoch, DescriptorIndex marked, DescriptorIndex delta)
static bool SwapState(Tagged< DescriptorArray > array, RawGCStateType old_state, RawGCStateType new_state)
static constexpr int ToKeyIndex(int descriptor_number)
static constexpr int ToValueIndex(int descriptor_number)
static V8_EXPORT_PRIVATE Handle< DescriptorArray > Allocate(IsolateT *isolate, int nof_descriptors, int slack, AllocationType allocation=AllocationType::kYoung)
static constexpr int OffsetOfDescriptorAt(int descriptor)
static constexpr int ToDetailsIndex(int descriptor_number)
StructBodyDescriptor BodyDescriptor
#define BIT_FIELD_FIELDS(V, _)
double second
int32_t Atomic32
Definition atomicops.h:59
constexpr int kTaggedSize
Definition globals.h:542
#define FIELD_ADDR(p, offset)
#define DECL_INT16_ACCESSORS(name)
#define DECL_VERIFIER(Name)
#define DECL_RELAXED_UINT32_ACCESSORS(name)
#define DECL_PRINTER(Name)
#define TQ_OBJECT_CONSTRUCTORS(Type)
#define V8_EXPORT_PRIVATE
Definition macros.h:460
constexpr bool IsAligned(T value, U alignment)
Definition macros.h:403
#define V8_INLINE
Definition v8config.h:500