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(IsFound()); 205 return holder_; 206 } 207 type()208 PropertyType type() { 209 ASSERT(IsFound()); 210 return details_.type(); 211 } 212 GetAttributes()213 PropertyAttributes GetAttributes() { 214 ASSERT(IsFound()); 215 return details_.attributes(); 216 } 217 GetPropertyDetails()218 PropertyDetails GetPropertyDetails() { 219 return details_; 220 } 221 IsReadOnly()222 bool IsReadOnly() { return details_.IsReadOnly(); } IsDontDelete()223 bool IsDontDelete() { return details_.IsDontDelete(); } IsDontEnum()224 bool IsDontEnum() { return details_.IsDontEnum(); } IsDeleted()225 bool IsDeleted() { return details_.IsDeleted(); } IsFound()226 bool IsFound() { return lookup_type_ != NOT_FOUND; } 227 228 // Is the result is a property excluding transitions and the null 229 // descriptor? IsProperty()230 bool IsProperty() { 231 return IsFound() && (type() < FIRST_PHANTOM_PROPERTY_TYPE); 232 } 233 234 // Is the result a property or a transition? IsPropertyOrTransition()235 bool IsPropertyOrTransition() { 236 return IsFound() && (type() != NULL_DESCRIPTOR); 237 } 238 IsCacheable()239 bool IsCacheable() { return cacheable_; } DisallowCaching()240 void DisallowCaching() { cacheable_ = false; } 241 GetLazyValue()242 Object* GetLazyValue() { 243 switch (type()) { 244 case FIELD: 245 return holder()->FastPropertyAt(GetFieldIndex()); 246 case NORMAL: { 247 Object* value; 248 value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry()); 249 if (holder()->IsGlobalObject()) { 250 value = JSGlobalPropertyCell::cast(value)->value(); 251 } 252 return value; 253 } 254 case CONSTANT_FUNCTION: 255 return GetConstantFunction(); 256 default: 257 return Smi::FromInt(0); 258 } 259 } 260 GetTransitionMap()261 Map* GetTransitionMap() { 262 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 263 ASSERT(type() == MAP_TRANSITION); 264 return Map::cast(GetValue()); 265 } 266 GetFieldIndex()267 int GetFieldIndex() { 268 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 269 ASSERT(type() == FIELD); 270 return Descriptor::IndexFromValue(GetValue()); 271 } 272 GetDictionaryEntry()273 int GetDictionaryEntry() { 274 ASSERT(lookup_type_ == DICTIONARY_TYPE); 275 return number_; 276 } 277 GetConstantFunction()278 JSFunction* GetConstantFunction() { 279 ASSERT(type() == CONSTANT_FUNCTION); 280 return JSFunction::cast(GetValue()); 281 } 282 GetCallbackObject()283 Object* GetCallbackObject() { 284 if (lookup_type_ == CONSTANT_TYPE) { 285 // For now we only have the __proto__ as constant type. 286 return Heap::prototype_accessors(); 287 } 288 return GetValue(); 289 } 290 291 #ifdef DEBUG 292 void Print(); 293 #endif 294 GetValue()295 Object* GetValue() { 296 if (lookup_type_ == DESCRIPTOR_TYPE) { 297 DescriptorArray* descriptors = holder()->map()->instance_descriptors(); 298 return descriptors->GetValue(number_); 299 } 300 // In the dictionary case, the data is held in the value field. 301 ASSERT(lookup_type_ == DICTIONARY_TYPE); 302 return holder()->GetNormalizedProperty(this); 303 } 304 305 private: 306 JSObject* holder_; 307 int number_; 308 bool cacheable_; 309 PropertyDetails details_; 310 }; 311 312 313 } } // namespace v8::internal 314 315 #endif // V8_PROPERTY_H_ 316