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