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 // Ecma-262 3rd 8.6.1 13 enum PropertyAttributes { 14 NONE = v8::None, 15 READ_ONLY = v8::ReadOnly, 16 DONT_ENUM = v8::DontEnum, 17 DONT_DELETE = v8::DontDelete, 18 19 SEALED = DONT_DELETE, 20 FROZEN = SEALED | READ_ONLY, 21 22 STRING = 8, // Used to filter symbols and string names 23 SYMBOLIC = 16, 24 PRIVATE_SYMBOL = 32, 25 26 DONT_SHOW = DONT_ENUM | SYMBOLIC | PRIVATE_SYMBOL, 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 33 34 namespace v8 { 35 namespace internal { 36 37 class Smi; 38 template<class> class TypeImpl; 39 struct ZoneTypeConfig; 40 typedef TypeImpl<ZoneTypeConfig> Type; 41 class TypeInfo; 42 43 // Type of properties. 44 // Order of properties is significant. 45 // Must fit in the BitField PropertyDetails::TypeField. 46 // A copy of this is in mirror-debugger.js. 47 enum PropertyType { 48 // Only in slow mode. 49 NORMAL = 0, 50 // Only in fast mode. 51 FIELD = 1, 52 CONSTANT = 2, 53 CALLBACKS = 3 54 }; 55 56 57 class Representation { 58 public: 59 enum Kind { 60 kNone, 61 kInteger8, 62 kUInteger8, 63 kInteger16, 64 kUInteger16, 65 kSmi, 66 kInteger32, 67 kDouble, 68 kHeapObject, 69 kTagged, 70 kExternal, 71 kNumRepresentations 72 }; 73 74 Representation() : kind_(kNone) { } 75 76 static Representation None() { return Representation(kNone); } 77 static Representation Tagged() { return Representation(kTagged); } 78 static Representation Integer8() { return Representation(kInteger8); } 79 static Representation UInteger8() { return Representation(kUInteger8); } 80 static Representation Integer16() { return Representation(kInteger16); } 81 static Representation UInteger16() { return Representation(kUInteger16); } 82 static Representation Smi() { return Representation(kSmi); } 83 static Representation Integer32() { return Representation(kInteger32); } 84 static Representation Double() { return Representation(kDouble); } 85 static Representation HeapObject() { return Representation(kHeapObject); } 86 static Representation External() { return Representation(kExternal); } 87 88 static Representation FromKind(Kind kind) { return Representation(kind); } 89 90 static Representation FromType(Type* type); 91 92 bool Equals(const Representation& other) const { 93 return kind_ == other.kind_; 94 } 95 96 bool IsCompatibleForLoad(const Representation& other) const { 97 return (IsDouble() && other.IsDouble()) || 98 (!IsDouble() && !other.IsDouble()); 99 } 100 101 bool IsCompatibleForStore(const Representation& other) const { 102 return Equals(other); 103 } 104 105 bool is_more_general_than(const Representation& other) const { 106 if (kind_ == kExternal && other.kind_ == kNone) return true; 107 if (kind_ == kExternal && other.kind_ == kExternal) return false; 108 if (kind_ == kNone && other.kind_ == kExternal) return false; 109 110 DCHECK(kind_ != kExternal); 111 DCHECK(other.kind_ != kExternal); 112 if (IsHeapObject()) return other.IsNone(); 113 if (kind_ == kUInteger8 && other.kind_ == kInteger8) return false; 114 if (kind_ == kUInteger16 && other.kind_ == kInteger16) return false; 115 return kind_ > other.kind_; 116 } 117 118 bool fits_into(const Representation& other) const { 119 return other.is_more_general_than(*this) || other.Equals(*this); 120 } 121 122 Representation generalize(Representation other) { 123 if (other.fits_into(*this)) return *this; 124 if (other.is_more_general_than(*this)) return other; 125 return Representation::Tagged(); 126 } 127 128 int size() const { 129 DCHECK(!IsNone()); 130 if (IsInteger8() || IsUInteger8()) { 131 return sizeof(uint8_t); 132 } 133 if (IsInteger16() || IsUInteger16()) { 134 return sizeof(uint16_t); 135 } 136 if (IsInteger32()) { 137 return sizeof(uint32_t); 138 } 139 return kPointerSize; 140 } 141 142 Kind kind() const { return static_cast<Kind>(kind_); } 143 bool IsNone() const { return kind_ == kNone; } 144 bool IsInteger8() const { return kind_ == kInteger8; } 145 bool IsUInteger8() const { return kind_ == kUInteger8; } 146 bool IsInteger16() const { return kind_ == kInteger16; } 147 bool IsUInteger16() const { return kind_ == kUInteger16; } 148 bool IsTagged() const { return kind_ == kTagged; } 149 bool IsSmi() const { return kind_ == kSmi; } 150 bool IsSmiOrTagged() const { return IsSmi() || IsTagged(); } 151 bool IsInteger32() const { return kind_ == kInteger32; } 152 bool IsSmiOrInteger32() const { return IsSmi() || IsInteger32(); } 153 bool IsDouble() const { return kind_ == kDouble; } 154 bool IsHeapObject() const { return kind_ == kHeapObject; } 155 bool IsExternal() const { return kind_ == kExternal; } 156 bool IsSpecialization() const { 157 return IsInteger8() || IsUInteger8() || 158 IsInteger16() || IsUInteger16() || 159 IsSmi() || IsInteger32() || IsDouble(); 160 } 161 const char* Mnemonic() const; 162 163 private: 164 explicit Representation(Kind k) : kind_(k) { } 165 166 // Make sure kind fits in int8. 167 STATIC_ASSERT(kNumRepresentations <= (1 << kBitsPerByte)); 168 169 int8_t kind_; 170 }; 171 172 173 static const int kDescriptorIndexBitCount = 10; 174 // The maximum number of descriptors we want in a descriptor array (should 175 // fit in a page). 176 static const int kMaxNumberOfDescriptors = 177 (1 << kDescriptorIndexBitCount) - 2; 178 static const int kInvalidEnumCacheSentinel = 179 (1 << kDescriptorIndexBitCount) - 1; 180 181 182 // PropertyDetails captures type and attributes for a property. 183 // They are used both in property dictionaries and instance descriptors. 184 class PropertyDetails BASE_EMBEDDED { 185 public: 186 PropertyDetails(PropertyAttributes attributes, 187 PropertyType type, 188 int index) { 189 value_ = TypeField::encode(type) 190 | AttributesField::encode(attributes) 191 | DictionaryStorageField::encode(index); 192 193 DCHECK(type == this->type()); 194 DCHECK(attributes == this->attributes()); 195 } 196 197 PropertyDetails(PropertyAttributes attributes, 198 PropertyType type, 199 Representation representation, 200 int field_index = 0) { 201 value_ = TypeField::encode(type) 202 | AttributesField::encode(attributes) 203 | RepresentationField::encode(EncodeRepresentation(representation)) 204 | FieldIndexField::encode(field_index); 205 } 206 207 int pointer() const { return DescriptorPointer::decode(value_); } 208 209 PropertyDetails set_pointer(int i) { return PropertyDetails(value_, i); } 210 211 PropertyDetails CopyWithRepresentation(Representation representation) const { 212 return PropertyDetails(value_, representation); 213 } 214 PropertyDetails CopyAddAttributes(PropertyAttributes new_attributes) { 215 new_attributes = 216 static_cast<PropertyAttributes>(attributes() | new_attributes); 217 return PropertyDetails(value_, new_attributes); 218 } 219 220 // Conversion for storing details as Object*. 221 explicit inline PropertyDetails(Smi* smi); 222 inline Smi* AsSmi() const; 223 224 static uint8_t EncodeRepresentation(Representation representation) { 225 return representation.kind(); 226 } 227 228 static Representation DecodeRepresentation(uint32_t bits) { 229 return Representation::FromKind(static_cast<Representation::Kind>(bits)); 230 } 231 232 PropertyType type() const { return TypeField::decode(value_); } 233 234 PropertyAttributes attributes() const { 235 return AttributesField::decode(value_); 236 } 237 238 int dictionary_index() const { 239 return DictionaryStorageField::decode(value_); 240 } 241 242 Representation representation() const { 243 DCHECK(type() != NORMAL); 244 return DecodeRepresentation(RepresentationField::decode(value_)); 245 } 246 247 int field_index() const { 248 return FieldIndexField::decode(value_); 249 } 250 251 inline PropertyDetails AsDeleted() const; 252 253 static bool IsValidIndex(int index) { 254 return DictionaryStorageField::is_valid(index); 255 } 256 257 bool IsReadOnly() const { return (attributes() & READ_ONLY) != 0; } 258 bool IsConfigurable() const { return (attributes() & DONT_DELETE) == 0; } 259 bool IsDontEnum() const { return (attributes() & DONT_ENUM) != 0; } 260 bool IsDeleted() const { return DeletedField::decode(value_) != 0;} 261 262 // Bit fields in value_ (type, shift, size). Must be public so the 263 // constants can be embedded in generated code. 264 class TypeField : public BitField<PropertyType, 0, 2> {}; 265 class AttributesField : public BitField<PropertyAttributes, 2, 3> {}; 266 267 // Bit fields for normalized objects. 268 class DeletedField : public BitField<uint32_t, 5, 1> {}; 269 class DictionaryStorageField : public BitField<uint32_t, 6, 24> {}; 270 271 // Bit fields for fast objects. 272 class RepresentationField : public BitField<uint32_t, 5, 4> {}; 273 class DescriptorPointer 274 : public BitField<uint32_t, 9, kDescriptorIndexBitCount> {}; // NOLINT 275 class FieldIndexField 276 : public BitField<uint32_t, 9 + kDescriptorIndexBitCount, 277 kDescriptorIndexBitCount> {}; // NOLINT 278 // All bits for fast objects must fix in a smi. 279 STATIC_ASSERT(9 + kDescriptorIndexBitCount + kDescriptorIndexBitCount <= 31); 280 281 static const int kInitialIndex = 1; 282 283 private: 284 PropertyDetails(int value, int pointer) { 285 value_ = DescriptorPointer::update(value, pointer); 286 } 287 PropertyDetails(int value, Representation representation) { 288 value_ = RepresentationField::update( 289 value, EncodeRepresentation(representation)); 290 } 291 PropertyDetails(int value, PropertyAttributes attributes) { 292 value_ = AttributesField::update(value, attributes); 293 } 294 295 uint32_t value_; 296 }; 297 298 } } // namespace v8::internal 299 300 #endif // V8_PROPERTY_DETAILS_H_ 301