Home | History | Annotate | Download | only in src
      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