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_LAYOUT_DESCRIPTOR_INL_H_
6#define V8_LAYOUT_DESCRIPTOR_INL_H_
7
8#include "src/layout-descriptor.h"
9
10#include "src/handles-inl.h"
11#include "src/objects-inl.h"
12#include "src/objects/descriptor-array-inl.h"
13#include "src/objects/smi.h"
14
15// Has to be the last include (doesn't have include guards):
16#include "src/objects/object-macros.h"
17
18namespace v8 {
19namespace internal {
20
21LayoutDescriptor::LayoutDescriptor(Address ptr)
22 : ByteArray(ptr, AllowInlineSmiStorage::kAllowBeingASmi) {
23 SLOW_DCHECK(IsLayoutDescriptor());
24}
25CAST_ACCESSOR(LayoutDescriptor)
26
27LayoutDescriptor LayoutDescriptor::FromSmi(Smi smi) {
28 return LayoutDescriptor::cast(smi);
29}
30
31Handle<LayoutDescriptor> LayoutDescriptor::New(Isolate* isolate, int length) {
32 if (length <= kBitsInSmiLayout) {
33 // The whole bit vector fits into a smi.
34 return handle(LayoutDescriptor::FromSmi(Smi::zero()), isolate);
35 }
36 int backing_store_length = GetSlowModeBackingStoreLength(length);
37 Handle<LayoutDescriptor> result =
38 Handle<LayoutDescriptor>::cast(isolate->factory()->NewByteArray(
39 backing_store_length, AllocationType::kOld));
40 memset(reinterpret_cast<void*>(result->GetDataStartAddress()), 0,
41 result->DataSize());
42 return result;
43}
44
45
46bool 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
55LayoutDescriptor LayoutDescriptor::FastPointerLayout() {
56 return LayoutDescriptor::FromSmi(Smi::zero());
57}
58
59bool 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
73LayoutDescriptor LayoutDescriptor::SetRawData(int field_index) {
74 return SetTagged(field_index, false);
75}
76
77LayoutDescriptor 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
104bool 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
125
126bool LayoutDescriptor::IsFastPointerLayout() {
127 return *this == FastPointerLayout();
128}
129
130bool LayoutDescriptor::IsFastPointerLayout(Object layout_descriptor) {
131 return layout_descriptor == FastPointerLayout();
132}
133
134bool LayoutDescriptor::IsSlowLayout() { return !IsSmi(); }
135
136
137int LayoutDescriptor::capacity() {
138 return IsSlowLayout() ? (length() * kBitsPerByte) : kBitsInSmiLayout;
139}
140
141LayoutDescriptor LayoutDescriptor::cast_gc_safe(Object object) {
142 // The map word of the object can be a forwarding pointer during
143 // object evacuation phase of GC. Since the layout descriptor methods
144 // for checking whether a field is tagged or not do not depend on the
145 // object map, it should be safe.
146 return LayoutDescriptor::unchecked_cast(object);
147}
148
149int LayoutDescriptor::GetSlowModeBackingStoreLength(int length) {
150 DCHECK_LT(0, length);
151 // We allocate kTaggedSize rounded blocks of memory anyway so we increase
152 // the length of allocated array to utilize that "lost" space which could
153 // also help to avoid layout descriptor reallocations.
154 return RoundUp(length, kBitsPerByte * kTaggedSize) / kBitsPerByte;
155}
156
157int LayoutDescriptor::CalculateCapacity(Map map, DescriptorArray descriptors,
158 int num_descriptors) {
159 int inobject_properties = map->GetInObjectProperties();
160 if (inobject_properties == 0) return 0;
161
162 DCHECK_LE(num_descriptors, descriptors->number_of_descriptors());
163
164 int layout_descriptor_length;
165 const int kMaxWordsPerField = kDoubleSize / kTaggedSize;
166
167 if (num_descriptors <= kBitsInSmiLayout / kMaxWordsPerField) {
168 // Even in the "worst" case (all fields are doubles) it would fit into
169 // a Smi, so no need to calculate length.
170 layout_descriptor_length = kBitsInSmiLayout;
171
172 } else {
173 layout_descriptor_length = 0;
174
175 for (int i = 0; i < num_descriptors; i++) {
176 PropertyDetails details = descriptors->GetDetails(i);
177 if (!InobjectUnboxedField(inobject_properties, details)) continue;
178 int field_index = details.field_index();
179 int field_width_in_words = details.field_width_in_words();
180 layout_descriptor_length =
181 Max(layout_descriptor_length, field_index + field_width_in_words);
182 }
183 }
184 layout_descriptor_length = Min(layout_descriptor_length, inobject_properties);
185 return layout_descriptor_length;
186}
187
188LayoutDescriptor LayoutDescriptor::Initialize(
189 LayoutDescriptor layout_descriptor, Map map, DescriptorArray descriptors,
190 int num_descriptors) {
191 DisallowHeapAllocation no_allocation;
192 int inobject_properties = map->GetInObjectProperties();
193
194 for (int i = 0; i < num_descriptors; i++) {
195 PropertyDetails details = descriptors->GetDetails(i);
196 if (!InobjectUnboxedField(inobject_properties, details)) {
197 DCHECK(details.location() != kField ||
198 layout_descriptor->IsTagged(details.field_index()));
199 continue;
200 }
201 int field_index = details.field_index();
202 layout_descriptor = layout_descriptor->SetRawData(field_index);
203 if (details.field_width_in_words() > 1) {
204 layout_descriptor = layout_descriptor->SetRawData(field_index + 1);
205 }
206 }
207 return layout_descriptor;
208}
209
210int LayoutDescriptor::number_of_layout_words() {
211 return length() / kUInt32Size;
212}
213
214uint32_t LayoutDescriptor::get_layout_word(int index) const {
215 return get_uint32(index);
216}
217
218void LayoutDescriptor::set_layout_word(int index, uint32_t value) {
219 set_uint32(index, value);
220}
221
222// LayoutDescriptorHelper is a helper class for querying whether inobject
223// property at offset is Double or not.
224LayoutDescriptorHelper::LayoutDescriptorHelper(Map map)
225 : all_fields_tagged_(true),
226 header_size_(0),
227 layout_descriptor_(LayoutDescriptor::FastPointerLayout()) {
228 if (!FLAG_unbox_double_fields) return;
229
230 layout_descriptor_ = map->layout_descriptor_gc_safe();
231 if (layout_descriptor_->IsFastPointerLayout()) {
232 return;
233 }
234
235 header_size_ = map->GetInObjectPropertiesStartInWords() * kTaggedSize;
236 DCHECK_GE(header_size_, 0);
237
238 all_fields_tagged_ = false;
239}
240
241
242bool LayoutDescriptorHelper::IsTagged(int offset_in_bytes) {
243 DCHECK(IsAligned(offset_in_bytes, kTaggedSize));
244 if (all_fields_tagged_) return true;
245 // Object headers do not contain non-tagged fields.
246 if (offset_in_bytes < header_size_) return true;
247 int field_index = (offset_in_bytes - header_size_) / kTaggedSize;
248
249 return layout_descriptor_->IsTagged(field_index);
250}
251
252} // namespace internal
253} // namespace v8
254
255#include "src/objects/object-macros-undef.h"
256
257#endif // V8_LAYOUT_DESCRIPTOR_INL_H_
258