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