layout-descriptor-inl.h 7.74 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_LAYOUT_DESCRIPTOR_INL_H_
#define V8_LAYOUT_DESCRIPTOR_INL_H_

#include "src/layout-descriptor.h"

namespace v8 {
namespace internal {

LayoutDescriptor* LayoutDescriptor::FromSmi(Smi* smi) {
  return LayoutDescriptor::cast(smi);
}


Handle<LayoutDescriptor> LayoutDescriptor::New(Isolate* isolate, int length) {
  if (length <= kSmiValueSize) {
    // The whole bit vector fits into a smi.
    return handle(LayoutDescriptor::FromSmi(Smi::FromInt(0)), isolate);
  }
23
  length = GetSlowModeBackingStoreLength(length);
24 25
  return Handle<LayoutDescriptor>::cast(isolate->factory()->NewFixedTypedArray(
      length, kExternalUint32Array, true));
26 27 28 29 30
}


bool LayoutDescriptor::InobjectUnboxedField(int inobject_properties,
                                            PropertyDetails details) {
31
  if (details.type() != DATA || !details.representation().IsDouble()) {
32 33 34 35 36 37 38 39 40 41 42 43 44
    return false;
  }
  // We care only about in-object properties.
  return details.field_index() < inobject_properties;
}


LayoutDescriptor* LayoutDescriptor::FastPointerLayout() {
  return LayoutDescriptor::FromSmi(Smi::FromInt(0));
}


bool LayoutDescriptor::GetIndexes(int field_index, int* layout_word_index,
45
                                  int* layout_bit_index) {
46 47 48 49 50
  if (static_cast<unsigned>(field_index) >= static_cast<unsigned>(capacity())) {
    return false;
  }

  *layout_word_index = field_index / kNumberOfBits;
51
  CHECK((!IsSmi() && (*layout_word_index < length())) ||
52 53
        (IsSmi() && (*layout_word_index < 1)));

54
  *layout_bit_index = field_index % kNumberOfBits;
55 56 57 58
  return true;
}


59 60 61 62 63
LayoutDescriptor* LayoutDescriptor::SetRawData(int field_index) {
  return SetTagged(field_index, false);
}


64
LayoutDescriptor* LayoutDescriptor::SetTagged(int field_index, bool tagged) {
65 66
  int layout_word_index = 0;
  int layout_bit_index = 0;
67

68
  if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) {
69 70 71
    CHECK(false);
    return this;
  }
72
  uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

  if (IsSlowLayout()) {
    uint32_t value = get_scalar(layout_word_index);
    if (tagged) {
      value &= ~layout_mask;
    } else {
      value |= layout_mask;
    }
    set(layout_word_index, value);
    return this;
  } else {
    uint32_t value = static_cast<uint32_t>(Smi::cast(this)->value());
    if (tagged) {
      value &= ~layout_mask;
    } else {
      value |= layout_mask;
    }
    return LayoutDescriptor::FromSmi(Smi::FromInt(static_cast<int>(value)));
  }
}


bool LayoutDescriptor::IsTagged(int field_index) {
  if (IsFastPointerLayout()) return true;

  int layout_word_index;
99
  int layout_bit_index;
100

101
  if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) {
102 103 104
    // All bits after Out of bounds queries
    return true;
  }
105
  uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
106 107 108 109 110 111 112 113 114 115 116 117

  if (IsSlowLayout()) {
    uint32_t value = get_scalar(layout_word_index);
    return (value & layout_mask) == 0;
  } else {
    uint32_t value = static_cast<uint32_t>(Smi::cast(this)->value());
    return (value & layout_mask) == 0;
  }
}


bool LayoutDescriptor::IsFastPointerLayout() {
118 119 120 121 122 123
  return this == FastPointerLayout();
}


bool LayoutDescriptor::IsFastPointerLayout(Object* layout_descriptor) {
  return layout_descriptor == FastPointerLayout();
124 125 126 127 128 129 130
}


bool LayoutDescriptor::IsSlowLayout() { return !IsSmi(); }


int LayoutDescriptor::capacity() {
131
  return IsSlowLayout() ? (length() * kNumberOfBits) : kSmiValueSize;
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
}


LayoutDescriptor* LayoutDescriptor::cast_gc_safe(Object* object) {
  if (object->IsSmi()) {
    // Fast mode layout descriptor.
    return reinterpret_cast<LayoutDescriptor*>(object);
  }

  // This is a mixed descriptor which is a fixed typed array.
  MapWord map_word = reinterpret_cast<HeapObject*>(object)->map_word();
  if (map_word.IsForwardingAddress()) {
    // Mark-compact has already moved layout descriptor.
    object = map_word.ToForwardingAddress();
  }
  return LayoutDescriptor::cast(object);
}


