layout-descriptor.cc 11.1 KB
Newer Older
1 2 3 4
// 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.

5
#include "src/objects/layout-descriptor.h"
6

7
#include <sstream>
8

9
#include "src/base/bits.h"
10
#include "src/handles/handles-inl.h"
11
#include "src/objects/objects-inl.h"
12 13 14 15 16

namespace v8 {
namespace internal {

Handle<LayoutDescriptor> LayoutDescriptor::New(
17 18
    Isolate* isolate, Handle<Map> map, Handle<DescriptorArray> descriptors,
    int num_descriptors) {
19 20
  if (!FLAG_unbox_double_fields) return handle(FastPointerLayout(), isolate);

21 22
  int layout_descriptor_length =
      CalculateCapacity(*map, *descriptors, num_descriptors);
23

24 25 26
  if (layout_descriptor_length == 0) {
    // No double fields were found, use fast pointer layout.
    return handle(FastPointerLayout(), isolate);
27 28 29 30 31 32 33
  }

  // Initially, layout descriptor corresponds to an object with all fields
  // tagged.
  Handle<LayoutDescriptor> layout_descriptor_handle =
      LayoutDescriptor::New(isolate, layout_descriptor_length);

34
  LayoutDescriptor layout_descriptor = Initialize(
35 36
      *layout_descriptor_handle, *map, *descriptors, num_descriptors);

37 38 39
  return handle(layout_descriptor, isolate);
}

40
Handle<LayoutDescriptor> LayoutDescriptor::ShareAppend(
41
    Isolate* isolate, Handle<Map> map, PropertyDetails details) {
42
  DCHECK(map->owns_descriptors());
43 44 45
  Handle<LayoutDescriptor> layout_descriptor(map->GetLayoutDescriptor(),
                                             isolate);

46
  if (!InobjectUnboxedField(map->GetInObjectProperties(), details)) {
47 48
    DCHECK(details.location() != kField ||
           layout_descriptor->IsTagged(details.field_index()));
49 50 51 52 53 54 55
    return layout_descriptor;
  }
  int field_index = details.field_index();
  layout_descriptor = LayoutDescriptor::EnsureCapacity(
      isolate, layout_descriptor, field_index + details.field_width_in_words());

  DisallowHeapAllocation no_allocation;
56
  LayoutDescriptor layout_desc = *layout_descriptor;
57
  layout_desc = layout_desc.SetRawData(field_index);
58
  if (details.field_width_in_words() > 1) {
59
    layout_desc = layout_desc.SetRawData(field_index + 1);
60 61 62 63 64
  }
  return handle(layout_desc, isolate);
}

Handle<LayoutDescriptor> LayoutDescriptor::AppendIfFastOrUseFull(
65
    Isolate* isolate, Handle<Map> map, PropertyDetails details,
66 67
    Handle<LayoutDescriptor> full_layout_descriptor) {
  DisallowHeapAllocation no_allocation;
68
  LayoutDescriptor layout_descriptor = map->layout_descriptor();
69
  if (layout_descriptor.IsSlowLayout()) {
70 71
    return full_layout_descriptor;
  }
72
  if (!InobjectUnboxedField(map->GetInObjectProperties(), details)) {
73
    DCHECK(details.location() != kField ||
74
           layout_descriptor.IsTagged(details.field_index()));
75
    return handle(layout_descriptor, isolate);
76 77 78
  }
  int field_index = details.field_index();
  int new_capacity = field_index + details.field_width_in_words();
79
  if (new_capacity > layout_descriptor.capacity()) {
80 81 82 83 84
    // Current map's layout descriptor runs out of space, so use the full
    // layout descriptor.
    return full_layout_descriptor;
  }

85
  layout_descriptor = layout_descriptor.SetRawData(field_index);
86
  if (details.field_width_in_words() > 1) {
87
    layout_descriptor = layout_descriptor.SetRawData(field_index + 1);
88
  }
89
  return handle(layout_descriptor, isolate);
90 91 92 93 94 95 96 97 98 99 100 101 102 103
}

Handle<LayoutDescriptor> LayoutDescriptor::EnsureCapacity(
    Isolate* isolate, Handle<LayoutDescriptor> layout_descriptor,
    int new_capacity) {
  int old_capacity = layout_descriptor->capacity();
  if (new_capacity <= old_capacity) {
    return layout_descriptor;
  }
  Handle<LayoutDescriptor> new_layout_descriptor =
      LayoutDescriptor::New(isolate, new_capacity);
  DCHECK(new_layout_descriptor->IsSlowLayout());

  if (layout_descriptor->IsSlowLayout()) {
104 105
    memcpy(new_layout_descriptor->GetDataStartAddress(),
           layout_descriptor->GetDataStartAddress(),
106
           layout_descriptor->DataSize());
107 108 109
    return new_layout_descriptor;
  } else {
    // Fast layout.
jgruber's avatar
jgruber committed
110
    uint32_t value = static_cast<uint32_t>(Smi::ToInt(*layout_descriptor));
111
    new_layout_descriptor->set_layout_word(0, value);
112 113 114
    return new_layout_descriptor;
  }
}
115 116 117

bool LayoutDescriptor::IsTagged(int field_index, int max_sequence_length,
                                int* out_sequence_length) {
118
  DCHECK_GT(max_sequence_length, 0);
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
  if (IsFastPointerLayout()) {
    *out_sequence_length = max_sequence_length;
    return true;
  }

  int layout_word_index;
  int layout_bit_index;

  if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) {
    // Out of bounds queries are considered tagged.
    *out_sequence_length = max_sequence_length;
    return true;
  }
  uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;

jgruber's avatar
jgruber committed
134
  uint32_t value = IsSlowLayout() ? get_layout_word(layout_word_index)
135
                                  : static_cast<uint32_t>(Smi::ToInt(*this));
136 137 138 139

