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 #ifndef V8_LAYOUT_DESCRIPTOR_INL_H_ 6 #define V8_LAYOUT_DESCRIPTOR_INL_H_ 7 8 #include "src/layout-descriptor.h" 9 #include "src/objects-inl.h" 10 #include "src/objects/descriptor-array.h" 11 12 namespace v8 { 13 namespace internal { 14 15 LayoutDescriptor* LayoutDescriptor::FromSmi(Smi* smi) { 16 return LayoutDescriptor::cast(smi); 17 } 18 19 20 Handle<LayoutDescriptor> LayoutDescriptor::New(Isolate* isolate, int length) { 21 if (length <= kBitsInSmiLayout) { 22 // The whole bit vector fits into a smi. 23 return handle(LayoutDescriptor::FromSmi(Smi::kZero), isolate); 24 } 25 int backing_store_length = GetSlowModeBackingStoreLength(length); 26 Handle<LayoutDescriptor> result = Handle<LayoutDescriptor>::cast( 27 isolate->factory()->NewByteArray(backing_store_length, TENURED)); 28 memset(reinterpret_cast<void*>(result->GetDataStartAddress()), 0, 29 result->DataSize()); 30 return result; 31 } 32 33 34 bool LayoutDescriptor::InobjectUnboxedField(int inobject_properties, 35 PropertyDetails details) { 36 if (details.location() != kField || !details.representation().IsDouble()) { 37 return false; 38 } 39 // We care only about in-object properties. 40 return details.field_index() < inobject_properties; 41 } 42 43 44 LayoutDescriptor* LayoutDescriptor::FastPointerLayout() { 45 return LayoutDescriptor::FromSmi(Smi::kZero); 46 } 47 48 49 bool LayoutDescriptor::GetIndexes(int field_index, int* layout_word_index, 50 int* layout_bit_index) { 51 if (static_cast<unsigned>(field_index) >= static_cast<unsigned>(capacity())) { 52 return false; 53 } 54 55 *layout_word_index = field_index / kBitsPerLayoutWord; 56 CHECK((!IsSmi() && (*layout_word_index < length())) || 57 (IsSmi() && (*layout_word_index < 1))); 58 59 *layout_bit_index = field_index % kBitsPerLayoutWord; 60 return true; 61 } 62 63 64 LayoutDescriptor* LayoutDescriptor::SetRawData(int field_index) { 65 return SetTagged(field_index, false); 66 } 67 68 69 LayoutDescriptor* LayoutDescriptor::SetTagged(int field_index, bool tagged) { 70 int layout_word_index = 0; 71 int layout_bit_index = 0; 72 73 CHECK(GetIndexes(field_index, &layout_word_index, &layout_bit_index)); 74 uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index; 75 76 if (IsSlowLayout()) { 77 uint32_t value = get_layout_word(layout_word_index); 78 if (tagged) { 79 value &= ~layout_mask; 80 } else { 81 value |= layout_mask; 82 } 83 set_layout_word(layout_word_index, value); 84 return this; 85 } else { 86 uint32_t value = static_cast<uint32_t>(Smi::ToInt(this)); 87 if (tagged) { 88 value &= ~layout_mask; 89 } else { 90 value |= layout_mask; 91 } 92 return LayoutDescriptor::FromSmi(Smi::FromInt(static_cast<int>(value))); 93 } 94 } 95 96 97 bool LayoutDescriptor::IsTagged(int field_index) { 98 if (IsFastPointerLayout()) return true; 99 100 int layout_word_index; 101 int layout_bit_index; 102 103 if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) { 104 // All bits after Out of bounds queries 105 return true; 106 } 107 uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index; 108 109 if (IsSlowLayout()) { 110 uint32_t value = get_layout_word(layout_word_index); 111 return (value & layout_mask) == 0; 112 } else { 113 uint32_t value = static_cast<uint32_t>(Smi::ToInt(this)); 114 return (value & layout_mask) == 0; 115 } 116 } 117 118 119 bool LayoutDescriptor::IsFastPointerLayout() { 120 return this == FastPointerLayout(); 121 } 122 123 124 bool LayoutDescriptor::IsFastPointerLayout(Object* layout_descriptor) { 125 return layout_descriptor == FastPointerLayout(); 126 } 127 128 129 bool LayoutDescriptor::IsSlowLayout() { return !IsSmi(); } 130 131 132 int LayoutDescriptor::capacity() { 133 return IsSlowLayout() ? (length() * kBitsPerByte) : kBitsInSmiLayout; 134 } 135 136 137 LayoutDescriptor* LayoutDescriptor::cast_gc_safe(Object* object) { 138 // The map word of the object can be a forwarding pointer during 139 // object evacuation phase of GC. Since the layout descriptor methods 140 // for checking whether a field is tagged or not do not depend on the 141 // object map, it should be safe. 142 return reinterpret_cast<LayoutDescriptor*>(object); 143 } 144 145 int LayoutDescriptor::GetSlowModeBackingStoreLength(int length) { 146 DCHECK_LT(0, length); 147 // We allocate kPointerSize rounded blocks of memory anyway so we increase 148 // the length of allocated array to utilize that "lost" space which could 149 // also help to avoid layout descriptor reallocations. 150 return RoundUp(length, kBitsPerByte * kPointerSize) / kBitsPerByte; 151 } 152 153 154 int LayoutDescriptor::CalculateCapacity(Map* map, DescriptorArray* descriptors, 155 int num_descriptors) { 156 int inobject_properties = map->GetInObjectProperties(); 157 if (inobject_properties == 0) return 0; 158 159 DCHECK_LE(num_descriptors, descriptors->number_of_descriptors()); 160 161 int layout_descriptor_length; 162 const int kMaxWordsPerField = kDoubleSize / kPointerSize; 163 164 if (num_descriptors <= kBitsInSmiLayout / kMaxWordsPerField) { 165 // Even in the "worst" case (all fields are doubles) it would fit into 166 // a Smi, so no need to calculate length. 167 layout_descriptor_length = kBitsInSmiLayout; 168 169 } else { 170 layout_descriptor_length = 0; 171 172 for (int i = 0; i < num_descriptors; i++) { 173 PropertyDetails details = descriptors->GetDetails(i); 174 if (!InobjectUnboxedField(inobject_properties, details)) continue; 175 int field_index = details.field_index(); 176 int field_width_in_words = details.field_width_in_words(); 177 layout_descriptor_length = 178 Max(layout_descriptor_length, field_index + field_width_in_words); 179 } 180 } 181 layout_descriptor_length = Min(layout_descriptor_length, inobject_properties); 182 return layout_descriptor_length; 183 } 184 185 186 LayoutDescriptor* LayoutDescriptor::Initialize( 187 LayoutDescriptor* layout_descriptor, Map* map, DescriptorArray* descriptors, 188 int num_descriptors) { 189 DisallowHeapAllocation no_allocation; 190 int inobject_properties = map->GetInObjectProperties(); 191 192 for (int i = 0; i < num_descriptors; i++) { 193 PropertyDetails details = descriptors->GetDetails(i); 194 if (!InobjectUnboxedField(inobject_properties, details)) { 195 DCHECK(details.location() != kField || 196 layout_descriptor->IsTagged(details.field_index())); 197 continue; 198 } 199 int field_index = details.field_index(); 200 layout_descriptor = layout_descriptor->SetRawData(field_index); 201 if (details.field_width_in_words() > 1) { 202 layout_descriptor = layout_descriptor->SetRawData(field_index + 1); 203 } 204 } 205 return layout_descriptor; 206 } 207 208 int LayoutDescriptor::number_of_layout_words() { 209 return length() / kUInt32Size; 210 } 211 212 uint32_t LayoutDescriptor::get_layout_word(int index) const { 213 return get_uint32(index); 214 } 215 216 void LayoutDescriptor::set_layout_word(int index, uint32_t value) { 217 set_uint32(index, value); 218 } 219 220 // LayoutDescriptorHelper is a helper class for querying whether inobject 221 // property at offset is Double or not. 222 LayoutDescriptorHelper::LayoutDescriptorHelper(Map* map) 223 : all_fields_tagged_(true), 224 header_size_(0), 225 layout_descriptor_(LayoutDescriptor::FastPointerLayout()) { 226 if (!FLAG_unbox_double_fields) return; 227 228 layout_descriptor_ = map->layout_descriptor_gc_safe(); 229 if (layout_descriptor_->IsFastPointerLayout()) { 230 return; 231 } 232 233 header_size_ = map->GetInObjectPropertiesStartInWords() * kPointerSize; 234 DCHECK_GE(header_size_, 0); 235 236 all_fields_tagged_ = false; 237 } 238 239 240 bool LayoutDescriptorHelper::IsTagged(int offset_in_bytes) { 241 DCHECK(IsAligned(offset_in_bytes, kPointerSize)); 242 if (all_fields_tagged_) return true; 243 // Object headers do not contain non-tagged fields. 244 if (offset_in_bytes < header_size_) return true; 245 int field_index = (offset_in_bytes - header_size_) / kPointerSize; 246 247 return layout_descriptor_->IsTagged(field_index); 248 } 249 250 } // namespace internal 251 } // namespace v8 252 253 #endif // V8_LAYOUT_DESCRIPTOR_INL_H_ 254