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 : #include "src/layout-descriptor.h"
6 :
7 : #include <sstream>
8 :
9 : #include "src/base/bits.h"
10 : #include "src/handles-inl.h"
11 : #include "src/objects-inl.h"
12 :
13 : namespace v8 {
14 : namespace internal {
15 :
16 12356226 : Handle<LayoutDescriptor> LayoutDescriptor::New(
17 : Isolate* isolate, Handle<Map> map, Handle<DescriptorArray> descriptors,
18 : int num_descriptors) {
19 : if (!FLAG_unbox_double_fields) return handle(FastPointerLayout(), isolate);
20 :
21 : int layout_descriptor_length =
22 : CalculateCapacity(*map, *descriptors, num_descriptors);
23 :
24 12356232 : if (layout_descriptor_length == 0) {
25 : // No double fields were found, use fast pointer layout.
26 : return handle(FastPointerLayout(), isolate);
27 : }
28 :
29 : // Initially, layout descriptor corresponds to an object with all fields
30 : // tagged.
31 : Handle<LayoutDescriptor> layout_descriptor_handle =
32 : LayoutDescriptor::New(isolate, layout_descriptor_length);
33 :
34 : LayoutDescriptor layout_descriptor = Initialize(
35 : *layout_descriptor_handle, *map, *descriptors, num_descriptors);
36 :
37 : return handle(layout_descriptor, isolate);
38 : }
39 :
40 6193560 : Handle<LayoutDescriptor> LayoutDescriptor::ShareAppend(
41 : Isolate* isolate, Handle<Map> map, PropertyDetails details) {
42 : DCHECK(map->owns_descriptors());
43 : Handle<LayoutDescriptor> layout_descriptor(map->GetLayoutDescriptor(),
44 : isolate);
45 :
46 12387123 : if (!InobjectUnboxedField(map->GetInObjectProperties(), details)) {
47 : DCHECK(details.location() != kField ||
48 : layout_descriptor->IsTagged(details.field_index()));
49 6184404 : return layout_descriptor;
50 : }
51 : int field_index = details.field_index();
52 : layout_descriptor = LayoutDescriptor::EnsureCapacity(
53 9157 : isolate, layout_descriptor, field_index + details.field_width_in_words());
54 :
55 : DisallowHeapAllocation no_allocation;
56 : LayoutDescriptor layout_desc = *layout_descriptor;
57 : layout_desc = layout_desc->SetRawData(field_index);
58 : if (details.field_width_in_words() > 1) {
59 : layout_desc = layout_desc->SetRawData(field_index + 1);
60 : }
61 : return handle(layout_desc, isolate);
62 : }
63 :
64 30920 : Handle<LayoutDescriptor> LayoutDescriptor::AppendIfFastOrUseFull(
65 : Isolate* isolate, Handle<Map> map, PropertyDetails details,
66 : Handle<LayoutDescriptor> full_layout_descriptor) {
67 : DisallowHeapAllocation no_allocation;
68 : LayoutDescriptor layout_descriptor = map->layout_descriptor();
69 30920 : if (layout_descriptor->IsSlowLayout()) {
70 2200 : return full_layout_descriptor;
71 : }
72 57440 : if (!InobjectUnboxedField(map->GetInObjectProperties(), details)) {
73 : DCHECK(details.location() != kField ||
74 : layout_descriptor->IsTagged(details.field_index()));
75 : return handle(layout_descriptor, isolate);
76 : }
77 : int field_index = details.field_index();
78 : int new_capacity = field_index + details.field_width_in_words();
79 2627 : if (new_capacity > layout_descriptor->capacity()) {
80 : // Current map's layout descriptor runs out of space, so use the full
81 : // layout descriptor.
82 62 : return full_layout_descriptor;
83 : }
84 :
85 : layout_descriptor = layout_descriptor->SetRawData(field_index);
86 : if (details.field_width_in_words() > 1) {
87 : layout_descriptor = layout_descriptor->SetRawData(field_index + 1);
88 : }
89 : return handle(layout_descriptor, isolate);
90 : }
91 :
92 :
93 9157 : Handle<LayoutDescriptor> LayoutDescriptor::EnsureCapacity(
94 : Isolate* isolate, Handle<LayoutDescriptor> layout_descriptor,
95 : int new_capacity) {
96 : int old_capacity = layout_descriptor->capacity();
97 9157 : if (new_capacity <= old_capacity) {
98 9079 : return layout_descriptor;
99 : }
100 : Handle<LayoutDescriptor> new_layout_descriptor =
101 : LayoutDescriptor::New(isolate, new_capacity);
102 : DCHECK(new_layout_descriptor->IsSlowLayout());
103 :
104 78 : if (layout_descriptor->IsSlowLayout()) {
105 20 : memcpy(new_layout_descriptor->GetDataStartAddress(),
106 : layout_descriptor->GetDataStartAddress(),
107 : layout_descriptor->DataSize());
108 20 : return new_layout_descriptor;
109 : } else {
110 : // Fast layout.
111 58 : uint32_t value = static_cast<uint32_t>(Smi::ToInt(*layout_descriptor));
112 : new_layout_descriptor->set_layout_word(0, value);
113 58 : return new_layout_descriptor;
114 : }
115 : }
116 :
117 :
118 553579 : bool LayoutDescriptor::IsTagged(int field_index, int max_sequence_length,
119 : int* out_sequence_length) {
120 : DCHECK_GT(max_sequence_length, 0);
121 553579 : if (IsFastPointerLayout()) {
122 490 : *out_sequence_length = max_sequence_length;
123 490 : return true;
124 : }
125 :
126 : int layout_word_index;
127 : int layout_bit_index;
128 :
129 553089 : if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) {
130 : // Out of bounds queries are considered tagged.
131 200 : *out_sequence_length = max_sequence_length;
132 200 : return true;
133 : }
134 552889 : uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
135 :
136 : uint32_t value = IsSlowLayout() ? get_layout_word(layout_word_index)
137 960598 : : static_cast<uint32_t>(Smi::ToInt(*this));
138 :
139 552889 : bool is_tagged = (value & layout_mask) == 0;
140 552889 : if (!is_tagged) value = ~value; // Count set bits instead of cleared bits.
141 552889 : value = value & ~(layout_mask - 1); // Clear bits we are not interested in.
142 : int sequence_length;
143 552889 : if (IsSlowLayout()) {
144 145115 : sequence_length = base::bits::CountTrailingZeros(value) - layout_bit_index;
145 :
146 145115 : if (layout_bit_index + sequence_length == kBitsPerLayoutWord) {
147 : // This is a contiguous sequence till the end of current word, proceed
148 : // counting in the subsequent words.
149 112956 : ++layout_word_index;
150 : int num_words = number_of_layout_words();
151 672312 : for (; layout_word_index < num_words; layout_word_index++) {
152 : value = get_layout_word(layout_word_index);
153 370568 : bool cur_is_tagged = (value & 1) == 0;
154 370568 : if (cur_is_tagged != is_tagged) break;
155 369680 : if (!is_tagged) value = ~value; // Count set bits instead.
156 369680 : int cur_sequence_length = base::bits::CountTrailingZeros(value);
157 369680 : sequence_length += cur_sequence_length;
158 369680 : if (sequence_length >= max_sequence_length) break;
159 290062 : if (cur_sequence_length != kBitsPerLayoutWord) break;
160 : }
161 164572 : if (is_tagged && (field_index + sequence_length == capacity())) {
162 : // The contiguous sequence of tagged fields lasts till the end of the
163 : // layout descriptor which means that all the fields starting from
164 : // field_index are tagged.
165 : sequence_length = std::numeric_limits<int>::max();
166 : }
167 : }
168 : } else { // Fast layout.
169 : sequence_length = Min(base::bits::CountTrailingZeros(value),
170 407774 : static_cast<unsigned>(kBitsInSmiLayout)) -
171 407774 : layout_bit_index;
172 479456 : if (is_tagged && (field_index + sequence_length == capacity())) {
173 : // The contiguous sequence of tagged fields lasts till the end of the
174 : // layout descriptor which means that all the fields starting from
175 : // field_index are tagged.
176 : sequence_length = std::numeric_limits<int>::max();
177 : }
178 : }
179 552889 : *out_sequence_length = Min(sequence_length, max_sequence_length);
180 552889 : return is_tagged;
181 : }
182 :
183 :
184 215 : Handle<LayoutDescriptor> LayoutDescriptor::NewForTesting(Isolate* isolate,
185 : int length) {
186 215 : return New(isolate, length);
187 : }
188 :
189 147020 : LayoutDescriptor LayoutDescriptor::SetTaggedForTesting(int field_index,
190 : bool tagged) {
191 147020 : return SetTagged(field_index, tagged);
192 : }
193 :
194 407652 : bool LayoutDescriptorHelper::IsTagged(
195 : int offset_in_bytes, int end_offset,
196 : int* out_end_of_contiguous_region_offset) {
197 : DCHECK(IsAligned(offset_in_bytes, kTaggedSize));
198 : DCHECK(IsAligned(end_offset, kTaggedSize));
199 : DCHECK(offset_in_bytes < end_offset);
200 407652 : if (all_fields_tagged_) {
201 1130 : *out_end_of_contiguous_region_offset = end_offset;
202 : DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
203 1130 : return true;
204 : }
205 406522 : int max_sequence_length = (end_offset - offset_in_bytes) / kTaggedSize;
206 406522 : int field_index = Max(0, (offset_in_bytes - header_size_) / kTaggedSize);
207 : int sequence_length;
208 406522 : bool tagged = layout_descriptor_->IsTagged(field_index, max_sequence_length,
209 406522 : &sequence_length);
210 : DCHECK_GT(sequence_length, 0);
211 410584 : if (offset_in_bytes < header_size_) {
212 : // Object headers do not contain non-tagged fields. Check if the contiguous
213 : // region continues after the header.
214 179178 : if (tagged) {
215 : // First field is tagged, calculate end offset from there.
216 : *out_end_of_contiguous_region_offset =
217 20776 : header_size_ + sequence_length * kTaggedSize;
218 :
219 : } else {
220 158402 : *out_end_of_contiguous_region_offset = header_size_;
221 : }
222 : DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
223 : return true;
224 : }
225 : *out_end_of_contiguous_region_offset =
226 231406 : offset_in_bytes + sequence_length * kTaggedSize;
227 : DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
228 231406 : return tagged;
229 : }
230 :
231 5427 : LayoutDescriptor LayoutDescriptor::Trim(Heap* heap, Map map,
232 : DescriptorArray descriptors,
233 : int num_descriptors) {
234 : DisallowHeapAllocation no_allocation;
235 : // Fast mode descriptors are never shared and therefore always fully
236 : // correspond to their map.
237 5427 : if (!IsSlowLayout()) return *this;
238 :
239 : int layout_descriptor_length =
240 : CalculateCapacity(map, descriptors, num_descriptors);
241 : // It must not become fast-mode descriptor here, because otherwise it has to
242 : // be fast pointer layout descriptor already but it's is slow mode now.
243 : DCHECK_LT(kBitsInSmiLayout, layout_descriptor_length);
244 :
245 : // Trim, clean and reinitialize this slow-mode layout descriptor.
246 : int new_backing_store_length =
247 : GetSlowModeBackingStoreLength(layout_descriptor_length);
248 : int backing_store_length = length();
249 23 : if (new_backing_store_length != backing_store_length) {
250 : DCHECK_LT(new_backing_store_length, backing_store_length);
251 5 : int delta = backing_store_length - new_backing_store_length;
252 5 : heap->RightTrimFixedArray(*this, delta);
253 : }
254 23 : memset(GetDataStartAddress(), 0, DataSize());
255 : LayoutDescriptor layout_descriptor =
256 : Initialize(*this, map, descriptors, num_descriptors);
257 : DCHECK_EQ(*this, layout_descriptor);
258 23 : return layout_descriptor;
259 : }
260 :
261 6845 : bool LayoutDescriptor::IsConsistentWithMap(Map map, bool check_tail) {
262 : if (FLAG_unbox_double_fields) {
263 6845 : DescriptorArray descriptors = map->instance_descriptors();
264 : int nof_descriptors = map->NumberOfOwnDescriptors();
265 : int last_field_index = 0;
266 730505 : for (int i = 0; i < nof_descriptors; i++) {
267 361830 : PropertyDetails details = descriptors->GetDetails(i);
268 394170 : if (details.location() != kField) continue;
269 329490 : FieldIndex field_index = FieldIndex::ForDescriptor(map, i);
270 : bool tagged_expected =
271 550680 : !field_index.is_inobject() || !details.representation().IsDouble();
272 988470 : for (int bit = 0; bit < details.field_width_in_words(); bit++) {
273 329490 : bool tagged_actual = IsTagged(details.field_index() + bit);
274 : DCHECK_EQ(tagged_expected, tagged_actual);
275 329490 : if (tagged_actual != tagged_expected) return false;
276 : }
277 : last_field_index =
278 : Max(last_field_index,
279 : details.field_index() + details.field_width_in_words());
280 : }
281 : if (check_tail) {
282 : int n = capacity();
283 : for (int i = last_field_index; i < n; i++) {
284 : DCHECK(IsTagged(i));
285 : }
286 : }
287 : }
288 6845 : return true;
289 : }
290 : } // namespace internal
291 122036 : } // namespace v8
|