151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
int LayoutDescriptor::GetSlowModeBackingStoreLength(int length) {
  length = (length + kNumberOfBits - 1) / kNumberOfBits;
  DCHECK_LT(0, length);

  if (SmiValuesAre32Bits() && (length & 1)) {
    // On 64-bit systems if the length is odd then the half-word space would be
    // lost anyway (due to alignment and the fact that we are allocating
    // uint32-typed array), so we increase the length of allocated array
    // to utilize that "lost" space which could also help to avoid layout
    // descriptor reallocations.
    ++length;
  }
  return length;
}


int LayoutDescriptor::CalculateCapacity(Map* map, DescriptorArray* descriptors,
                                        int num_descriptors) {
169
  int inobject_properties = map->GetInObjectProperties();
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
  if (inobject_properties == 0) return 0;

  DCHECK_LE(num_descriptors, descriptors->number_of_descriptors());

  int layout_descriptor_length;
  const int kMaxWordsPerField = kDoubleSize / kPointerSize;

  if (num_descriptors <= kSmiValueSize / kMaxWordsPerField) {
    // Even in the "worst" case (all fields are doubles) it would fit into
    // a Smi, so no need to calculate length.
    layout_descriptor_length = kSmiValueSize;

  } else {
    layout_descriptor_length = 0;

    for (int i = 0; i < num_descriptors; i++) {
      PropertyDetails details = descriptors->GetDetails(i);
      if (!InobjectUnboxedField(inobject_properties, details)) continue;
      int field_index = details.field_index();
      int field_width_in_words = details.field_width_in_words();
      layout_descriptor_length =
          Max(layout_descriptor_length, field_index + field_width_in_words);
    }
  }
  layout_descriptor_length = Min(layout_descriptor_length, inobject_properties);
  return layout_descriptor_length;
}


LayoutDescriptor* LayoutDescriptor::Initialize(
    LayoutDescriptor* layout_descriptor, Map* map, DescriptorArray* descriptors,
    int num_descriptors) {
  DisallowHeapAllocation no_allocation;
203
  int inobject_properties = map->GetInObjectProperties();
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221

  for (int i = 0; i < num_descriptors; i++) {
    PropertyDetails details = descriptors->GetDetails(i);
    if (!InobjectUnboxedField(inobject_properties, details)) {
      DCHECK(details.location() != kField ||
             layout_descriptor->IsTagged(details.field_index()));
      continue;
    }
    int field_index = details.field_index();
    layout_descriptor = layout_descriptor->SetRawData(field_index);
    if (details.field_width_in_words() > 1) {
      layout_descriptor = layout_descriptor->SetRawData(field_index + 1);
    }
  }
  return layout_descriptor;
}


222
// LayoutDescriptorHelper is a helper class for querying whether inobject
223
// property at offset is Double or not.
224
LayoutDescriptorHelper::LayoutDescriptorHelper(Map* map)
225 226 227 228 229 230 231 232 233 234
    : all_fields_tagged_(true),
      header_size_(0),
      layout_descriptor_(LayoutDescriptor::FastPointerLayout()) {
  if (!FLAG_unbox_double_fields) return;

  layout_descriptor_ = map->layout_descriptor_gc_safe();
  if (layout_descriptor_->IsFastPointerLayout()) {
    return;
  }

235
  int inobject_properties = map->GetInObjectProperties();
236 237 238 239 240 241 242 243
  DCHECK(inobject_properties > 0);
  header_size_ = map->instance_size() - (inobject_properties * kPointerSize);
  DCHECK(header_size_ >= 0);

  all_fields_tagged_ = false;
}


244
bool LayoutDescriptorHelper::IsTagged(int offset_in_bytes) {
245 246 247 248 249 250 251 252
  DCHECK(IsAligned(offset_in_bytes, kPointerSize));
  if (all_fields_tagged_) return true;
  // Object headers do not contain non-tagged fields.
  if (offset_in_bytes < header_size_) return true;
  int field_index = (offset_in_bytes - header_size_) / kPointerSize;

  return layout_descriptor_->IsTagged(field_index);
}
253 254
}  // namespace internal
}  // namespace v8
255 256

#endif  // V8_LAYOUT_DESCRIPTOR_INL_H_