V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
layout-descriptor.cc
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 #include "src/objects-inl.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 Handle<LayoutDescriptor> LayoutDescriptor::New(
17  Isolate* isolate, Handle<Map> map, Handle<DescriptorArray> descriptors,
18  int num_descriptors) {
19  if (!FLAG_unbox_double_fields) return handle(FastPointerLayout(), isolate);
20 
21  int layout_descriptor_length =
22  CalculateCapacity(*map, *descriptors, num_descriptors);
23 
24  if (layout_descriptor_length == 0) {
25  // No double fields were found, use fast pointer layout.
26  return handle(FastPointerLayout(), isolate);
27  }
28 
29  // Initially, layout descriptor corresponds to an object with all fields
30  // tagged.
31  Handle<LayoutDescriptor> layout_descriptor_handle =
32  LayoutDescriptor::New(isolate, layout_descriptor_length);
33 
34  LayoutDescriptor layout_descriptor = Initialize(
35  *layout_descriptor_handle, *map, *descriptors, num_descriptors);
36 
37  return handle(layout_descriptor, isolate);
38 }
39 
40 Handle<LayoutDescriptor> LayoutDescriptor::ShareAppend(
41  Isolate* isolate, Handle<Map> map, PropertyDetails details) {
42  DCHECK(map->owns_descriptors());
43  Handle<LayoutDescriptor> layout_descriptor(map->GetLayoutDescriptor(),
44  isolate);
45 
46  if (!InobjectUnboxedField(map->GetInObjectProperties(), details)) {
47  DCHECK(details.location() != kField ||
48  layout_descriptor->IsTagged(details.field_index()));
49  return layout_descriptor;
50  }
51  int field_index = details.field_index();
52  layout_descriptor = LayoutDescriptor::EnsureCapacity(
53  isolate, layout_descriptor, field_index + details.field_width_in_words());
54 
55  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  return handle(layout_desc, isolate);
62 }
63 
64 Handle<LayoutDescriptor> LayoutDescriptor::AppendIfFastOrUseFull(
65  Isolate* isolate, Handle<Map> map, PropertyDetails details,
66  Handle<LayoutDescriptor> full_layout_descriptor) {
67  DisallowHeapAllocation no_allocation;
68  LayoutDescriptor layout_descriptor = map->layout_descriptor();
69  if (layout_descriptor->IsSlowLayout()) {
70  return full_layout_descriptor;
71  }
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  int field_index = details.field_index();
78  int new_capacity = field_index + details.field_width_in_words();
79  if (new_capacity > layout_descriptor->capacity()) {
80  // Current map's layout descriptor runs out of space, so use the full
81  // layout descriptor.
82  return full_layout_descriptor;
83  }
84 
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 Handle<LayoutDescriptor> LayoutDescriptor::EnsureCapacity(
94  Isolate* isolate, Handle<LayoutDescriptor> layout_descriptor,
95  int new_capacity) {
96  int old_capacity = layout_descriptor->capacity();
97  if (new_capacity <= old_capacity) {
98  return layout_descriptor;
99  }
100  Handle<LayoutDescriptor> new_layout_descriptor =
101  LayoutDescriptor::New(isolate, new_capacity);
102  DCHECK(new_layout_descriptor->IsSlowLayout());
103 
104  if (layout_descriptor->IsSlowLayout()) {
105  memcpy(new_layout_descriptor->GetDataStartAddress(),
106  layout_descriptor->GetDataStartAddress(),
107  layout_descriptor->DataSize());
108  return new_layout_descriptor;
109  } else {
110  // Fast layout.
111  uint32_t value = static_cast<uint32_t>(Smi::ToInt(*layout_descriptor));
112  new_layout_descriptor->set_layout_word(0, value);
113  return new_layout_descriptor;
114  }
115 }
116 
117 
118 bool LayoutDescriptor::IsTagged(int field_index, int max_sequence_length,
119  int* out_sequence_length) {
120  DCHECK_GT(max_sequence_length, 0);
121  if (IsFastPointerLayout()) {
122  *out_sequence_length = max_sequence_length;
123  return true;
124  }
125 
126  int layout_word_index;
127  int layout_bit_index;
128 
129  if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) {
130  // Out of bounds queries are considered tagged.
131  *out_sequence_length = max_sequence_length;
132  return true;
133  }
134  uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
135 
136  uint32_t value = IsSlowLayout() ? get_layout_word(layout_word_index)
137  : static_cast<uint32_t>(Smi::ToInt(*this));
138 
139  bool is_tagged = (value & layout_mask) == 0;
140  if (!is_tagged) value = ~value; // Count set bits instead of cleared bits.
141  value = value & ~(layout_mask - 1); // Clear bits we are not interested in.
142  int sequence_length;
143  if (IsSlowLayout()) {
144  sequence_length = base::bits::CountTrailingZeros(value) - layout_bit_index;
145 
146  if (layout_bit_index + sequence_length == kBitsPerLayoutWord) {
147  // This is a contiguous sequence till the end of current word, proceed
148  // counting in the subsequent words.
149  ++layout_word_index;
150  int num_words = number_of_layout_words();
151  for (; layout_word_index < num_words; layout_word_index++) {
152  value = get_layout_word(layout_word_index);
153  bool cur_is_tagged = (value & 1) == 0;
154  if (cur_is_tagged != is_tagged) break;
155  if (!is_tagged) value = ~value; // Count set bits instead.
156  int cur_sequence_length = base::bits::CountTrailingZeros(value);
157  sequence_length += cur_sequence_length;
158  if (sequence_length >= max_sequence_length) break;
159  if (cur_sequence_length != kBitsPerLayoutWord) break;
160  }
161  if (is_tagged && (field_index + sequence_length == capacity())) {
162  // The contiguous sequence of tagged fields lasts till the end of the
163  // layout descriptor which means that all the fields starting from
164  // field_index are tagged.
165  sequence_length = std::numeric_limits<int>::max();
166  }
167  }
168  } else { // Fast layout.
169  sequence_length = Min(base::bits::CountTrailingZeros(value),
170  static_cast<unsigned>(kBitsInSmiLayout)) -
171  layout_bit_index;
172  if (is_tagged && (field_index + sequence_length == capacity())) {
173  // The contiguous sequence of tagged fields lasts till the end of the
174  // layout descriptor which means that all the fields starting from
175  // field_index are tagged.
176  sequence_length = std::numeric_limits<int>::max();
177  }
178  }
179  *out_sequence_length = Min(sequence_length, max_sequence_length);
180  return is_tagged;
181 }
182 
183 
184 Handle<LayoutDescriptor> LayoutDescriptor::NewForTesting(Isolate* isolate,
185  int length) {
186  return New(isolate, length);
187 }
188 
189 LayoutDescriptor LayoutDescriptor::SetTaggedForTesting(int field_index,
190  bool tagged) {
191  return SetTagged(field_index, tagged);
192 }
193 
194 bool LayoutDescriptorHelper::IsTagged(
195  int offset_in_bytes, int end_offset,
196  int* out_end_of_contiguous_region_offset) {
197  DCHECK(IsAligned(offset_in_bytes, kPointerSize));
198  DCHECK(IsAligned(end_offset, kPointerSize));
199  DCHECK(offset_in_bytes < end_offset);
200  if (all_fields_tagged_) {
201  *out_end_of_contiguous_region_offset = end_offset;
202  DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
203  return true;
204  }
205  int max_sequence_length = (end_offset - offset_in_bytes) / kPointerSize;
206  int field_index = Max(0, (offset_in_bytes - header_size_) / kPointerSize);
207  int sequence_length;
208  bool tagged = layout_descriptor_->IsTagged(field_index, max_sequence_length,
209  &sequence_length);
210  DCHECK_GT(sequence_length, 0);
211  if (offset_in_bytes < header_size_) {
212  // Object headers do not contain non-tagged fields. Check if the contiguous
213  // region continues after the header.
214  if (tagged) {
215  // First field is tagged, calculate end offset from there.
216  *out_end_of_contiguous_region_offset =
217  header_size_ + sequence_length * kPointerSize;
218 
219  } else {
220  *out_end_of_contiguous_region_offset = header_size_;
221  }
222  DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
223  return true;
224  }
225  *out_end_of_contiguous_region_offset =
226  offset_in_bytes + sequence_length * kPointerSize;
227  DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
228  return tagged;
229 }
230 
231 LayoutDescriptor LayoutDescriptor::Trim(Heap* heap, Map map,
232  DescriptorArray* descriptors,
233  int num_descriptors) {
234  DisallowHeapAllocation no_allocation;
235  // Fast mode descriptors are never shared and therefore always fully
236  // correspond to their map.
237  if (!IsSlowLayout()) return *this;
238 
239  int layout_descriptor_length =
240  CalculateCapacity(map, descriptors, num_descriptors);
241  // It must not become fast-mode descriptor here, because otherwise it has to
242  // be fast pointer layout descriptor already but it's is slow mode now.
243  DCHECK_LT(kBitsInSmiLayout, layout_descriptor_length);
244 
245  // Trim, clean and reinitialize this slow-mode layout descriptor.
246  int new_backing_store_length =
247  GetSlowModeBackingStoreLength(layout_descriptor_length);
248  int backing_store_length = length();
249  if (new_backing_store_length != backing_store_length) {
250  DCHECK_LT(new_backing_store_length, backing_store_length);
251  int delta = backing_store_length - new_backing_store_length;
252  heap->RightTrimFixedArray(*this, delta);
253  }
254  memset(GetDataStartAddress(), 0, DataSize());
255  LayoutDescriptor layout_descriptor =
256  Initialize(*this, map, descriptors, num_descriptors);
257  DCHECK_EQ(*this, layout_descriptor);
258  return layout_descriptor;
259 }
260 
261 bool LayoutDescriptor::IsConsistentWithMap(Map map, bool check_tail) {
262  if (FLAG_unbox_double_fields) {
263  DescriptorArray* descriptors = map->instance_descriptors();
264  int nof_descriptors = map->NumberOfOwnDescriptors();
265  int last_field_index = 0;
266  for (int i = 0; i < nof_descriptors; i++) {
267  PropertyDetails details = descriptors->GetDetails(i);
268  if (details.location() != kField) continue;
269  FieldIndex field_index = FieldIndex::ForDescriptor(map, i);
270  bool tagged_expected =
271  !field_index.is_inobject() || !details.representation().IsDouble();
272  for (int bit = 0; bit < details.field_width_in_words(); bit++) {
273  bool tagged_actual = IsTagged(details.field_index() + bit);
274  DCHECK_EQ(tagged_expected, tagged_actual);
275  if (tagged_actual != tagged_expected) return false;
276  }
277  last_field_index =
278  Max(last_field_index,
279  details.field_index() + details.field_width_in_words());
280  }
281  if (check_tail) {
282  int n = capacity();
283  for (int i = last_field_index; i < n; i++) {
284  DCHECK(IsTagged(i));
285  }
286  }
287  }
288  return true;
289 }
290 } // namespace internal
291 } // namespace v8
Definition: libplatform.h:13