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