  bool is_tagged = (value & layout_mask) == 0;
  if (!is_tagged) value = ~value;  // Count set bits instead of cleared bits.
  value = value & ~(layout_mask - 1);  // Clear bits we are not interested in.
140 141 142
  int sequence_length;
  if (IsSlowLayout()) {
    sequence_length = base::bits::CountTrailingZeros(value) - layout_bit_index;
143

144 145 146
    if (layout_bit_index + sequence_length == kBitsPerLayoutWord) {
      // This is a contiguous sequence till the end of current word, proceed
      // counting in the subsequent words.
147
      ++layout_word_index;
148 149 150
      int num_words = number_of_layout_words();
      for (; layout_word_index < num_words; layout_word_index++) {
        value = get_layout_word(layout_word_index);
151 152 153
        bool cur_is_tagged = (value & 1) == 0;
        if (cur_is_tagged != is_tagged) break;
        if (!is_tagged) value = ~value;  // Count set bits instead.
154
        int cur_sequence_length = base::bits::CountTrailingZeros(value);
155 156
        sequence_length += cur_sequence_length;
        if (sequence_length >= max_sequence_length) break;
157
        if (cur_sequence_length != kBitsPerLayoutWord) break;
158
      }
159 160 161 162 163 164
      if (is_tagged && (field_index + sequence_length == capacity())) {
        // The contiguous sequence of tagged fields lasts till the end of the
        // layout descriptor which means that all the fields starting from
        // field_index are tagged.
        sequence_length = std::numeric_limits<int>::max();
      }
165
    }
166 167 168 169
  } else {  // Fast layout.
    sequence_length = Min(base::bits::CountTrailingZeros(value),
                          static_cast<unsigned>(kBitsInSmiLayout)) -
                      layout_bit_index;
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
    if (is_tagged && (field_index + sequence_length == capacity())) {
      // The contiguous sequence of tagged fields lasts till the end of the
      // layout descriptor which means that all the fields starting from
      // field_index are tagged.
      sequence_length = std::numeric_limits<int>::max();
    }
  }
  *out_sequence_length = Min(sequence_length, max_sequence_length);
  return is_tagged;
}

Handle<LayoutDescriptor> LayoutDescriptor::NewForTesting(Isolate* isolate,
                                                         int length) {
  return New(isolate, length);
}

186 187
LayoutDescriptor LayoutDescriptor::SetTaggedForTesting(int field_index,
                                                       bool tagged) {
188 189 190 191 192 193
  return SetTagged(field_index, tagged);
}

bool LayoutDescriptorHelper::IsTagged(
    int offset_in_bytes, int end_offset,
    int* out_end_of_contiguous_region_offset) {
194 195
  DCHECK(IsAligned(offset_in_bytes, kTaggedSize));
  DCHECK(IsAligned(end_offset, kTaggedSize));
196 197 198 199 200 201
  DCHECK(offset_in_bytes < end_offset);
  if (all_fields_tagged_) {
    *out_end_of_contiguous_region_offset = end_offset;
    DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
    return true;
  }
202 203
  int max_sequence_length = (end_offset - offset_in_bytes) / kTaggedSize;
  int field_index = Max(0, (offset_in_bytes - header_size_) / kTaggedSize);
204
  int sequence_length;
205 206
  bool tagged = layout_descriptor_.IsTagged(field_index, max_sequence_length,
                                            &sequence_length);
207
  DCHECK_GT(sequence_length, 0);
208 209 210 211 212 213
  if (offset_in_bytes < header_size_) {
    // Object headers do not contain non-tagged fields. Check if the contiguous
    // region continues after the header.
    if (tagged) {
      // First field is tagged, calculate end offset from there.
      *out_end_of_contiguous_region_offset =
214
          header_size_ + sequence_length * kTaggedSize;
215 216 217 218 219 220 221 222

    } else {
      *out_end_of_contiguous_region_offset = header_size_;
    }
    DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
    return true;
  }
  *out_end_of_contiguous_region_offset =
223
      offset_in_bytes + sequence_length * kTaggedSize;
224 225 226
  DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
  return tagged;
}
227

228
LayoutDescriptor LayoutDescriptor::Trim(Heap* heap, Map map,
229
                                        DescriptorArray descriptors,
230
                                        int num_descriptors) {
231 232 233
  DisallowHeapAllocation no_allocation;
  // Fast mode descriptors are never shared and therefore always fully
  // correspond to their map.
234
  if (!IsSlowLayout()) return *this;
235 236 237 238 239

  int layout_descriptor_length =
      CalculateCapacity(map, descriptors, num_descriptors);
  // It must not become fast-mode descriptor here, because otherwise it has to
  // be fast pointer layout descriptor already but it's is slow mode now.
240
  DCHECK_LT(kBitsInSmiLayout, layout_descriptor_length);
241 242

  // Trim, clean and reinitialize this slow-mode layout descriptor.
243 244 245 246 247 248
  int new_backing_store_length =
      GetSlowModeBackingStoreLength(layout_descriptor_length);
  int backing_store_length = length();
  if (new_backing_store_length != backing_store_length) {
    DCHECK_LT(new_backing_store_length, backing_store_length);
    int delta = backing_store_length - new_backing_store_length;
249
    heap->RightTrimFixedArray(*this, delta);
250
  }
251
  memset(GetDataStartAddress(), 0, DataSize());
252 253 254
  LayoutDescriptor layout_descriptor =
      Initialize(*this, map, descriptors, num_descriptors);
  DCHECK_EQ(*this, layout_descriptor);
255 256 257
  return layout_descriptor;
}

258
bool LayoutDescriptor::IsConsistentWithMap(Map map, bool check_tail) {
259
  if (FLAG_unbox_double_fields) {
260 261
    DescriptorArray descriptors = map.instance_descriptors();
    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 267 268 269 270 271 272 273
      FieldIndex field_index = FieldIndex::ForDescriptor(map, i);
      bool tagged_expected =
          !field_index.is_inobject() || !details.representation().IsDouble();
      for (int bit = 0; bit < details.field_width_in_words(); bit++) {
        bool tagged_actual = IsTagged(details.field_index() + bit);
        DCHECK_EQ(tagged_expected, tagged_actual);
        if (tagged_actual != tagged_expected) return false;
      }
274 275 276 277 278 279 280 281 282
      last_field_index =
          Max(last_field_index,
              details.field_index() + details.field_width_in_words());
    }
    if (check_tail) {
      int n = capacity();
      for (int i = last_field_index; i < n; i++) {
        DCHECK(IsTagged(i));
      }
283 284 285 286
    }
  }
  return true;
}
287 288
}  // namespace internal
}  // namespace v8