blob: fdf2c6c4ab5fc0c6cec0d00921583451c5c7848a [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004
5#ifndef V8_PROPERTY_DETAILS_H_
6#define V8_PROPERTY_DETAILS_H_
7
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008#include "include/v8.h"
9#include "src/allocation.h"
10#include "src/utils.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012namespace v8 {
13namespace internal {
14
15// ES6 6.1.7.1
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016enum PropertyAttributes {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017 NONE = ::v8::None,
18 READ_ONLY = ::v8::ReadOnly,
19 DONT_ENUM = ::v8::DontEnum,
20 DONT_DELETE = ::v8::DontDelete,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022 ALL_ATTRIBUTES_MASK = READ_ONLY | DONT_ENUM | DONT_DELETE,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000024 SEALED = DONT_DELETE,
25 FROZEN = SEALED | READ_ONLY,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000026
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000027 ABSENT = 64, // Used in runtime to indicate a property is absent.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010028 // ABSENT can never be stored in or returned from a descriptor's attributes
29 // bitfield. It is only used as a return value meaning the attributes of
30 // a non-existent property.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031
32 // When creating a property, EVAL_DECLARED used to indicate that the property
33 // came from a sloppy-mode direct eval, and certain checks need to be done.
34 // Cannot be stored in or returned from a descriptor's attributes bitfield.
35 EVAL_DECLARED = 128
Ben Murdoch3ef787d2012-04-12 10:51:47 +010036};
37
38
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000039enum PropertyFilter {
40 ALL_PROPERTIES = 0,
41 ONLY_WRITABLE = 1,
42 ONLY_ENUMERABLE = 2,
43 ONLY_CONFIGURABLE = 4,
44 SKIP_STRINGS = 8,
45 SKIP_SYMBOLS = 16,
46 ONLY_ALL_CAN_READ = 32,
47 ENUMERABLE_STRINGS = ONLY_ENUMERABLE | SKIP_SYMBOLS,
48};
49// Enable fast comparisons of PropertyAttributes against PropertyFilters.
50STATIC_ASSERT(ALL_PROPERTIES == static_cast<PropertyFilter>(NONE));
51STATIC_ASSERT(ONLY_WRITABLE == static_cast<PropertyFilter>(READ_ONLY));
52STATIC_ASSERT(ONLY_ENUMERABLE == static_cast<PropertyFilter>(DONT_ENUM));
53STATIC_ASSERT(ONLY_CONFIGURABLE == static_cast<PropertyFilter>(DONT_DELETE));
54STATIC_ASSERT(((SKIP_STRINGS | SKIP_SYMBOLS | ONLY_ALL_CAN_READ) &
55 ALL_ATTRIBUTES_MASK) == 0);
56
Ben Murdoch3ef787d2012-04-12 10:51:47 +010057
58class Smi;
Ben Murdoch097c5b22016-05-18 11:27:45 +010059class Type;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000060class TypeInfo;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010061
62// Type of properties.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040063// Order of kinds is significant.
64// Must fit in the BitField PropertyDetails::KindField.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065enum PropertyKind { kData = 0, kAccessor = 1 };
Emily Bernierd0a1eb72015-03-24 16:35:39 -040066
67
68// Order of modes is significant.
69// Must fit in the BitField PropertyDetails::StoreModeField.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000070enum PropertyLocation { kField = 0, kDescriptor = 1 };
Emily Bernierd0a1eb72015-03-24 16:35:39 -040071
72
Ben Murdoch3ef787d2012-04-12 10:51:47 +010073// Order of properties is significant.
74// Must fit in the BitField PropertyDetails::TypeField.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000075// A copy of this is in debug/mirrors.js.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010076enum PropertyType {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000077 DATA = (kField << 1) | kData,
78 DATA_CONSTANT = (kDescriptor << 1) | kData,
79 ACCESSOR = (kField << 1) | kAccessor,
80 ACCESSOR_CONSTANT = (kDescriptor << 1) | kAccessor
Ben Murdoch3ef787d2012-04-12 10:51:47 +010081};
82
83
Ben Murdochb8a8cc12014-11-26 15:28:44 +000084class Representation {
85 public:
86 enum Kind {
87 kNone,
88 kInteger8,
89 kUInteger8,
90 kInteger16,
91 kUInteger16,
92 kSmi,
93 kInteger32,
94 kDouble,
95 kHeapObject,
96 kTagged,
97 kExternal,
98 kNumRepresentations
99 };
100
101 Representation() : kind_(kNone) { }
102
103 static Representation None() { return Representation(kNone); }
104 static Representation Tagged() { return Representation(kTagged); }
105 static Representation Integer8() { return Representation(kInteger8); }
106 static Representation UInteger8() { return Representation(kUInteger8); }
107 static Representation Integer16() { return Representation(kInteger16); }
108 static Representation UInteger16() { return Representation(kUInteger16); }
109 static Representation Smi() { return Representation(kSmi); }
110 static Representation Integer32() { return Representation(kInteger32); }
111 static Representation Double() { return Representation(kDouble); }
112 static Representation HeapObject() { return Representation(kHeapObject); }
113 static Representation External() { return Representation(kExternal); }
114
115 static Representation FromKind(Kind kind) { return Representation(kind); }
116
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000117 bool Equals(const Representation& other) const {
118 return kind_ == other.kind_;
119 }
120
121 bool IsCompatibleForLoad(const Representation& other) const {
122 return (IsDouble() && other.IsDouble()) ||
123 (!IsDouble() && !other.IsDouble());
124 }
125
126 bool IsCompatibleForStore(const Representation& other) const {
127 return Equals(other);
128 }
129
130 bool is_more_general_than(const Representation& other) const {
131 if (kind_ == kExternal && other.kind_ == kNone) return true;
132 if (kind_ == kExternal && other.kind_ == kExternal) return false;
133 if (kind_ == kNone && other.kind_ == kExternal) return false;
134
135 DCHECK(kind_ != kExternal);
136 DCHECK(other.kind_ != kExternal);
137 if (IsHeapObject()) return other.IsNone();
138 if (kind_ == kUInteger8 && other.kind_ == kInteger8) return false;
139 if (kind_ == kUInteger16 && other.kind_ == kInteger16) return false;
140 return kind_ > other.kind_;
141 }
142
143 bool fits_into(const Representation& other) const {
144 return other.is_more_general_than(*this) || other.Equals(*this);
145 }
146
147 Representation generalize(Representation other) {
148 if (other.fits_into(*this)) return *this;
149 if (other.is_more_general_than(*this)) return other;
150 return Representation::Tagged();
151 }
152
153 int size() const {
154 DCHECK(!IsNone());
155 if (IsInteger8() || IsUInteger8()) {
156 return sizeof(uint8_t);
157 }
158 if (IsInteger16() || IsUInteger16()) {
159 return sizeof(uint16_t);
160 }
161 if (IsInteger32()) {
162 return sizeof(uint32_t);
163 }
164 return kPointerSize;
165 }
166
167 Kind kind() const { return static_cast<Kind>(kind_); }
168 bool IsNone() const { return kind_ == kNone; }
169 bool IsInteger8() const { return kind_ == kInteger8; }
170 bool IsUInteger8() const { return kind_ == kUInteger8; }
171 bool IsInteger16() const { return kind_ == kInteger16; }
172 bool IsUInteger16() const { return kind_ == kUInteger16; }
173 bool IsTagged() const { return kind_ == kTagged; }
174 bool IsSmi() const { return kind_ == kSmi; }
175 bool IsSmiOrTagged() const { return IsSmi() || IsTagged(); }
176 bool IsInteger32() const { return kind_ == kInteger32; }
177 bool IsSmiOrInteger32() const { return IsSmi() || IsInteger32(); }
178 bool IsDouble() const { return kind_ == kDouble; }
179 bool IsHeapObject() const { return kind_ == kHeapObject; }
180 bool IsExternal() const { return kind_ == kExternal; }
181 bool IsSpecialization() const {
182 return IsInteger8() || IsUInteger8() ||
183 IsInteger16() || IsUInteger16() ||
184 IsSmi() || IsInteger32() || IsDouble();
185 }
186 const char* Mnemonic() const;
187
188 private:
189 explicit Representation(Kind k) : kind_(k) { }
190
191 // Make sure kind fits in int8.
192 STATIC_ASSERT(kNumRepresentations <= (1 << kBitsPerByte));
193
194 int8_t kind_;
195};
196
197
198static const int kDescriptorIndexBitCount = 10;
199// The maximum number of descriptors we want in a descriptor array (should
200// fit in a page).
201static const int kMaxNumberOfDescriptors =
202 (1 << kDescriptorIndexBitCount) - 2;
203static const int kInvalidEnumCacheSentinel =
204 (1 << kDescriptorIndexBitCount) - 1;
205
206
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000207enum class PropertyCellType {
208 // Meaningful when a property cell does not contain the hole.
209 kUndefined, // The PREMONOMORPHIC of property cells.
210 kConstant, // Cell has been assigned only once.
211 kConstantType, // Cell has been assigned only one type.
212 kMutable, // Cell will no longer be tracked as constant.
213
214 // Meaningful when a property cell contains the hole.
215 kUninitialized = kUndefined, // Cell has never been initialized.
216 kInvalidated = kConstant, // Cell has been deleted or invalidated.
217
218 // For dictionaries not holding cells.
219 kNoCell = kMutable,
220};
221
222
223enum class PropertyCellConstantType {
224 kSmi,
225 kStableMap,
226};
227
228
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100229// PropertyDetails captures type and attributes for a property.
230// They are used both in property dictionaries and instance descriptors.
231class PropertyDetails BASE_EMBEDDED {
232 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000233 PropertyDetails(PropertyAttributes attributes, PropertyType type, int index,
234 PropertyCellType cell_type) {
235 value_ = TypeField::encode(type) | AttributesField::encode(attributes) |
236 DictionaryStorageField::encode(index) |
237 PropertyCellTypeField::encode(cell_type);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100238
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000239 DCHECK(type == this->type());
240 DCHECK(attributes == this->attributes());
241 }
242
243 PropertyDetails(PropertyAttributes attributes,
244 PropertyType type,
245 Representation representation,
246 int field_index = 0) {
247 value_ = TypeField::encode(type)
248 | AttributesField::encode(attributes)
249 | RepresentationField::encode(EncodeRepresentation(representation))
250 | FieldIndexField::encode(field_index);
251 }
252
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000253 PropertyDetails(PropertyAttributes attributes, PropertyKind kind,
254 PropertyLocation location, Representation representation,
255 int field_index = 0) {
256 value_ = KindField::encode(kind) | LocationField::encode(location) |
257 AttributesField::encode(attributes) |
258 RepresentationField::encode(EncodeRepresentation(representation)) |
259 FieldIndexField::encode(field_index);
260 }
261
262 static PropertyDetails Empty() {
263 return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
264 }
265
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000266 int pointer() const { return DescriptorPointer::decode(value_); }
267
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000268 PropertyDetails set_pointer(int i) const {
269 return PropertyDetails(value_, i);
270 }
271
272 PropertyDetails set_cell_type(PropertyCellType type) const {
273 PropertyDetails details = *this;
274 details.value_ = PropertyCellTypeField::update(details.value_, type);
275 return details;
276 }
277
278 PropertyDetails set_index(int index) const {
279 PropertyDetails details = *this;
280 details.value_ = DictionaryStorageField::update(details.value_, index);
281 return details;
282 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000283
284 PropertyDetails CopyWithRepresentation(Representation representation) const {
285 return PropertyDetails(value_, representation);
286 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287 PropertyDetails CopyAddAttributes(PropertyAttributes new_attributes) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000288 new_attributes =
289 static_cast<PropertyAttributes>(attributes() | new_attributes);
290 return PropertyDetails(value_, new_attributes);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100291 }
292
293 // Conversion for storing details as Object*.
294 explicit inline PropertyDetails(Smi* smi);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 inline Smi* AsSmi() const;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100296
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297 static uint8_t EncodeRepresentation(Representation representation) {
298 return representation.kind();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100299 }
300
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000301 static Representation DecodeRepresentation(uint32_t bits) {
302 return Representation::FromKind(static_cast<Representation::Kind>(bits));
303 }
304
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400305 PropertyKind kind() const { return KindField::decode(value_); }
306 PropertyLocation location() const { return LocationField::decode(value_); }
307
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000308 PropertyType type() const { return TypeField::decode(value_); }
309
310 PropertyAttributes attributes() const {
311 return AttributesField::decode(value_);
312 }
313
314 int dictionary_index() const {
315 return DictionaryStorageField::decode(value_);
316 }
317
318 Representation representation() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000319 return DecodeRepresentation(RepresentationField::decode(value_));
320 }
321
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400322 int field_index() const { return FieldIndexField::decode(value_); }
323
324 inline int field_width_in_words() const;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000325
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000326 static bool IsValidIndex(int index) {
327 return DictionaryStorageField::is_valid(index);
328 }
329
330 bool IsReadOnly() const { return (attributes() & READ_ONLY) != 0; }
331 bool IsConfigurable() const { return (attributes() & DONT_DELETE) == 0; }
332 bool IsDontEnum() const { return (attributes() & DONT_ENUM) != 0; }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100333 bool IsEnumerable() const { return !IsDontEnum(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000334 PropertyCellType cell_type() const {
335 return PropertyCellTypeField::decode(value_);
336 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100337
338 // Bit fields in value_ (type, shift, size). Must be public so the
339 // constants can be embedded in generated code.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400340 class KindField : public BitField<PropertyKind, 0, 1> {};
341 class LocationField : public BitField<PropertyLocation, 1, 1> {};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000342 class AttributesField : public BitField<PropertyAttributes, 2, 3> {};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343 static const int kAttributesReadOnlyMask =
344 (READ_ONLY << AttributesField::kShift);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000345
346 // Bit fields for normalized objects.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000347 class PropertyCellTypeField : public BitField<PropertyCellType, 5, 2> {};
348 class DictionaryStorageField : public BitField<uint32_t, 7, 24> {};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000349
350 // Bit fields for fast objects.
351 class RepresentationField : public BitField<uint32_t, 5, 4> {};
352 class DescriptorPointer
353 : public BitField<uint32_t, 9, kDescriptorIndexBitCount> {}; // NOLINT
354 class FieldIndexField
355 : public BitField<uint32_t, 9 + kDescriptorIndexBitCount,
356 kDescriptorIndexBitCount> {}; // NOLINT
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400357
358 // NOTE: TypeField overlaps with KindField and LocationField.
359 class TypeField : public BitField<PropertyType, 0, 2> {};
360 STATIC_ASSERT(KindField::kNext == LocationField::kShift);
361 STATIC_ASSERT(TypeField::kShift == KindField::kShift);
362 STATIC_ASSERT(TypeField::kNext == LocationField::kNext);
363
364 // All bits for both fast and slow objects must fit in a smi.
365 STATIC_ASSERT(DictionaryStorageField::kNext <= 31);
366 STATIC_ASSERT(FieldIndexField::kNext <= 31);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100367
368 static const int kInitialIndex = 1;
369
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400370#ifdef OBJECT_PRINT
371 // For our gdb macros, we should perhaps change these in the future.
372 void Print(bool dictionary_mode);
373#endif
374
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100375 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000376 PropertyDetails(int value, int pointer) {
377 value_ = DescriptorPointer::update(value, pointer);
378 }
379 PropertyDetails(int value, Representation representation) {
380 value_ = RepresentationField::update(
381 value, EncodeRepresentation(representation));
382 }
383 PropertyDetails(int value, PropertyAttributes attributes) {
384 value_ = AttributesField::update(value, attributes);
385 }
386
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100387 uint32_t value_;
388};
389
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400390
391std::ostream& operator<<(std::ostream& os,
392 const PropertyAttributes& attributes);
393std::ostream& operator<<(std::ostream& os, const PropertyDetails& details);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000394} // namespace internal
395} // namespace v8
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100396
397#endif // V8_PROPERTY_DETAILS_H_