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 inobject_properties = map->inobject_properties();
23 if (inobject_properties == 0) return handle(FastPointerLayout(), isolate);
25 DCHECK(num_descriptors <= descriptors->number_of_descriptors());
27 int layout_descriptor_length;
28 const int kMaxWordsPerField = kDoubleSize / kPointerSize;
30 if (num_descriptors <= kSmiValueSize / kMaxWordsPerField) {
31 // Even in the "worst" case (all fields are doubles) it would fit into
32 // a Smi, so no need to calculate length.
33 layout_descriptor_length = kSmiValueSize;
36 layout_descriptor_length = 0;
38 for (int i = 0; i < num_descriptors; i++) {
39 PropertyDetails details = descriptors->GetDetails(i);
40 if (!InobjectUnboxedField(inobject_properties, details)) continue;
41 int field_index = details.field_index();
42 int field_width_in_words = details.field_width_in_words();
43 layout_descriptor_length =
44 Max(layout_descriptor_length, field_index + field_width_in_words);
47 if (layout_descriptor_length == 0) {
48 // No double fields were found, use fast pointer layout.
49 return handle(FastPointerLayout(), isolate);
52 layout_descriptor_length = Min(layout_descriptor_length, inobject_properties);
54 // Initially, layout descriptor corresponds to an object with all fields
56 Handle<LayoutDescriptor> layout_descriptor_handle =
57 LayoutDescriptor::New(isolate, layout_descriptor_length);
59 DisallowHeapAllocation no_allocation;
60 LayoutDescriptor* layout_descriptor = *layout_descriptor_handle;
62 for (int i = 0; i < num_descriptors; i++) {
63 PropertyDetails details = descriptors->GetDetails(i);
64 if (!InobjectUnboxedField(inobject_properties, details)) continue;
65 int field_index = details.field_index();
66 layout_descriptor = layout_descriptor->SetRawData(field_index);
67 if (details.field_width_in_words() > 1) {
68 layout_descriptor = layout_descriptor->SetRawData(field_index + 1);
71 return handle(layout_descriptor, isolate);
75 Handle<LayoutDescriptor> LayoutDescriptor::ShareAppend(
76 Handle<Map> map, PropertyDetails details) {
77 DCHECK(map->owns_descriptors());
78 Isolate* isolate = map->GetIsolate();
79 Handle<LayoutDescriptor> layout_descriptor(map->GetLayoutDescriptor(),
82 if (!InobjectUnboxedField(map->inobject_properties(), details)) {
83 DCHECK(details.location() != kField ||
84 layout_descriptor->IsTagged(details.field_index()));
85 return layout_descriptor;
87 int field_index = details.field_index();
88 layout_descriptor = LayoutDescriptor::EnsureCapacity(
89 isolate, layout_descriptor, field_index + details.field_width_in_words());
91 DisallowHeapAllocation no_allocation;
92 LayoutDescriptor* layout_desc = *layout_descriptor;
93 layout_desc = layout_desc->SetRawData(field_index);
94 if (details.field_width_in_words() > 1) {
95 layout_desc = layout_desc->SetRawData(field_index + 1);
97 return handle(layout_desc, isolate);
101 Handle<LayoutDescriptor> LayoutDescriptor::AppendIfFastOrUseFull(
102 Handle<Map> map, PropertyDetails details,
103 Handle<LayoutDescriptor> full_layout_descriptor) {
104 DisallowHeapAllocation no_allocation;
105 LayoutDescriptor* layout_descriptor = map->layout_descriptor();
106 if (layout_descriptor->IsSlowLayout()) {
107 return full_layout_descriptor;
109 if (!InobjectUnboxedField(map->inobject_properties(), details)) {
110 DCHECK(details.location() != kField ||
111 layout_descriptor->IsTagged(details.field_index()));
112 return handle(layout_descriptor, map->GetIsolate());
114 int field_index = details.field_index();
115 int new_capacity = field_index + details.field_width_in_words();
116 if (new_capacity > layout_descriptor->capacity()) {
117 // Current map's layout descriptor runs out of space, so use the full
118 // layout descriptor.
119 return full_layout_descriptor;
122 layout_descriptor = layout_descriptor->SetRawData(field_index);
123 if (details.field_width_in_words() > 1) {
124 layout_descriptor = layout_descriptor->SetRawData(field_index + 1);
126 return handle(layout_descriptor, map->GetIsolate());
130 Handle<LayoutDescriptor> LayoutDescriptor::EnsureCapacity(
131 Isolate* isolate, Handle<LayoutDescriptor> layout_descriptor,
133 int old_capacity = layout_descriptor->capacity();
134 if (new_capacity <= old_capacity) {
135 return layout_descriptor;
137 Handle<LayoutDescriptor> new_layout_descriptor =
138 LayoutDescriptor::New(isolate, new_capacity);
139 DCHECK(new_layout_descriptor->IsSlowLayout());
141 if (layout_descriptor->IsSlowLayout()) {
142 memcpy(new_layout_descriptor->DataPtr(), layout_descriptor->DataPtr(),
143 layout_descriptor->DataSize());
144 return new_layout_descriptor;
148 static_cast<uint32_t>(Smi::cast(*layout_descriptor)->value());
149 new_layout_descriptor->set(0, value);
150 return new_layout_descriptor;
155 bool LayoutDescriptor::IsTagged(int field_index, int max_sequence_length,
156 int* out_sequence_length) {
157 DCHECK(max_sequence_length > 0);
158 if (IsFastPointerLayout()) {
159 *out_sequence_length = max_sequence_length;
163 int layout_word_index;
164 int layout_bit_index;
166 if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) {
167 // Out of bounds queries are considered tagged.
168 *out_sequence_length = max_sequence_length;
171 uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
173 uint32_t value = IsSlowLayout()
174 ? get_scalar(layout_word_index)
175 : static_cast<uint32_t>(Smi::cast(this)->value());
177 bool is_tagged = (value & layout_mask) == 0;
178 if (!is_tagged) value = ~value; // Count set bits instead of cleared bits.
179 value = value & ~(layout_mask - 1); // Clear bits we are not interested in.
180 int sequence_length = CountTrailingZeros32(value) - layout_bit_index;
182 if (layout_bit_index + sequence_length == kNumberOfBits) {
183 // This is a contiguous sequence till the end of current word, proceed
184 // counting in the subsequent words.
185 if (IsSlowLayout()) {
188 for (; layout_word_index < len; layout_word_index++) {
189 value = get_scalar(layout_word_index);
190 bool cur_is_tagged = (value & 1) == 0;
191 if (cur_is_tagged != is_tagged) break;
192 if (!is_tagged) value = ~value; // Count set bits instead.
193 int cur_sequence_length = CountTrailingZeros32(value);
194 sequence_length += cur_sequence_length;
195 if (sequence_length >= max_sequence_length) break;
196 if (cur_sequence_length != kNumberOfBits) break;
199 if (is_tagged && (field_index + sequence_length == capacity())) {
200 // The contiguous sequence of tagged fields lasts till the end of the
201 // layout descriptor which means that all the fields starting from
202 // field_index are tagged.
203 sequence_length = std::numeric_limits<int>::max();
206 *out_sequence_length = Min(sequence_length, max_sequence_length);
211 Handle<LayoutDescriptor> LayoutDescriptor::NewForTesting(Isolate* isolate,
213 return New(isolate, length);
217 LayoutDescriptor* LayoutDescriptor::SetTaggedForTesting(int field_index,
219 return SetTagged(field_index, tagged);
223 bool LayoutDescriptorHelper::IsTagged(
224 int offset_in_bytes, int end_offset,
225 int* out_end_of_contiguous_region_offset) {
226 DCHECK(IsAligned(offset_in_bytes, kPointerSize));
227 DCHECK(IsAligned(end_offset, kPointerSize));
228 DCHECK(offset_in_bytes < end_offset);
229 if (all_fields_tagged_) {
230 *out_end_of_contiguous_region_offset = end_offset;
231 DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
234 int max_sequence_length = (end_offset - offset_in_bytes) / kPointerSize;
235 int field_index = Max(0, (offset_in_bytes - header_size_) / kPointerSize);
237 bool tagged = layout_descriptor_->IsTagged(field_index, max_sequence_length,
239 DCHECK(sequence_length > 0);
240 if (offset_in_bytes < header_size_) {
241 // Object headers do not contain non-tagged fields. Check if the contiguous
242 // region continues after the header.
244 // First field is tagged, calculate end offset from there.
245 *out_end_of_contiguous_region_offset =
246 header_size_ + sequence_length * kPointerSize;
249 *out_end_of_contiguous_region_offset = header_size_;
251 DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
254 *out_end_of_contiguous_region_offset =
255 offset_in_bytes + sequence_length * kPointerSize;
256 DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
261 bool LayoutDescriptor::IsConsistentWithMap(Map* map) {
262 if (FLAG_unbox_double_fields) {
263 DescriptorArray* descriptors = map->instance_descriptors();
264 int nof_descriptors = map->NumberOfOwnDescriptors();
265 for (int i = 0; i < nof_descriptors; i++) {
266 PropertyDetails details = descriptors->GetDetails(i);
267 if (details.type() != DATA) continue;
268 FieldIndex field_index = FieldIndex::ForDescriptor(map, i);
269 bool tagged_expected =
270 !field_index.is_inobject() || !details.representation().IsDouble();
271 for (int bit = 0; bit < details.field_width_in_words(); bit++) {
272 bool tagged_actual = IsTagged(details.field_index() + bit);
273 DCHECK_EQ(tagged_expected, tagged_actual);
274 if (tagged_actual != tagged_expected) return false;
281 } // namespace v8::internal