1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
|
// 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_DESCRIPTOR_ARRAY_H_
#define V8_OBJECTS_DESCRIPTOR_ARRAY_H_
#include "src/common/globals.h"
#include "src/objects/fixed-array.h"
// TODO(jkummerow): Consider forward-declaring instead.
#include "src/base/bit-field.h"
#include "src/objects/internal-index.h"
#include "src/objects/objects.h"
#include "src/objects/struct.h"
#include "src/utils/utils.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
template <typename T>
class Handle;
class Isolate;
// An EnumCache is a pair used to hold keys and indices caches.
class EnumCache : public TorqueGeneratedEnumCache<EnumCache, Struct> {
public:
DECL_VERIFIER(EnumCache)
TQ_OBJECT_CONSTRUCTORS(EnumCache)
};
// A DescriptorArray is a custom array that holds instance descriptors.
// It has the following layout:
// Header:
// [16:0 bits]: number_of_all_descriptors (including slack)
// [32:16 bits]: number_of_descriptors
// [48:32 bits]: raw_number_of_marked_descriptors (used by GC)
// [64:48 bits]: alignment filler
// [kEnumCacheOffset]: enum cache
// Elements:
// [kHeaderSize + 0]: first key (and internalized String)
// [kHeaderSize + 1]: first descriptor details (see PropertyDetails)
// [kHeaderSize + 2]: first value for constants / Smi(1) when not used
// Slack:
// [kHeaderSize + number of descriptors * 3]: start of slack
// The "value" fields store either values or field types. A field type is either
// FieldType::None(), FieldType::Any() or a weak reference to a Map. All other
// references are strong.
class DescriptorArray
: public TorqueGeneratedDescriptorArray<DescriptorArray, HeapObject> {
public:
DECL_INT16_ACCESSORS(number_of_all_descriptors)
DECL_INT16_ACCESSORS(number_of_descriptors)
inline int16_t number_of_slack_descriptors() const;
inline int number_of_entries() const;
void ClearEnumCache();
inline void CopyEnumCacheFrom(DescriptorArray array);
static void InitializeOrChangeEnumCache(Handle<DescriptorArray> descriptors,
Isolate* isolate,
Handle<FixedArray> keys,
Handle<FixedArray> indices);
// Accessors for fetching instance descriptor at descriptor number.
inline Name GetKey(InternalIndex descriptor_number) const;
inline Name GetKey(const Isolate* isolate,
InternalIndex descriptor_number) const;
inline Object GetStrongValue(InternalIndex descriptor_number);
inline Object GetStrongValue(const Isolate* isolate,
InternalIndex descriptor_number);
inline MaybeObject GetValue(InternalIndex descriptor_number);
inline MaybeObject GetValue(const Isolate* isolate,
InternalIndex descriptor_number);
inline PropertyDetails GetDetails(InternalIndex descriptor_number);
inline int GetFieldIndex(InternalIndex descriptor_number);
inline FieldType GetFieldType(InternalIndex descriptor_number);
inline FieldType GetFieldType(const Isolate* isolate,
InternalIndex descriptor_number);
inline Name GetSortedKey(int descriptor_number);
inline Name GetSortedKey(const Isolate* isolate, int descriptor_number);
inline int GetSortedKeyIndex(int descriptor_number);
// Accessor for complete descriptor.
inline void Set(InternalIndex descriptor_number, Descriptor* desc);
inline void Set(InternalIndex descriptor_number, Name key, MaybeObject value,
PropertyDetails details);
void Replace(InternalIndex descriptor_number, Descriptor* descriptor);
// Generalizes constness, representation and field type of all field
// descriptors.
void GeneralizeAllFields();
// Append automatically sets the enumeration index. This should only be used
// to add descriptors in bulk at the end, followed by sorting the descriptor
// array.
inline void Append(Descriptor* desc);
static Handle<DescriptorArray> CopyUpTo(Isolate* isolate,
Handle<DescriptorArray> desc,
int enumeration_index, int slack = 0);
static Handle<DescriptorArray> CopyUpToAddAttributes(
Isolate* isolate, Handle<DescriptorArray> desc, int enumeration_index,
PropertyAttributes attributes, int slack = 0);
static Handle<DescriptorArray> CopyForFastObjectClone(
Isolate* isolate, Handle<DescriptorArray> desc, int enumeration_index,
int slack = 0);
// Sort the instance descriptors by the hash codes of their keys.
void Sort();
// Search the instance descriptors for given name.
V8_INLINE InternalIndex Search(Name name, int number_of_own_descriptors);
V8_INLINE InternalIndex Search(Name name, Map map);
// As the above, but uses DescriptorLookupCache and updates it when
// necessary.
V8_INLINE InternalIndex SearchWithCache(Isolate* isolate, Name name, Map map);
bool IsEqualUpTo(DescriptorArray desc, int nof_descriptors);
// Allocates a DescriptorArray, but returns the singleton
// empty descriptor array object if number_of_descriptors is 0.
template <typename LocalIsolate>
V8_EXPORT_PRIVATE static Handle<DescriptorArray> Allocate(
LocalIsolate* isolate, int nof_descriptors, int slack,
AllocationType allocation = AllocationType::kYoung);
void Initialize(EnumCache enum_cache, HeapObject undefined_value,
int nof_descriptors, int slack);
// Constant for denoting key was not found.
static const int kNotFound = -1;
STATIC_ASSERT(IsAligned(kStartOfWeakFieldsOffset, kTaggedSize));
STATIC_ASSERT(IsAligned(kHeaderSize, kTaggedSize));
// Garbage collection support.
DECL_INT16_ACCESSORS(raw_number_of_marked_descriptors)
// Atomic compare-and-swap operation on the raw_number_of_marked_descriptors.
int16_t CompareAndSwapRawNumberOfMarkedDescriptors(int16_t expected,
int16_t value);
int16_t UpdateNumberOfMarkedDescriptors(unsigned mark_compact_epoch,
int16_t number_of_marked_descriptors);
static constexpr int SizeFor(int number_of_all_descriptors) {
return OffsetOfDescriptorAt(number_of_all_descriptors);
}
static constexpr int OffsetOfDescriptorAt(int descriptor) {
return kDescriptorsOffset + descriptor * kEntrySize * kTaggedSize;
}
inline ObjectSlot GetFirstPointerSlot();
inline ObjectSlot GetDescriptorSlot(int descriptor);
static_assert(kEndOfStrongFieldsOffset == kStartOfWeakFieldsOffset,
"Weak fields follow strong fields.");
static_assert(kEndOfWeakFieldsOffset == kHeaderSize,
"Weak fields extend up to the end of the header.");
static_assert(kDescriptorsOffset == kHeaderSize,
"Variable-size array follows header.");
// We use this visitor to also visitor to also visit the enum_cache, which is
// the only tagged field in the header, and placed at the end of the header.
using BodyDescriptor = FlexibleWeakBodyDescriptor<kStartOfStrongFieldsOffset>;
// Layout of descriptor.
// Naming is consistent with Dictionary classes for easy templating.
static const int kEntryKeyIndex = 0;
static const int kEntryDetailsIndex = 1;
static const int kEntryValueIndex = 2;
static const int kEntrySize = 3;
static const int kEntryKeyOffset = kEntryKeyIndex * kTaggedSize;
static const int kEntryDetailsOffset = kEntryDetailsIndex * kTaggedSize;
static const int kEntryValueOffset = kEntryValueIndex * kTaggedSize;
// Print all the descriptors.
void PrintDescriptors(std::ostream& os);
void PrintDescriptorDetails(std::ostream& os, InternalIndex descriptor,
PropertyDetails::PrintMode mode);
DECL_PRINTER(DescriptorArray)
DECL_VERIFIER(DescriptorArray)
#ifdef DEBUG
// Is the descriptor array sorted and without duplicates?
V8_EXPORT_PRIVATE bool IsSortedNoDuplicates(int valid_descriptors = -1);
// Are two DescriptorArrays equal?
bool IsEqualTo(DescriptorArray other);
#endif
static constexpr int ToDetailsIndex(int descriptor_number) {
return (descriptor_number * kEntrySize) + kEntryDetailsIndex;
}
// Conversion from descriptor number to array indices.
static constexpr int ToKeyIndex(int descriptor_number) {
return (descriptor_number * kEntrySize) + kEntryKeyIndex;
}
static constexpr int ToValueIndex(int descriptor_number) {
return (descriptor_number * kEntrySize) + kEntryValueIndex;
}
using EntryKeyField = TaggedField<HeapObject, kEntryKeyOffset>;
using EntryDetailsField = TaggedField<Smi, kEntryDetailsOffset>;
using EntryValueField = TaggedField<MaybeObject, kEntryValueOffset>;
private:
DECL_INT16_ACCESSORS(filler16bits)
inline void SetKey(InternalIndex descriptor_number, Name key);
inline void SetValue(InternalIndex descriptor_number, MaybeObject value);
inline void SetDetails(InternalIndex descriptor_number,
PropertyDetails details);
// Transfer a complete descriptor from the src descriptor array to this
// descriptor array.
void CopyFrom(InternalIndex index, DescriptorArray src);
inline void SetSortedKey(int pointer, int descriptor_number);
// Swap first and second descriptor.
inline void SwapSortedKeys(int first, int second);
TQ_OBJECT_CONSTRUCTORS(DescriptorArray)
};
class NumberOfMarkedDescriptors {
public:
// Bit positions for |bit_field|.
#define BIT_FIELD_FIELDS(V, _) \
V(Epoch, unsigned, 2, _) \
V(Marked, int16_t, 14, _)
DEFINE_BIT_FIELDS(BIT_FIELD_FIELDS)
#undef BIT_FIELD_FIELDS
static const int kMaxNumberOfMarkedDescriptors = Marked::kMax;
// Decodes the raw value of the number of marked descriptors for the
// given mark compact garbage collection epoch.
static inline int16_t decode(unsigned mark_compact_epoch, int16_t raw_value) {
unsigned epoch_from_value = Epoch::decode(static_cast<uint16_t>(raw_value));
int16_t marked_from_value =
Marked::decode(static_cast<uint16_t>(raw_value));
unsigned actual_epoch = mark_compact_epoch & Epoch::kMask;
if (actual_epoch == epoch_from_value) return marked_from_value;
// If the epochs do not match, then either the raw_value is zero (freshly
// allocated descriptor array) or the epoch from value lags by 1.
DCHECK_IMPLIES(raw_value != 0,
Epoch::decode(epoch_from_value + 1) == actual_epoch);
// Not matching epochs means that the no descriptors were marked in the
// current epoch.
return 0;
}
// Encodes the number of marked descriptors for the given mark compact
// garbage collection epoch.
static inline int16_t encode(unsigned mark_compact_epoch, int16_t value) {
// TODO(ulan): avoid casting to int16_t by adding support for uint16_t
// atomics.
return static_cast<int16_t>(
Epoch::encode(mark_compact_epoch & Epoch::kMask) |
Marked::encode(value));
}
};
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_DESCRIPTOR_ARRAY_H_
|