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