• 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 #ifndef V8_OBJECTS_LAYOUT_DESCRIPTOR_INL_H_
6 #define V8_OBJECTS_LAYOUT_DESCRIPTOR_INL_H_
7 
8 #include "src/objects/layout-descriptor.h"
9 
10 #include "src/handles/handles-inl.h"
11 #include "src/objects/descriptor-array-inl.h"
12 #include "src/objects/fixed-array-inl.h"
13 #include "src/objects/objects-inl.h"
14 #include "src/objects/smi.h"
15 
16 // Has to be the last include (doesn't have include guards):
17 #include "src/objects/object-macros.h"
18 
19 namespace v8 {
20 namespace internal {
21 
LayoutDescriptor(Address ptr)22 LayoutDescriptor::LayoutDescriptor(Address ptr)
23     : ByteArray(ptr, AllowInlineSmiStorage::kAllowBeingASmi) {
24   SLOW_DCHECK(IsLayoutDescriptor());
25 }
CAST_ACCESSOR(LayoutDescriptor)26 CAST_ACCESSOR(LayoutDescriptor)
27 
28 LayoutDescriptor LayoutDescriptor::FromSmi(Smi smi) {
29   return LayoutDescriptor::cast(smi);
30 }
31 
New(Isolate * isolate,int length)32 Handle<LayoutDescriptor> LayoutDescriptor::New(Isolate* isolate, int length) {
33   if (length <= kBitsInSmiLayout) {
34     // The whole bit vector fits into a smi.
35     return handle(LayoutDescriptor::FromSmi(Smi::zero()), isolate);
36   }
37   int backing_store_length = GetSlowModeBackingStoreLength(length);
38   Handle<LayoutDescriptor> result =
39       Handle<LayoutDescriptor>::cast(isolate->factory()->NewByteArray(
40           backing_store_length, AllocationType::kOld));
41   memset(reinterpret_cast<void*>(result->GetDataStartAddress()), 0,
42          result->DataSize());
43   return result;
44 }
45 
InobjectUnboxedField(int inobject_properties,PropertyDetails details)46 bool LayoutDescriptor::InobjectUnboxedField(int inobject_properties,
47                                             PropertyDetails details) {
48   if (details.location() != kField || !details.representation().IsDouble()) {
49     return false;
50   }
51   // We care only about in-object properties.
52   return details.field_index() < inobject_properties;
53 }
54 
FastPointerLayout()55 LayoutDescriptor LayoutDescriptor::FastPointerLayout() {
56   return LayoutDescriptor::FromSmi(Smi::zero());
57 }
58 
GetIndexes(int field_index,int * layout_word_index,int * layout_bit_index)59 bool LayoutDescriptor::GetIndexes(int field_index, int* layout_word_index,
60                                   int* layout_bit_index) {
61   if (static_cast<unsigned>(field_index) >= static_cast<unsigned>(capacity())) {
62     return false;
63   }
64 
65   *layout_word_index = field_index / kBitsPerLayoutWord;
66   CHECK((!IsSmi() && (*layout_word_index < length())) ||
67         (IsSmi() && (*layout_word_index < 1)));
68 
69   *layout_bit_index = field_index % kBitsPerLayoutWord;
70   return true;
71 }
72 
SetRawData(int field_index)73 LayoutDescriptor LayoutDescriptor::SetRawData(int field_index) {
74   return SetTagged(field_index, false);
75 }
76 
SetTagged(int field_index,bool tagged)77 LayoutDescriptor LayoutDescriptor::SetTagged(int field_index, bool tagged) {
78   int layout_word_index = 0;
79   int layout_bit_index = 0;
80 
81   CHECK(GetIndexes(field_index, &layout_word_index, &layout_bit_index));
82   uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
83 
84   if (IsSlowLayout()) {
85     uint32_t value = get_layout_word(layout_word_index);
86     if (tagged) {
87       value &= ~layout_mask;
88     } else {
89       value |= layout_mask;
90     }
91     set_layout_word(layout_word_index, value);
92     return *this;
93   } else {
94     uint32_t value = static_cast<uint32_t>(Smi::ToInt(*this));
95     if (tagged) {
96       value &= ~layout_mask;
97     } else {
98       value |= layout_mask;
99     }
100     return LayoutDescriptor::FromSmi(Smi::FromInt(static_cast<int>(value)));
101   }
102 }
103 
IsTagged(int field_index)104 bool LayoutDescriptor::IsTagged(int field_index) {
105   if (IsFastPointerLayout()) return true;
106 
107   int layout_word_index;
108   int layout_bit_index;
109 
110   if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) {
111     // All bits after Out of bounds queries
112     return true;
113   }
114   uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
115 
116   if (IsSlowLayout()) {
117     uint32_t value = get_layout_word(layout_word_index);
118     return (value & layout_mask) == 0;
119   } else {
120     uint32_t value = static_cast<uint32_t>(Smi::ToInt(*this));
121     return (value & layout_mask) == 0;
122   }
123 }
124 
IsFastPointerLayout()125 bool LayoutDescriptor::IsFastPointerLayout() {
126   return *this == FastPointerLayout();
127 }
128 
IsFastPointerLayout(Object layout_descriptor)129 bool LayoutDescriptor::IsFastPointerLayout(Object layout_descriptor) {
130   return layout_descriptor == FastPointerLayout();
131 }
132 
IsSlowLayout()133 bool LayoutDescriptor::IsSlowLayout() { return !IsSmi(); }
134 
capacity()135 int LayoutDescriptor::capacity() {
136   return IsSlowLayout() ? (length() * kBitsPerByte) : kBitsInSmiLayout;
137 }
138 
cast_gc_safe(Object object)139 LayoutDescriptor LayoutDescriptor::cast_gc_safe(Object object) {
140   // The map word of the object can be a forwarding pointer during
141   // object evacuation phase of GC. Since the layout descriptor methods
142   // for checking whether a field is tagged or not do not depend on the
143   // object map, it should be safe.
144   return LayoutDescriptor::unchecked_cast(object);
145 }
146 
GetSlowModeBackingStoreLength(int length)147 int LayoutDescriptor::GetSlowModeBackingStoreLength(int length) {
148   DCHECK_LT(0, length);
149   // We allocate kTaggedSize rounded blocks of memory anyway so we increase
150   // the length  of allocated array to utilize that "lost" space which could
151   // also help to avoid layout descriptor reallocations.
152   return RoundUp(length, kBitsPerByte * kTaggedSize) / kBitsPerByte;
153 }
154 
CalculateCapacity(Map map,DescriptorArray descriptors,int num_descriptors)155 int LayoutDescriptor::CalculateCapacity(Map map, DescriptorArray descriptors,
156                                         int num_descriptors) {
157   int inobject_properties = map.GetInObjectProperties();
158   if (inobject_properties == 0) return 0;
159 
160   DCHECK_LE(num_descriptors, descriptors.number_of_descriptors());
161 
162   int layout_descriptor_length;
163   const int kMaxWordsPerField = kDoubleSize / kTaggedSize;
164 
165   if (num_descriptors <= kBitsInSmiLayout / kMaxWordsPerField) {
166     // Even in the "worst" case (all fields are doubles) it would fit into
167     // a Smi, so no need to calculate length.
168     layout_descriptor_length = kBitsInSmiLayout;
169 
170   } else {
171     layout_descriptor_length = 0;
172 
173     for (InternalIndex i : InternalIndex::Range(num_descriptors)) {
174       PropertyDetails details = descriptors.GetDetails(i);
175       if (!InobjectUnboxedField(inobject_properties, details)) continue;
176       int field_index = details.field_index();
177       int field_width_in_words = details.field_width_in_words();
178       layout_descriptor_length = std::max(layout_descriptor_length,
179                                           field_index + field_width_in_words);
180     }
181   }
182   layout_descriptor_length =
183       std::min(layout_descriptor_length, inobject_properties);
184   return layout_descriptor_length;
185 }
186 
Initialize(LayoutDescriptor layout_descriptor,Map map,DescriptorArray descriptors,int num_descriptors)187 LayoutDescriptor LayoutDescriptor::Initialize(
188     LayoutDescriptor layout_descriptor, Map map, DescriptorArray descriptors,
189     int num_descriptors) {
190   DisallowHeapAllocation no_allocation;
191   int inobject_properties = map.GetInObjectProperties();
192 
193   for (InternalIndex i : InternalIndex::Range(num_descriptors)) {
194     PropertyDetails details = descriptors.GetDetails(i);
195     if (!InobjectUnboxedField(inobject_properties, details)) {
196       DCHECK(details.location() != kField ||
197              layout_descriptor.IsTagged(details.field_index()));
198       continue;
199     }
200     int field_index = details.field_index();
201     layout_descriptor = layout_descriptor.SetRawData(field_index);
202     if (details.field_width_in_words() > 1) {
203       layout_descriptor = layout_descriptor.SetRawData(field_index + 1);
204     }
205   }
206   return layout_descriptor;
207 }
208 
number_of_layout_words()209 int LayoutDescriptor::number_of_layout_words() {
210   return length() / kUInt32Size;
211 }
212 
get_layout_word(int index)213 uint32_t LayoutDescriptor::get_layout_word(int index) const {
214   return get_uint32_relaxed(index);
215 }
216 
set_layout_word(int index,uint32_t value)217 void LayoutDescriptor::set_layout_word(int index, uint32_t value) {
218   set_uint32_relaxed(index, value);
219 }
220 
221 // LayoutDescriptorHelper is a helper class for querying whether inobject
222 // property at offset is Double or not.
LayoutDescriptorHelper(Map map)223 LayoutDescriptorHelper::LayoutDescriptorHelper(Map map)
224     : all_fields_tagged_(true),
225       header_size_(0),
226       layout_descriptor_(LayoutDescriptor::FastPointerLayout()) {
227   if (!FLAG_unbox_double_fields) return;
228 
229   layout_descriptor_ = map.layout_descriptor_gc_safe();
230   if (layout_descriptor_.IsFastPointerLayout()) {
231     return;
232   }
233 
234   header_size_ = map.GetInObjectPropertiesStartInWords() * kTaggedSize;
235   DCHECK_GE(header_size_, 0);
236 
237   all_fields_tagged_ = false;
238 }
239 
IsTagged(int offset_in_bytes)240 bool LayoutDescriptorHelper::IsTagged(int offset_in_bytes) {
241   DCHECK(IsAligned(offset_in_bytes, kTaggedSize));
242   if (all_fields_tagged_) return true;
243   // Object headers do not contain non-tagged fields.
244   if (offset_in_bytes < header_size_) return true;
245   int field_index = (offset_in_bytes - header_size_) / kTaggedSize;
246 
247   return layout_descriptor_.IsTagged(field_index);
248 }
249 
250 }  // namespace internal
251 }  // namespace v8
252 
253 #include "src/objects/object-macros-undef.h"
254 
255 #endif  // V8_OBJECTS_LAYOUT_DESCRIPTOR_INL_H_
256