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.
9 #include "src/base/bits.h"
10 #include "src/layout-descriptor.h"
12 using v8::base::bits::CountTrailingZeros32;
17 Handle<LayoutDescriptor> LayoutDescriptor::New(
18 Handle<Map> map, Handle<DescriptorArray> descriptors, int num_descriptors) {
19 Isolate* isolate = descriptors->GetIsolate();
20 if (!FLAG_unbox_double_fields) return handle(FastPointerLayout(), isolate);
22 int layout_descriptor_length =
23 CalculateCapacity(*map, *descriptors, num_descriptors);
25 if (layout_descriptor_length == 0) {
26 // No double fields were found, use fast pointer layout.
27 return handle(FastPointerLayout(), isolate);
30 // Initially, layout descriptor corresponds to an object with all fields
32 Handle<LayoutDescriptor> layout_descriptor_handle =
33 LayoutDescriptor::New(isolate, layout_descriptor_length);
35 LayoutDescriptor* layout_descriptor = Initialize(
36 *layout_descriptor_handle, *map, *descriptors, num_descriptors);
38 return handle(layout_descriptor, isolate);
42 Handle<LayoutDescriptor> LayoutDescriptor::ShareAppend(
43 Handle<Map> map, PropertyDetails details) {
44 DCHECK(map->owns_descriptors());
45 Isolate* isolate = map->GetIsolate();
46 Handle<LayoutDescriptor> layout_descriptor(map->GetLayoutDescriptor(),
49 if (!InobjectUnboxedField(map->inobject_properties(), details)) {
50 DCHECK(details.location() != kField ||
51 layout_descriptor->IsTagged(details.field_index()));
52 return layout_descriptor;
54 int field_index = details.field_index();
55 layout_descriptor = LayoutDescriptor::EnsureCapacity(
56 isolate, layout_descriptor, field_index + details.field_width_in_words());
58 DisallowHeapAllocation no_allocation;
59 LayoutDescriptor* layout_desc = *layout_descriptor;
60 layout_desc = layout_desc->SetRawData(field_index);
61 if (details.field_width_in_words() > 1) {
62 layout_desc = layout_desc->SetRawData(field_index + 1);
64 return handle(layout_desc, isolate);
68 Handle<LayoutDescriptor> LayoutDescriptor::AppendIfFastOrUseFull(
69 Handle<Map> map, PropertyDetails details,
70 Handle<LayoutDescriptor> full_layout_descriptor) {
71 DisallowHeapAllocation no_allocation;
72 LayoutDescriptor* layout_descriptor = map->layout_descriptor();
73 if (layout_descriptor->IsSlowLayout()) {
74 return full_layout_descriptor;
76 if (!InobjectUnboxedField(map->inobject_properties(), details)) {
77 DCHECK(details.location() != kField ||
78 layout_descriptor->IsTagged(details.field_index()));
79 return handle(layout_descriptor, map->GetIsolate());
81 int field_index = details.field_index();
82 int new_capacity = field_index + details.field_width_in_words();
83 if (new_capacity > layout_descriptor->capacity()) {
84 // Current map's layout descriptor runs out of space, so use the full
86 return full_layout_descriptor;
89 layout_descriptor = layout_descriptor->SetRawData(field_index);
90 if (details.field_width_in_words() > 1) {
91 layout_descriptor = layout_descriptor->SetRawData(field_index + 1);
93 return handle(layout_descriptor, map->GetIsolate());
97 Handle<LayoutDescriptor> LayoutDescriptor::EnsureCapacity(
98 Isolate* isolate, Handle<LayoutDescriptor> layout_descriptor,
100 int old_capacity = layout_descriptor->capacity();
101 if (new_capacity <= old_capacity) {
102 return layout_descriptor;
104 Handle<LayoutDescriptor> new_layout_descriptor =
105 LayoutDescriptor::New(isolate, new_capacity);
106 DCHECK(new_layout_descriptor->IsSlowLayout());
108 if (layout_descriptor->IsSlowLayout()) {
109 memcpy(new_layout_descriptor->DataPtr(), layout_descriptor->DataPtr(),
110 layout_descriptor->DataSize());
111 return new_layout_descriptor;
115 static_cast<uint32_t>(Smi::cast(*layout_descriptor)->value());
116 new_layout_descriptor->set(0, value);
117 return new_layout_descriptor;
122 bool LayoutDescriptor::IsTagged(int field_index, int max_sequence_length,
123 int* out_sequence_length) {
124 DCHECK(max_sequence_length > 0);
125 if (IsFastPointerLayout()) {
126 *out_sequence_length = max_sequence_length;
130 int layout_word_index;
131 int layout_bit_index;
133 if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) {
134 // Out of bounds queries are considered tagged.
135 *out_sequence_length = max_sequence_length;
138 uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
140 uint32_t value = IsSlowLayout()
141 ? get_scalar(layout_word_index)
142 : static_cast<uint32_t>(Smi::cast(this)->value());
144 bool is_tagged = (value & layout_mask) == 0;
145 if (!is_tagged) value = ~value; // Count set bits instead of cleared bits.
146 value = value & ~(layout_mask - 1); // Clear bits we are not interested in.
147 int sequence_length = CountTrailingZeros32(value) - layout_bit_index;
149 if (layout_bit_index + sequence_length == kNumberOfBits) {
150 // This is a contiguous sequence till the end of current word, proceed
151 // counting in the subsequent words.
152 if (IsSlowLayout()) {
155 for (; layout_word_index < len; layout_word_index++) {
156 value = get_scalar(layout_word_index);
157 bool cur_is_tagged = (value & 1) == 0;
158 if (cur_is_tagged != is_tagged) break;
159 if (!is_tagged) value = ~value; // Count set bits instead.
160 int cur_sequence_length = CountTrailingZeros32(value);
161 sequence_length += cur_sequence_length;
162 if (sequence_length >= max_sequence_length) break;
163 if (cur_sequence_length != kNumberOfBits) break;
166 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();
173 *out_sequence_length = Min(sequence_length, max_sequence_length);
178 Handle<LayoutDescriptor> LayoutDescriptor::NewForTesting(Isolate* isolate,
180 return New(isolate, length);
184 LayoutDescriptor* LayoutDescriptor::SetTaggedForTesting(int field_index,
186 return SetTagged(field_index, tagged);
190 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 if (all_fields_tagged_) {
197 *out_end_of_contiguous_region_offset = end_offset;
198 DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
201 int max_sequence_length = (end_offset - offset_in_bytes) / kPointerSize;
202 int field_index = Max(0, (offset_in_bytes - header_size_) / kPointerSize);
204 bool tagged = layout_descriptor_->IsTagged(field_index, max_sequence_length,
206 DCHECK(sequence_length > 0);
207 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.
211 // First field is tagged, calculate end offset from there.
212 *out_end_of_contiguous_region_offset =
213 header_size_ + sequence_length * kPointerSize;
216 *out_end_of_contiguous_region_offset = header_size_;
218 DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
221 *out_end_of_contiguous_region_offset =
222 offset_in_bytes + sequence_length * kPointerSize;
223 DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
228 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 if (!IsSlowLayout()) return this;
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);
242 // Trim, clean and reinitialize this slow-mode layout descriptor.
243 int array_length = GetSlowModeBackingStoreLength(layout_descriptor_length);
244 int current_length = length();
245 if (current_length != array_length) {
246 DCHECK_LT(array_length, current_length);
247 int delta = current_length - array_length;
248 heap->RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>(this, delta);
250 memset(DataPtr(), 0, DataSize());
251 LayoutDescriptor* layout_descriptor =
252 Initialize(this, map, descriptors, num_descriptors);
253 DCHECK_EQ(this, layout_descriptor);
254 return layout_descriptor;
258 bool LayoutDescriptor::IsConsistentWithMap(Map* map, bool check_tail) {
259 if (FLAG_unbox_double_fields) {
260 DescriptorArray* descriptors = map->instance_descriptors();
261 int nof_descriptors = map->NumberOfOwnDescriptors();
262 int last_field_index = 0;
263 for (int i = 0; i < nof_descriptors; i++) {
264 PropertyDetails details = descriptors->GetDetails(i);
265 if (details.location() != kField) continue;
266 FieldIndex field_index = FieldIndex::ForDescriptor(map, i);
267 bool tagged_expected =
268 !field_index.is_inobject() || !details.representation().IsDouble();
269 for (int bit = 0; bit < details.field_width_in_words(); bit++) {
270 bool tagged_actual = IsTagged(details.field_index() + bit);
271 DCHECK_EQ(tagged_expected, tagged_actual);
272 if (tagged_actual != tagged_expected) return false;
275 Max(last_field_index,
276 details.field_index() + details.field_width_in_words());
280 for (int i = last_field_index; i < n; i++) {
287 } // namespace internal