1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_PROPERTY_H_ 29 #define V8_PROPERTY_H_ 30 31 namespace v8 { 32 namespace internal { 33 34 35 // Abstraction for elements in instance-descriptor arrays. 36 // 37 // Each descriptor has a key, property attributes, property type, 38 // property index (in the actual instance-descriptor array) and 39 // optionally a piece of data. 40 // 41 42 class Descriptor BASE_EMBEDDED { 43 public: 44 static int IndexFromValue(Object* value) { 45 return Smi::cast(value)->value(); 46 } 47 48 MUST_USE_RESULT MaybeObject* KeyToSymbol() { 49 if (!StringShape(key_).IsSymbol()) { 50 Object* result; 51 { MaybeObject* maybe_result = HEAP->LookupSymbol(key_); 52 if (!maybe_result->ToObject(&result)) return maybe_result; 53 } 54 key_ = String::cast(result); 55 } 56 return key_; 57 } 58 59 String* GetKey() { return key_; } 60 Object* GetValue() { return value_; } 61 PropertyDetails GetDetails() { return details_; } 62 63 #ifdef OBJECT_PRINT 64 void Print(FILE* out); 65 #endif 66 67 void SetEnumerationIndex(int index) { 68 ASSERT(PropertyDetails::IsValidIndex(index)); 69 details_ = PropertyDetails(details_.attributes(), details_.type(), index); 70 } 71 72 private: 73 String* key_; 74 Object* value_; 75 PropertyDetails details_; 76 77 protected: 78 Descriptor() : details_(Smi::FromInt(0)) {} 79 80 void Init(String* key, Object* value, PropertyDetails details) { 81 key_ = key; 82 value_ = value; 83 details_ = details; 84 } 85 86 Descriptor(String* key, Object* value, PropertyDetails details) 87 : key_(key), 88 value_(value), 89 details_(details) { } 90 91 Descriptor(String* key, 92 Object* value, 93 PropertyAttributes attributes, 94 PropertyType type, 95 int index = 0) 96 : key_(key), 97 value_(value), 98 details_(attributes, type, index) { } 99 100 friend class DescriptorArray; 101 }; 102 103 // A pointer from a map to the new map that is created by adding 104 // a named property. These are key to the speed and functioning of V8. 105 // The two maps should always have the same prototype, since 106 // MapSpace::CreateBackPointers depends on this. 107 class MapTransitionDescriptor: public Descriptor { 108 public: 109 MapTransitionDescriptor(String* key, Map* map, PropertyAttributes attributes) 110 : Descriptor(key, map, attributes, MAP_TRANSITION) { } 111 }; 112 113 class ExternalArrayTransitionDescriptor: public Descriptor { 114 public: 115 ExternalArrayTransitionDescriptor(String* key, 116 Map* map, 117 ExternalArrayType array_type) 118 : Descriptor(key, map, PropertyDetails(NONE, 119 EXTERNAL_ARRAY_TRANSITION, 120 array_type)) { } 121 }; 122 123 // Marks a field name in a map so that adding the field is guaranteed 124 // to create a FIELD descriptor in the new map. Used after adding 125 // a constant function the first time, creating a CONSTANT_FUNCTION 126 // descriptor in the new map. This avoids creating multiple maps with 127 // the same CONSTANT_FUNCTION field. 128 class ConstTransitionDescriptor: public Descriptor { 129 public: 130 explicit ConstTransitionDescriptor(String* key, Map* map) 131 : Descriptor(key, map, NONE, CONSTANT_TRANSITION) { } 132 }; 133 134 135 class FieldDescriptor: public Descriptor { 136 public: 137 FieldDescriptor(String* key, 138 int field_index, 139 PropertyAttributes attributes, 140 int index = 0) 141 : Descriptor(key, Smi::FromInt(field_index), attributes, FIELD, index) {} 142 }; 143 144 145 class ConstantFunctionDescriptor: public Descriptor { 146 public: 147 ConstantFunctionDescriptor(String* key, 148 JSFunction* function, 149 PropertyAttributes attributes, 150 int index = 0) 151 : Descriptor(key, function, attributes, CONSTANT_FUNCTION, index) {} 152 }; 153 154 155 class CallbacksDescriptor: public Descriptor { 156 public: 157 CallbacksDescriptor(String* key, 158 Object* proxy, 159 PropertyAttributes attributes, 160 int index = 0) 161 : Descriptor(key, proxy, attributes, CALLBACKS, index) {} 162 }; 163 164 165 class LookupResult BASE_EMBEDDED { 166 public: 167 // Where did we find the result; 168 enum { 169 NOT_FOUND, 170 DESCRIPTOR_TYPE, 171 DICTIONARY_TYPE, 172 INTERCEPTOR_TYPE, 173 CONSTANT_TYPE 174 } lookup_type_; 175 176 LookupResult() 177 : lookup_type_(NOT_FOUND), 178 cacheable_(true), 179 details_(NONE, NORMAL) {} 180 181 void DescriptorResult(JSObject* holder, PropertyDetails details, int number) { 182 lookup_type_ = DESCRIPTOR_TYPE; 183 holder_ = holder; 184 details_ = details; 185 number_ = number; 186 } 187 188 void DescriptorResult(JSObject* holder, Smi* details, int number) { 189 lookup_type_ = DESCRIPTOR_TYPE; 190 holder_ = holder; 191 details_ = PropertyDetails(details); 192 number_ = number; 193 } 194 195 void ConstantResult(JSObject* holder) { 196 lookup_type_ = CONSTANT_TYPE; 197 holder_ = holder; 198 details_ = 199 PropertyDetails(static_cast<PropertyAttributes>(DONT_ENUM | 200 DONT_DELETE), 201 CALLBACKS); 202 number_ = -1; 203 } 204 205 void DictionaryResult(JSObject* holder, int entry) { 206 lookup_type_ = DICTIONARY_TYPE; 207 holder_ = holder; 208 details_ = holder->property_dictionary()->DetailsAt(entry); 209 number_ = entry; 210 } 211 212 void InterceptorResult(JSObject* holder) { 213 lookup_type_ = INTERCEPTOR_TYPE; 214 holder_ = holder; 215 details_ = PropertyDetails(NONE, INTERCEPTOR); 216 } 217 218 void NotFound() { 219 lookup_type_ = NOT_FOUND; 220 } 221 222 JSObject* holder() { 223 ASSERT(IsFound()); 224 return holder_; 225 } 226 227 PropertyType type() { 228 ASSERT(IsFound()); 229 return details_.type(); 230 } 231 232 PropertyAttributes GetAttributes() { 233 ASSERT(IsFound()); 234 return details_.attributes(); 235 } 236 237 PropertyDetails GetPropertyDetails() { 238 return details_; 239 } 240 241 bool IsReadOnly() { return details_.IsReadOnly(); } 242 bool IsDontDelete() { return details_.IsDontDelete(); } 243 bool IsDontEnum() { return details_.IsDontEnum(); } 244 bool IsDeleted() { return details_.IsDeleted(); } 245 bool IsFound() { return lookup_type_ != NOT_FOUND; } 246 247 // Is the result is a property excluding transitions and the null 248 // descriptor? 249 bool IsProperty() { 250 return IsFound() && (type() < FIRST_PHANTOM_PROPERTY_TYPE); 251 } 252 253 // Is the result a property or a transition? 254 bool IsPropertyOrTransition() { 255 return IsFound() && (type() != NULL_DESCRIPTOR); 256 } 257 258 bool IsCacheable() { return cacheable_; } 259 void DisallowCaching() { cacheable_ = false; } 260 261 Object* GetLazyValue() { 262 switch (type()) { 263 case FIELD: 264 return holder()->FastPropertyAt(GetFieldIndex()); 265 case NORMAL: { 266 Object* value; 267 value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry()); 268 if (holder()->IsGlobalObject()) { 269 value = JSGlobalPropertyCell::cast(value)->value(); 270 } 271 return value; 272 } 273 case CONSTANT_FUNCTION: 274 return GetConstantFunction(); 275 default: 276 return Smi::FromInt(0); 277 } 278 } 279 280 Map* GetTransitionMap() { 281 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 282 ASSERT(type() == MAP_TRANSITION || type() == CONSTANT_TRANSITION || 283 type() == EXTERNAL_ARRAY_TRANSITION); 284 return Map::cast(GetValue()); 285 } 286 287 Map* GetTransitionMapFromMap(Map* map) { 288 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 289 ASSERT(type() == MAP_TRANSITION); 290 return Map::cast(map->instance_descriptors()->GetValue(number_)); 291 } 292 293 int GetFieldIndex() { 294 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 295 ASSERT(type() == FIELD); 296 return Descriptor::IndexFromValue(GetValue()); 297 } 298 299 int GetLocalFieldIndexFromMap(Map* map) { 300 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 301 ASSERT(type() == FIELD); 302 return Descriptor::IndexFromValue( 303 map->instance_descriptors()->GetValue(number_)) - 304 map->inobject_properties(); 305 } 306 307 int GetDictionaryEntry() { 308 ASSERT(lookup_type_ == DICTIONARY_TYPE); 309 return number_; 310 } 311 312 JSFunction* GetConstantFunction() { 313 ASSERT(type() == CONSTANT_FUNCTION); 314 return JSFunction::cast(GetValue()); 315 } 316 317 JSFunction* GetConstantFunctionFromMap(Map* map) { 318 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 319 ASSERT(type() == CONSTANT_FUNCTION); 320 return JSFunction::cast(map->instance_descriptors()->GetValue(number_)); 321 } 322 323 Object* GetCallbackObject() { 324 if (lookup_type_ == CONSTANT_TYPE) { 325 // For now we only have the __proto__ as constant type. 326 return HEAP->prototype_accessors(); 327 } 328 return GetValue(); 329 } 330 331 #ifdef OBJECT_PRINT 332 void Print(FILE* out); 333 #endif 334 335 Object* GetValue() { 336 if (lookup_type_ == DESCRIPTOR_TYPE) { 337 DescriptorArray* descriptors = holder()->map()->instance_descriptors(); 338 return descriptors->GetValue(number_); 339 } 340 // In the dictionary case, the data is held in the value field. 341 ASSERT(lookup_type_ == DICTIONARY_TYPE); 342 return holder()->GetNormalizedProperty(this); 343 } 344 345 private: 346 JSObject* holder_; 347 int number_; 348 bool cacheable_; 349 PropertyDetails details_; 350 }; 351 352 353 } } // namespace v8::internal 354 355 #endif // V8_PROPERTY_H_ 356