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