1 // Copyright 2014 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_LAYOUT_DESCRIPTOR_INL_H_
6 #define V8_OBJECTS_LAYOUT_DESCRIPTOR_INL_H_
7
8 #include "src/objects/layout-descriptor.h"
9
10 #include "src/handles/handles-inl.h"
11 #include "src/objects/descriptor-array-inl.h"
12 #include "src/objects/fixed-array-inl.h"
13 #include "src/objects/objects-inl.h"
14 #include "src/objects/smi.h"
15
16 // Has to be the last include (doesn't have include guards):
17 #include "src/objects/object-macros.h"
18
19 namespace v8 {
20 namespace internal {
21
LayoutDescriptor(Address ptr)22 LayoutDescriptor::LayoutDescriptor(Address ptr)
23 : ByteArray(ptr, AllowInlineSmiStorage::kAllowBeingASmi) {
24 SLOW_DCHECK(IsLayoutDescriptor());
25 }
CAST_ACCESSOR(LayoutDescriptor)26 CAST_ACCESSOR(LayoutDescriptor)
27
28 LayoutDescriptor LayoutDescriptor::FromSmi(Smi smi) {
29 return LayoutDescriptor::cast(smi);
30 }
31
New(Isolate * isolate,int length)32 Handle<LayoutDescriptor> LayoutDescriptor::New(Isolate* isolate, int length) {
33 if (length <= kBitsInSmiLayout) {
34 // The whole bit vector fits into a smi.
35 return handle(LayoutDescriptor::FromSmi(Smi::zero()), isolate);
36 }
37 int backing_store_length = GetSlowModeBackingStoreLength(length);
38 Handle<LayoutDescriptor> result =
39 Handle<LayoutDescriptor>::cast(isolate->factory()->NewByteArray(
40 backing_store_length, AllocationType::kOld));
41 memset(reinterpret_cast<void*>(result->GetDataStartAddress()), 0,
42 result->DataSize());
43 return result;
44 }
45
InobjectUnboxedField(int inobject_properties,PropertyDetails details)46 bool LayoutDescriptor::InobjectUnboxedField(int inobject_properties,
47 PropertyDetails details) {
48 if (details.location() != kField || !details.representation().IsDouble()) {
49 return false;
50 }
51 // We care only about in-object properties.
52 return details.field_index() < inobject_properties;
53 }
54
FastPointerLayout()55 LayoutDescriptor LayoutDescriptor::FastPointerLayout() {
56 return LayoutDescriptor::FromSmi(Smi::zero());
57 }
58
GetIndexes(int field_index,int * layout_word_index,int * layout_bit_index)59 bool LayoutDescriptor::GetIndexes(int field_index, int* layout_word_index,
60 int* layout_bit_index) {
61 if (static_cast<unsigned>(field_index) >= static_cast<unsigned>(capacity())) {
62 return false;
63 }
64
65 *layout_word_index = field_index / kBitsPerLayoutWord;
66 CHECK((!IsSmi() && (*layout_word_index < length())) ||
67 (IsSmi() && (*layout_word_index < 1)));
68
69 *layout_bit_index = field_index % kBitsPerLayoutWord;
70 return true;
71 }
72
SetRawData(int field_index)73 LayoutDescriptor LayoutDescriptor::SetRawData(int field_index) {
74 return SetTagged(field_index, false);
75 }
76
SetTagged(int field_index,bool tagged)77 LayoutDescriptor LayoutDescriptor::SetTagged(int field_index, bool tagged) {
78 int layout_word_index = 0;
79 int layout_bit_index = 0;
80
81 CHECK(GetIndexes(field_index, &layout_word_index, &layout_bit_index));
82 uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
83
84 if (IsSlowLayout()) {
85 uint32_t value = get_layout_word(layout_word_index);
86 if (tagged) {
87 value &= ~layout_mask;
88 } else {
89 value |= layout_mask;
90 }
91 set_layout_word(layout_word_index, value);
92 return *this;
93 } else {
94 uint32_t value = static_cast<uint32_t>(Smi::ToInt(*this));
95 if (tagged) {
96 value &= ~layout_mask;
97 } else {
98 value |= layout_mask;
99 }
100 return LayoutDescriptor::FromSmi(Smi::FromInt(static_cast<int>(value)));
101 }
102 }
103
IsTagged(int field_index)104 bool LayoutDescriptor::IsTagged(int field_index) {
105 if (IsFastPointerLayout()) return true;
106
107 int layout_word_index;
108 int layout_bit_index;
109
110 if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) {
111 // All bits after Out of bounds queries
112 return true;
113 }
114 uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
115
116 if (IsSlowLayout()) {
117 uint32_t value = get_layout_word(layout_word_index);
118 return (value & layout_mask) == 0;
119 } else {
120 uint32_t value = static_cast<uint32_t>(Smi::ToInt(*this));
121 return (value & layout_mask) == 0;
122 }
123 }
124
IsFastPointerLayout()125 bool LayoutDescriptor::IsFastPointerLayout() {
126 return *this == FastPointerLayout();
127 }
128
IsFastPointerLayout(Object layout_descriptor)129 bool LayoutDescriptor::IsFastPointerLayout(Object layout_descriptor) {
130 return layout_descriptor == FastPointerLayout();
131 }
132
IsSlowLayout()133 bool LayoutDescriptor::IsSlowLayout() { return !IsSmi(); }
134
capacity()135 int LayoutDescriptor::capacity() {
136 return IsSlowLayout() ? (length() * kBitsPerByte) : kBitsInSmiLayout;
137 }
138
cast_gc_safe(Object object)139 LayoutDescriptor LayoutDescriptor::cast_gc_safe(Object object) {
140 // The map word of the object can be a forwarding pointer during
141 // object evacuation phase of GC. Since the layout descriptor methods
142 // for checking whether a field is tagged or not do not depend on the
143 // object map, it should be safe.
144 return LayoutDescriptor::unchecked_cast(object);
145 }
146
GetSlowModeBackingStoreLength(int length)147 int LayoutDescriptor::GetSlowModeBackingStoreLength(int length) {
148 DCHECK_LT(0, length);
149 // We allocate kTaggedSize rounded blocks of memory anyway so we increase
150 // the length of allocated array to utilize that "lost" space which could
151 // also help to avoid layout descriptor reallocations.
152 return RoundUp(length, kBitsPerByte * kTaggedSize) / kBitsPerByte;
153 }
154
CalculateCapacity(Map map,DescriptorArray descriptors,int num_descriptors)155 int LayoutDescriptor::CalculateCapacity(Map map, DescriptorArray descriptors,
156 int num_descriptors) {
157 int inobject_properties = map.GetInObjectProperties();
158 if (inobject_properties == 0) return 0;
159
160 DCHECK_LE(num_descriptors, descriptors.number_of_descriptors());
161
162 int layout_descriptor_length;
163 const int kMaxWordsPerField = kDoubleSize / kTaggedSize;
164
165 if (num_descriptors <= kBitsInSmiLayout / kMaxWordsPerField) {
166 // Even in the "worst" case (all fields are doubles) it would fit into
167 // a Smi, so no need to calculate length.
168 layout_descriptor_length = kBitsInSmiLayout;
169
170 } else {
171 layout_descriptor_length = 0;
172
173 for (InternalIndex i : InternalIndex::Range(num_descriptors)) {
174 PropertyDetails details = descriptors.GetDetails(i);
175 if (!InobjectUnboxedField(inobject_properties, details)) continue;
176 int field_index = details.field_index();
177 int field_width_in_words = details.field_width_in_words();
178 layout_descriptor_length = std::max(layout_descriptor_length,
179 field_index + field_width_in_words);
180 }
181 }
182 layout_descriptor_length =
183 std::min(layout_descriptor_length, inobject_properties);
184 return layout_descriptor_length;
185 }
186
Initialize(LayoutDescriptor layout_descriptor,Map map,DescriptorArray descriptors,int num_descriptors)187 LayoutDescriptor LayoutDescriptor::Initialize(
188 LayoutDescriptor layout_descriptor, Map map, DescriptorArray descriptors,
189 int num_descriptors) {
190 DisallowHeapAllocation no_allocation;
191 int inobject_properties = map.GetInObjectProperties();
192
193 for (InternalIndex i : InternalIndex::Range(num_descriptors)) {
194 PropertyDetails details = descriptors.GetDetails(i);
195 if (!InobjectUnboxedField(inobject_properties, details)) {
196 DCHECK(details.location() != kField ||
197 layout_descriptor.IsTagged(details.field_index()));
198 continue;
199 }
200 int field_index = details.field_index();
201 layout_descriptor = layout_descriptor.SetRawData(field_index);
202 if (details.field_width_in_words() > 1) {
203 layout_descriptor = layout_descriptor.SetRawData(field_index + 1);
204 }
205 }
206 return layout_descriptor;
207 }
208
number_of_layout_words()209 int LayoutDescriptor::number_of_layout_words() {
210 return length() / kUInt32Size;
211 }
212
get_layout_word(int index)213 uint32_t LayoutDescriptor::get_layout_word(int index) const {
214 return get_uint32_relaxed(index);
215 }
216
set_layout_word(int index,uint32_t value)217 void LayoutDescriptor::set_layout_word(int index, uint32_t value) {
218 set_uint32_relaxed(index, value);
219 }
220
221 // LayoutDescriptorHelper is a helper class for querying whether inobject
222 // property at offset is Double or not.
LayoutDescriptorHelper(Map map)223 LayoutDescriptorHelper::LayoutDescriptorHelper(Map map)
224 : all_fields_tagged_(true),
225 header_size_(0),
226 layout_descriptor_(LayoutDescriptor::FastPointerLayout()) {
227 if (!FLAG_unbox_double_fields) return;
228
229 layout_descriptor_ = map.layout_descriptor_gc_safe();
230 if (layout_descriptor_.IsFastPointerLayout()) {
231 return;
232 }
233
234 header_size_ = map.GetInObjectPropertiesStartInWords() * kTaggedSize;
235 DCHECK_GE(header_size_, 0);
236
237 all_fields_tagged_ = false;
238 }
239
IsTagged(int offset_in_bytes)240 bool LayoutDescriptorHelper::IsTagged(int offset_in_bytes) {
241 DCHECK(IsAligned(offset_in_bytes, kTaggedSize));
242 if (all_fields_tagged_) return true;
243 // Object headers do not contain non-tagged fields.
244 if (offset_in_bytes < header_size_) return true;
245 int field_index = (offset_in_bytes - header_size_) / kTaggedSize;
246
247 return layout_descriptor_.IsTagged(field_index);
248 }
249
250 } // namespace internal
251 } // namespace v8
252
253 #include "src/objects/object-macros-undef.h"
254
255 #endif // V8_OBJECTS_LAYOUT_DESCRIPTOR_INL_H_
256