1 // Copyright 2012 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_PROPERTY_DETAILS_H_
6 #define V8_PROPERTY_DETAILS_H_
7 
8 #include "include/v8.h"
9 #include "src/allocation.h"
10 #include "src/utils.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 // ES6 6.1.7.1
16 enum PropertyAttributes {
17   NONE = ::v8::None,
18   READ_ONLY = ::v8::ReadOnly,
19   DONT_ENUM = ::v8::DontEnum,
20   DONT_DELETE = ::v8::DontDelete,
21 
22   ALL_ATTRIBUTES_MASK = READ_ONLY | DONT_ENUM | DONT_DELETE,
23 
24   SEALED = DONT_DELETE,
25   FROZEN = SEALED | READ_ONLY,
26 
27   ABSENT = 64,  // Used in runtime to indicate a property is absent.
28   // 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.
31 
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
36 };
37 
38 
39 enum 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.
50 STATIC_ASSERT(ALL_PROPERTIES == static_cast<PropertyFilter>(NONE));
51 STATIC_ASSERT(ONLY_WRITABLE == static_cast<PropertyFilter>(READ_ONLY));
52 STATIC_ASSERT(ONLY_ENUMERABLE == static_cast<PropertyFilter>(DONT_ENUM));
53 STATIC_ASSERT(ONLY_CONFIGURABLE == static_cast<PropertyFilter>(DONT_DELETE));
54 STATIC_ASSERT(((SKIP_STRINGS | SKIP_SYMBOLS | ONLY_ALL_CAN_READ) &
55                ALL_ATTRIBUTES_MASK) == 0);
56 
57 
58 class Smi;
59 template<class> class TypeImpl;
60 struct ZoneTypeConfig;
61 typedef TypeImpl<ZoneTypeConfig> Type;
62 class TypeInfo;
63 
64 // Type of properties.
65 // Order of kinds is significant.
66 // Must fit in the BitField PropertyDetails::KindField.
67 enum PropertyKind { kData = 0, kAccessor = 1 };
68 
69 
70 // Order of modes is significant.
71 // Must fit in the BitField PropertyDetails::StoreModeField.
72 enum PropertyLocation { kField = 0, kDescriptor = 1 };
73 
74 
75 // Order of properties is significant.
76 // Must fit in the BitField PropertyDetails::TypeField.
77 // A copy of this is in debug/mirrors.js.
78 enum PropertyType {
79   DATA = (kField << 1) | kData,
80   DATA_CONSTANT = (kDescriptor << 1) | kData,
81   ACCESSOR = (kField << 1) | kAccessor,
82   ACCESSOR_CONSTANT = (kDescriptor << 1) | kAccessor
83 };
84 
85 
86 class Representation {
87  public:
88   enum Kind {
89     kNone,
90     kInteger8,
91     kUInteger8,
92     kInteger16,
93     kUInteger16,
94     kSmi,
95     kInteger32,
96     kDouble,
97     kHeapObject,
98     kTagged,
99     kExternal,
100     kNumRepresentations
101   };
102 
Representation()103   Representation() : kind_(kNone) { }
104 
None()105   static Representation None() { return Representation(kNone); }
Tagged()106   static Representation Tagged() { return Representation(kTagged); }
Integer8()107   static Representation Integer8() { return Representation(kInteger8); }
UInteger8()108   static Representation UInteger8() { return Representation(kUInteger8); }
Integer16()109   static Representation Integer16() { return Representation(kInteger16); }
UInteger16()110   static Representation UInteger16() { return Representation(kUInteger16); }
Smi()111   static Representation Smi() { return Representation(kSmi); }
Integer32()112   static Representation Integer32() { return Representation(kInteger32); }
Double()113   static Representation Double() { return Representation(kDouble); }
HeapObject()114   static Representation HeapObject() { return Representation(kHeapObject); }
External()115   static Representation External() { return Representation(kExternal); }
116 
FromKind(Kind kind)117   static Representation FromKind(Kind kind) { return Representation(kind); }
118 
Equals(const Representation & other)119   bool Equals(const Representation& other) const {
120     return kind_ == other.kind_;
121   }
122 
IsCompatibleForLoad(const Representation & other)123   bool IsCompatibleForLoad(const Representation& other) const {
124     return (IsDouble() && other.IsDouble()) ||
125         (!IsDouble() && !other.IsDouble());
126   }
127 
IsCompatibleForStore(const Representation & other)128   bool IsCompatibleForStore(const Representation& other) const {
129     return Equals(other);
130   }
131 
is_more_general_than(const Representation & other)132   bool is_more_general_than(const Representation& other) const {
133     if (kind_ == kExternal && other.kind_ == kNone) return true;
134     if (kind_ == kExternal && other.kind_ == kExternal) return false;
135     if (kind_ == kNone && other.kind_ == kExternal) return false;
136 
137     DCHECK(kind_ != kExternal);
138     DCHECK(other.kind_ != kExternal);
139     if (IsHeapObject()) return other.IsNone();
140     if (kind_ == kUInteger8 && other.kind_ == kInteger8) return false;
141     if (kind_ == kUInteger16 && other.kind_ == kInteger16) return false;
142     return kind_ > other.kind_;
143   }
144 
fits_into(const Representation & other)145   bool fits_into(const Representation& other) const {
146     return other.is_more_general_than(*this) || other.Equals(*this);
147   }
148 
generalize(Representation other)149   Representation generalize(Representation other) {
150     if (other.fits_into(*this)) return *this;
151     if (other.is_more_general_than(*this)) return other;
152     return Representation::Tagged();
153   }
154 
size()155   int size() const {
156     DCHECK(!IsNone());
157     if (IsInteger8() || IsUInteger8()) {
158       return sizeof(uint8_t);
159     }
160     if (IsInteger16() || IsUInteger16()) {
161       return sizeof(uint16_t);
162     }
163     if (IsInteger32()) {
164       return sizeof(uint32_t);
165     }
166     return kPointerSize;
167   }
168 
kind()169   Kind kind() const { return static_cast<Kind>(kind_); }
IsNone()170   bool IsNone() const { return kind_ == kNone; }
IsInteger8()171   bool IsInteger8() const { return kind_ == kInteger8; }
IsUInteger8()172   bool IsUInteger8() const { return kind_ == kUInteger8; }
IsInteger16()173   bool IsInteger16() const { return kind_ == kInteger16; }
IsUInteger16()174   bool IsUInteger16() const { return kind_ == kUInteger16; }
IsTagged()175   bool IsTagged() const { return kind_ == kTagged; }
IsSmi()176   bool IsSmi() const { return kind_ == kSmi; }
IsSmiOrTagged()177   bool IsSmiOrTagged() const { return IsSmi() || IsTagged(); }
IsInteger32()178   bool IsInteger32() const { return kind_ == kInteger32; }
IsSmiOrInteger32()179   bool IsSmiOrInteger32() const { return IsSmi() || IsInteger32(); }
IsDouble()180   bool IsDouble() const { return kind_ == kDouble; }
IsHeapObject()181   bool IsHeapObject() const { return kind_ == kHeapObject; }
IsExternal()182   bool IsExternal() const { return kind_ == kExternal; }
IsSpecialization()183   bool IsSpecialization() const {
184     return IsInteger8() || IsUInteger8() ||
185       IsInteger16() || IsUInteger16() ||
186       IsSmi() || IsInteger32() || IsDouble();
187   }
188   const char* Mnemonic() const;
189 
190  private:
Representation(Kind k)191   explicit Representation(Kind k) : kind_(k) { }
192 
193   // Make sure kind fits in int8.
194   STATIC_ASSERT(kNumRepresentations <= (1 << kBitsPerByte));
195 
196   int8_t kind_;
197 };
198 
199 
200 static const int kDescriptorIndexBitCount = 10;
201 // The maximum number of descriptors we want in a descriptor array (should
202 // fit in a page).
203 static const int kMaxNumberOfDescriptors =
204     (1 << kDescriptorIndexBitCount) - 2;
205 static const int kInvalidEnumCacheSentinel =
206     (1 << kDescriptorIndexBitCount) - 1;
207 
208 
209 enum class PropertyCellType {
210   // Meaningful when a property cell does not contain the hole.
211   kUndefined,     // The PREMONOMORPHIC of property cells.
212   kConstant,      // Cell has been assigned only once.
213   kConstantType,  // Cell has been assigned only one type.
214   kMutable,       // Cell will no longer be tracked as constant.
215 
216   // Meaningful when a property cell contains the hole.
217   kUninitialized = kUndefined,  // Cell has never been initialized.
218   kInvalidated = kConstant,     // Cell has been deleted or invalidated.
219 
220   // For dictionaries not holding cells.
221   kNoCell = kMutable,
222 };
223 
224 
225 enum class PropertyCellConstantType {
226   kSmi,
227   kStableMap,
228 };
229 
230 
231 // PropertyDetails captures type and attributes for a property.
232 // They are used both in property dictionaries and instance descriptors.
233 class PropertyDetails BASE_EMBEDDED {
234  public:
PropertyDetails(PropertyAttributes attributes,PropertyType type,int index,PropertyCellType cell_type)235   PropertyDetails(PropertyAttributes attributes, PropertyType type, int index,
236                   PropertyCellType cell_type) {
237     value_ = TypeField::encode(type) | AttributesField::encode(attributes) |
238              DictionaryStorageField::encode(index) |
239              PropertyCellTypeField::encode(cell_type);
240 
241     DCHECK(type == this->type());
242     DCHECK(attributes == this->attributes());
243   }
244 
245   PropertyDetails(PropertyAttributes attributes,
246                   PropertyType type,
247                   Representation representation,
248                   int field_index = 0) {
249     value_ = TypeField::encode(type)
250         | AttributesField::encode(attributes)
251         | RepresentationField::encode(EncodeRepresentation(representation))
252         | FieldIndexField::encode(field_index);
253   }
254 
255   PropertyDetails(PropertyAttributes attributes, PropertyKind kind,
256                   PropertyLocation location, Representation representation,
257                   int field_index = 0) {
258     value_ = KindField::encode(kind) | LocationField::encode(location) |
259              AttributesField::encode(attributes) |
260              RepresentationField::encode(EncodeRepresentation(representation)) |
261              FieldIndexField::encode(field_index);
262   }
263 
Empty()264   static PropertyDetails Empty() {
265     return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
266   }
267 
pointer()268   int pointer() const { return DescriptorPointer::decode(value_); }
269 
set_pointer(int i)270   PropertyDetails set_pointer(int i) const {
271     return PropertyDetails(value_, i);
272   }
273 
set_cell_type(PropertyCellType type)274   PropertyDetails set_cell_type(PropertyCellType type) const {
275     PropertyDetails details = *this;
276     details.value_ = PropertyCellTypeField::update(details.value_, type);
277     return details;
278   }
279 
set_index(int index)280   PropertyDetails set_index(int index) const {
281     PropertyDetails details = *this;
282     details.value_ = DictionaryStorageField::update(details.value_, index);
283     return details;
284   }
285 
CopyWithRepresentation(Representation representation)286   PropertyDetails CopyWithRepresentation(Representation representation) const {
287     return PropertyDetails(value_, representation);
288   }
CopyAddAttributes(PropertyAttributes new_attributes)289   PropertyDetails CopyAddAttributes(PropertyAttributes new_attributes) const {
290     new_attributes =
291         static_cast<PropertyAttributes>(attributes() | new_attributes);
292     return PropertyDetails(value_, new_attributes);
293   }
294 
295   // Conversion for storing details as Object*.
296   explicit inline PropertyDetails(Smi* smi);
297   inline Smi* AsSmi() const;
298 
EncodeRepresentation(Representation representation)299   static uint8_t EncodeRepresentation(Representation representation) {
300     return representation.kind();
301   }
302 
DecodeRepresentation(uint32_t bits)303   static Representation DecodeRepresentation(uint32_t bits) {
304     return Representation::FromKind(static_cast<Representation::Kind>(bits));
305   }
306 
kind()307   PropertyKind kind() const { return KindField::decode(value_); }
location()308   PropertyLocation location() const { return LocationField::decode(value_); }
309 
type()310   PropertyType type() const { return TypeField::decode(value_); }
311 
attributes()312   PropertyAttributes attributes() const {
313     return AttributesField::decode(value_);
314   }
315 
dictionary_index()316   int dictionary_index() const {
317     return DictionaryStorageField::decode(value_);
318   }
319 
representation()320   Representation representation() const {
321     return DecodeRepresentation(RepresentationField::decode(value_));
322   }
323 
field_index()324   int field_index() const { return FieldIndexField::decode(value_); }
325 
326   inline int field_width_in_words() const;
327 
IsValidIndex(int index)328   static bool IsValidIndex(int index) {
329     return DictionaryStorageField::is_valid(index);
330   }
331 
IsReadOnly()332   bool IsReadOnly() const { return (attributes() & READ_ONLY) != 0; }
IsConfigurable()333   bool IsConfigurable() const { return (attributes() & DONT_DELETE) == 0; }
IsDontEnum()334   bool IsDontEnum() const { return (attributes() & DONT_ENUM) != 0; }
cell_type()335   PropertyCellType cell_type() const {
336     return PropertyCellTypeField::decode(value_);
337   }
338 
339   // Bit fields in value_ (type, shift, size). Must be public so the
340   // constants can be embedded in generated code.
341   class KindField : public BitField<PropertyKind, 0, 1> {};
342   class LocationField : public BitField<PropertyLocation, 1, 1> {};
343   class AttributesField : public BitField<PropertyAttributes, 2, 3> {};
344   static const int kAttributesReadOnlyMask =
345       (READ_ONLY << AttributesField::kShift);
346 
347   // Bit fields for normalized objects.
348   class PropertyCellTypeField : public BitField<PropertyCellType, 5, 2> {};
349   class DictionaryStorageField : public BitField<uint32_t, 7, 24> {};
350 
351   // Bit fields for fast objects.
352   class RepresentationField : public BitField<uint32_t, 5, 4> {};
353   class DescriptorPointer
354       : public BitField<uint32_t, 9, kDescriptorIndexBitCount> {};  // NOLINT
355   class FieldIndexField
356       : public BitField<uint32_t, 9 + kDescriptorIndexBitCount,
357                         kDescriptorIndexBitCount> {};  // NOLINT
358 
359   // NOTE: TypeField overlaps with KindField and LocationField.
360   class TypeField : public BitField<PropertyType, 0, 2> {};
361   STATIC_ASSERT(KindField::kNext == LocationField::kShift);
362   STATIC_ASSERT(TypeField::kShift == KindField::kShift);
363   STATIC_ASSERT(TypeField::kNext == LocationField::kNext);
364 
365   // All bits for both fast and slow objects must fit in a smi.
366   STATIC_ASSERT(DictionaryStorageField::kNext <= 31);
367   STATIC_ASSERT(FieldIndexField::kNext <= 31);
368 
369   static const int kInitialIndex = 1;
370 
371 #ifdef OBJECT_PRINT
372   // For our gdb macros, we should perhaps change these in the future.
373   void Print(bool dictionary_mode);
374 #endif
375 
376  private:
PropertyDetails(int value,int pointer)377   PropertyDetails(int value, int pointer) {
378     value_ = DescriptorPointer::update(value, pointer);
379   }
PropertyDetails(int value,Representation representation)380   PropertyDetails(int value, Representation representation) {
381     value_ = RepresentationField::update(
382         value, EncodeRepresentation(representation));
383   }
PropertyDetails(int value,PropertyAttributes attributes)384   PropertyDetails(int value, PropertyAttributes attributes) {
385     value_ = AttributesField::update(value, attributes);
386   }
387 
388   uint32_t value_;
389 };
390 
391 
392 std::ostream& operator<<(std::ostream& os,
393                          const PropertyAttributes& attributes);
394 std::ostream& operator<<(std::ostream& os, const PropertyDetails& details);
395 }  // namespace internal
396 }  // namespace v8
397 
398 #endif  // V8_PROPERTY_DETAILS_H_
399