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 12 using v8::base::bits::CountTrailingZeros32; 13 14 namespace v8 { 15 namespace internal { 16 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); 21 22 int layout_descriptor_length = 23 CalculateCapacity(*map, *descriptors, num_descriptors); 24 25 if (layout_descriptor_length == 0) { 26 // No double fields were found, use fast pointer layout. 27 return handle(FastPointerLayout(), isolate); 28 } 29 30 // Initially, layout descriptor corresponds to an object with all fields 31 // tagged. 32 Handle<LayoutDescriptor> layout_descriptor_handle = 33 LayoutDescriptor::New(isolate, layout_descriptor_length); 34 35 LayoutDescriptor* layout_descriptor = Initialize( 36 *layout_descriptor_handle, *map, *descriptors, num_descriptors); 37 38 return handle(layout_descriptor, isolate); 39 } 40 41 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(), 47 isolate); 48 49 if (!InobjectUnboxedField(map->GetInObjectProperties(), details)) { 50 DCHECK(details.location() != kField || 51 layout_descriptor->IsTagged(details.field_index())); 52 return layout_descriptor; 53 } 54 int field_index = details.field_index(); 55 layout_descriptor = LayoutDescriptor::EnsureCapacity( 56 isolate, layout_descriptor, field_index + details.field_width_in_words()); 57 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); 63 } 64 return handle(layout_desc, isolate); 65 } 66 67 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; 75 } 76 if (!InobjectUnboxedField(map->GetInObjectProperties(), details)) { 77 DCHECK(details.location() != kField || 78 layout_descriptor->IsTagged(details.field_index())); 79 return handle(layout_descriptor, map->GetIsolate()); 80 } 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 85 // layout descriptor. 86 return full_layout_descriptor; 87 } 88 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); 92 } 93 return handle(layout_descriptor, map->GetIsolate()); 94 } 95 96 97 Handle<LayoutDescriptor> LayoutDescriptor::EnsureCapacity( 98 Isolate* isolate, Handle<LayoutDescriptor> layout_descriptor, 99 int new_capacity) { 100 int old_capacity = layout_descriptor->capacity(); 101 if (new_capacity <= old_capacity) { 102 return layout_descriptor; 103 } 104 Handle<LayoutDescriptor> new_layout_descriptor = 105 LayoutDescriptor::New(isolate, new_capacity); 106 DCHECK(new_layout_descriptor->IsSlowLayout()); 107 108 if (layout_descriptor->IsSlowLayout()) { 109 memcpy(new_layout_descriptor->DataPtr(), layout_descriptor->DataPtr(), 110 layout_descriptor->DataSize()); 111 return new_layout_descriptor; 112 } else { 113 // Fast layout. 114 uint32_t value = 115 static_cast<uint32_t>(Smi::cast(*layout_descriptor)->value()); 116 new_layout_descriptor->set(0, value); 117 return new_layout_descriptor; 118 } 119 } 120 121 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; 127 return true; 128 } 129 130 int layout_word_index; 131 int layout_bit_index; 132 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; 136 return true; 137 } 138 uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index; 139 140 uint32_t value = IsSlowLayout() 141 ? get_scalar(layout_word_index) 142 : static_cast<uint32_t>(Smi::cast(this)->value()); 143 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; 148 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()) { 153 int len = length(); 154 ++layout_word_index; 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; 164 } 165 } 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(); 171 } 172 } 173 *out_sequence_length = Min(sequence_length, max_sequence_length); 174 return is_tagged; 175 } 176 177 178 Handle<LayoutDescriptor> LayoutDescriptor::NewForTesting(Isolate* isolate, 179 int length) { 180 return New(isolate, length); 181 } 182 183 184 LayoutDescriptor* LayoutDescriptor::SetTaggedForTesting(int field_index, 185 bool tagged) { 186 return SetTagged(field_index, tagged); 187 } 188 189 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); 199 return true; 200 } 201 int max_sequence_length = (end_offset - offset_in_bytes) / kPointerSize; 202 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 &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. 210 if (tagged) { 211 // First field is tagged, calculate end offset from there. 212 *out_end_of_contiguous_region_offset = 213 header_size_ + sequence_length * kPointerSize; 214 215 } else { 216 *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 offset_in_bytes + sequence_length * kPointerSize; 223 DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset); 224 return tagged; 225 } 226 227 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; 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 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); 249 } 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; 255 } 256 257 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; 273 } 274 last_field_index = 275 Max(last_field_index, 276 details.field_index() + details.field_width_in_words()); 277 } 278 if (check_tail) { 279 int n = capacity(); 280 for (int i = last_field_index; i < n; i++) { 281 DCHECK(IsTagged(i)); 282 } 283 } 284 } 285 return true; 286 } 287 } // namespace internal 288 } // namespace v8 289