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: IndexFromValue(Object * value)44 static int IndexFromValue(Object* value) { 45 return Smi::cast(value)->value(); 46 } 47 KeyToSymbol()48 Object* KeyToSymbol() { 49 if (!StringShape(key_).IsSymbol()) { 50 Object* result = Heap::LookupSymbol(key_); 51 if (result->IsFailure()) return result; 52 key_ = String::cast(result); 53 } 54 return key_; 55 } 56 GetKey()57 String* GetKey() { return key_; } GetValue()58 Object* GetValue() { return value_; } GetDetails()59 PropertyDetails GetDetails() { return details_; } 60 61 #ifdef DEBUG 62 void Print(); 63 #endif 64 SetEnumerationIndex(int index)65 void SetEnumerationIndex(int index) { 66 ASSERT(PropertyDetails::IsValidIndex(index)); 67 details_ = PropertyDetails(details_.attributes(), details_.type(), index); 68 } 69 70 private: 71 String* key_; 72 Object* value_; 73 PropertyDetails details_; 74 75 protected: Descriptor()76 Descriptor() : details_(Smi::FromInt(0)) {} 77 Init(String * key,Object * value,PropertyDetails details)78 void Init(String* key, Object* value, PropertyDetails details) { 79 key_ = key; 80 value_ = value; 81 details_ = details; 82 } 83 Descriptor(String * key,Object * value,PropertyDetails details)84 Descriptor(String* key, Object* value, PropertyDetails details) 85 : key_(key), 86 value_(value), 87 details_(details) { } 88 89 Descriptor(String* key, 90 Object* value, 91 PropertyAttributes attributes, 92 PropertyType type, 93 int index = 0) key_(key)94 : key_(key), 95 value_(value), 96 details_(attributes, type, index) { } 97 98 friend class DescriptorArray; 99 }; 100 101 // A pointer from a map to the new map that is created by adding 102 // a named property. These are key to the speed and functioning of V8. 103 // The two maps should always have the same prototype, since 104 // MapSpace::CreateBackPointers depends on this. 105 class MapTransitionDescriptor: public Descriptor { 106 public: MapTransitionDescriptor(String * key,Map * map,PropertyAttributes attributes)107 MapTransitionDescriptor(String* key, Map* map, PropertyAttributes attributes) 108 : Descriptor(key, map, attributes, MAP_TRANSITION) { } 109 }; 110 111 // Marks a field name in a map so that adding the field is guaranteed 112 // to create a FIELD descriptor in the new map. Used after adding 113 // a constant function the first time, creating a CONSTANT_FUNCTION 114 // descriptor in the new map. This avoids creating multiple maps with 115 // the same CONSTANT_FUNCTION field. 116 class ConstTransitionDescriptor: public Descriptor { 117 public: ConstTransitionDescriptor(String * key)118 explicit ConstTransitionDescriptor(String* key) 119 : Descriptor(key, Smi::FromInt(0), NONE, CONSTANT_TRANSITION) { } 120 }; 121 122 123 class FieldDescriptor: public Descriptor { 124 public: 125 FieldDescriptor(String* key, 126 int field_index, 127 PropertyAttributes attributes, 128 int index = 0) Descriptor(key,Smi::FromInt (field_index),attributes,FIELD,index)129 : Descriptor(key, Smi::FromInt(field_index), attributes, FIELD, index) {} 130 }; 131 132 133 class ConstantFunctionDescriptor: public Descriptor { 134 public: 135 ConstantFunctionDescriptor(String* key, 136 JSFunction* function, 137 PropertyAttributes attributes, 138 int index = 0) Descriptor(key,function,attributes,CONSTANT_FUNCTION,index)139 : Descriptor(key, function, attributes, CONSTANT_FUNCTION, index) {} 140 }; 141 142 143 class CallbacksDescriptor: public Descriptor { 144 public: 145 CallbacksDescriptor(String* key, 146 Object* proxy, 147 PropertyAttributes attributes, 148 int index = 0) Descriptor(key,proxy,attributes,CALLBACKS,index)149 : Descriptor(key, proxy, attributes, CALLBACKS, index) {} 150 }; 151 152 153 class LookupResult BASE_EMBEDDED { 154 public: 155 // Where did we find the result; 156 enum { 157 NOT_FOUND, 158 DESCRIPTOR_TYPE, 159 DICTIONARY_TYPE, 160 INTERCEPTOR_TYPE, 161 CONSTANT_TYPE 162 } lookup_type_; 163 LookupResult()164 LookupResult() 165 : lookup_type_(NOT_FOUND), 166 cacheable_(true), 167 details_(NONE, NORMAL) {} 168 DescriptorResult(JSObject * holder,PropertyDetails details,int number)169 void DescriptorResult(JSObject* holder, PropertyDetails details, int number) { 170 lookup_type_ = DESCRIPTOR_TYPE; 171 holder_ = holder; 172 details_ = details; 173 number_ = number; 174 } 175 ConstantResult(JSObject * holder)176 void ConstantResult(JSObject* holder) { 177 lookup_type_ = CONSTANT_TYPE; 178 holder_ = holder; 179 details_ = 180 PropertyDetails(static_cast<PropertyAttributes>(DONT_ENUM | 181 DONT_DELETE), 182 CALLBACKS); 183 number_ = -1; 184 } 185 DictionaryResult(JSObject * holder,int entry)186 void DictionaryResult(JSObject* holder, int entry) { 187 lookup_type_ = DICTIONARY_TYPE; 188 holder_ = holder; 189 details_ = holder->property_dictionary()->DetailsAt(entry); 190 number_ = entry; 191 } 192 InterceptorResult(JSObject * holder)193 void InterceptorResult(JSObject* holder) { 194 lookup_type_ = INTERCEPTOR_TYPE; 195 holder_ = holder; 196 details_ = PropertyDetails(NONE, INTERCEPTOR); 197 } 198 NotFound()199 void NotFound() { 200 lookup_type_ = NOT_FOUND; 201 } 202 holder()203 JSObject* holder() { 204 ASSERT(IsValid()); 205 return holder_; 206 } 207 type()208 PropertyType type() { 209 ASSERT(IsValid()); 210 return details_.type(); 211 } 212 IsTransitionType()213 bool IsTransitionType() { 214 PropertyType t = type(); 215 if (t == MAP_TRANSITION || t == CONSTANT_TRANSITION) return true; 216 return false; 217 } 218 GetAttributes()219 PropertyAttributes GetAttributes() { 220 ASSERT(IsValid()); 221 return details_.attributes(); 222 } 223 GetPropertyDetails()224 PropertyDetails GetPropertyDetails() { 225 return details_; 226 } 227 IsReadOnly()228 bool IsReadOnly() { return details_.IsReadOnly(); } IsDontDelete()229 bool IsDontDelete() { return details_.IsDontDelete(); } IsDontEnum()230 bool IsDontEnum() { return details_.IsDontEnum(); } IsDeleted()231 bool IsDeleted() { return details_.IsDeleted(); } 232 IsValid()233 bool IsValid() { return lookup_type_ != NOT_FOUND; } IsNotFound()234 bool IsNotFound() { return lookup_type_ == NOT_FOUND; } 235 236 // Tells whether the result is a property. 237 // Excluding transitions and the null descriptor. IsProperty()238 bool IsProperty() { 239 return IsValid() && type() < FIRST_PHANTOM_PROPERTY_TYPE; 240 } 241 IsCacheable()242 bool IsCacheable() { return cacheable_; } DisallowCaching()243 void DisallowCaching() { cacheable_ = false; } 244 245 // Tells whether the value needs to be loaded. IsLoaded()246 bool IsLoaded() { 247 if (lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE) { 248 Object* target = GetLazyValue(); 249 return !target->IsJSObject() || JSObject::cast(target)->IsLoaded(); 250 } 251 return true; 252 } 253 GetLazyValue()254 Object* GetLazyValue() { 255 switch (type()) { 256 case FIELD: 257 return holder()->FastPropertyAt(GetFieldIndex()); 258 case NORMAL: { 259 Object* value; 260 value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry()); 261 if (holder()->IsGlobalObject()) { 262 value = JSGlobalPropertyCell::cast(value)->value(); 263 } 264 return value; 265 } 266 case CONSTANT_FUNCTION: 267 return GetConstantFunction(); 268 default: 269 return Smi::FromInt(0); 270 } 271 } 272 GetTransitionMap()273 Map* GetTransitionMap() { 274 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 275 ASSERT(type() == MAP_TRANSITION); 276 return Map::cast(GetValue()); 277 } 278 GetFieldIndex()279 int GetFieldIndex() { 280 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 281 ASSERT(type() == FIELD); 282 return Descriptor::IndexFromValue(GetValue()); 283 } 284 GetDictionaryEntry()285 int GetDictionaryEntry() { 286 ASSERT(lookup_type_ == DICTIONARY_TYPE); 287 return number_; 288 } 289 GetConstantFunction()290 JSFunction* GetConstantFunction() { 291 ASSERT(type() == CONSTANT_FUNCTION); 292 return JSFunction::cast(GetValue()); 293 } 294 GetCallbackObject()295 Object* GetCallbackObject() { 296 if (lookup_type_ == CONSTANT_TYPE) { 297 // For now we only have the __proto__ as constant type. 298 return Heap::prototype_accessors(); 299 } 300 return GetValue(); 301 } 302 303 #ifdef DEBUG 304 void Print(); 305 #endif 306 GetValue()307 Object* GetValue() { 308 if (lookup_type_ == DESCRIPTOR_TYPE) { 309 DescriptorArray* descriptors = holder()->map()->instance_descriptors(); 310 return descriptors->GetValue(number_); 311 } 312 // In the dictionary case, the data is held in the value field. 313 ASSERT(lookup_type_ == DICTIONARY_TYPE); 314 return holder()->GetNormalizedProperty(this); 315 } 316 317 private: 318 JSObject* holder_; 319 int number_; 320 bool cacheable_; 321 PropertyDetails details_; 322 }; 323 324 325 } } // namespace v8::internal 326 327 #endif // V8_PROPERTY_H_ 328