property.h revision b0fe1620dcb4135ac3ab2d66ff93072373911299
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 31namespace v8 { 32namespace 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 42class 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. 107class MapTransitionDescriptor: public Descriptor { 108 public: 109 MapTransitionDescriptor(String* key, Map* map, PropertyAttributes attributes) 110 : Descriptor(key, map, attributes, MAP_TRANSITION) { } 111}; 112 113// Marks a field name in a map so that adding the field is guaranteed 114// to create a FIELD descriptor in the new map. Used after adding 115// a constant function the first time, creating a CONSTANT_FUNCTION 116// descriptor in the new map. This avoids creating multiple maps with 117// the same CONSTANT_FUNCTION field. 118class ConstTransitionDescriptor: public Descriptor { 119 public: 120 explicit ConstTransitionDescriptor(String* key, Map* map) 121 : Descriptor(key, map, NONE, CONSTANT_TRANSITION) { } 122}; 123 124 125class FieldDescriptor: public Descriptor { 126 public: 127 FieldDescriptor(String* key, 128 int field_index, 129 PropertyAttributes attributes, 130 int index = 0) 131 : Descriptor(key, Smi::FromInt(field_index), attributes, FIELD, index) {} 132}; 133 134 135class ConstantFunctionDescriptor: public Descriptor { 136 public: 137 ConstantFunctionDescriptor(String* key, 138 JSFunction* function, 139 PropertyAttributes attributes, 140 int index = 0) 141 : Descriptor(key, function, attributes, CONSTANT_FUNCTION, index) {} 142}; 143 144 145class CallbacksDescriptor: public Descriptor { 146 public: 147 CallbacksDescriptor(String* key, 148 Object* proxy, 149 PropertyAttributes attributes, 150 int index = 0) 151 : Descriptor(key, proxy, attributes, CALLBACKS, index) {} 152}; 153 154 155class LookupResult BASE_EMBEDDED { 156 public: 157 // Where did we find the result; 158 enum { 159 NOT_FOUND, 160 DESCRIPTOR_TYPE, 161 DICTIONARY_TYPE, 162 INTERCEPTOR_TYPE, 163 CONSTANT_TYPE 164 } lookup_type_; 165 166 LookupResult() 167 : lookup_type_(NOT_FOUND), 168 cacheable_(true), 169 details_(NONE, NORMAL) {} 170 171 void DescriptorResult(JSObject* holder, PropertyDetails details, int number) { 172 lookup_type_ = DESCRIPTOR_TYPE; 173 holder_ = holder; 174 details_ = details; 175 number_ = number; 176 } 177 178 void ConstantResult(JSObject* holder) { 179 lookup_type_ = CONSTANT_TYPE; 180 holder_ = holder; 181 details_ = 182 PropertyDetails(static_cast<PropertyAttributes>(DONT_ENUM | 183 DONT_DELETE), 184 CALLBACKS); 185 number_ = -1; 186 } 187 188 void DictionaryResult(JSObject* holder, int entry) { 189 lookup_type_ = DICTIONARY_TYPE; 190 holder_ = holder; 191 details_ = holder->property_dictionary()->DetailsAt(entry); 192 number_ = entry; 193 } 194 195 void InterceptorResult(JSObject* holder) { 196 lookup_type_ = INTERCEPTOR_TYPE; 197 holder_ = holder; 198 details_ = PropertyDetails(NONE, INTERCEPTOR); 199 } 200 201 void NotFound() { 202 lookup_type_ = NOT_FOUND; 203 } 204 205 JSObject* holder() { 206 ASSERT(IsFound()); 207 return holder_; 208 } 209 210 PropertyType type() { 211 ASSERT(IsFound()); 212 return details_.type(); 213 } 214 215 PropertyAttributes GetAttributes() { 216 ASSERT(IsFound()); 217 return details_.attributes(); 218 } 219 220 PropertyDetails GetPropertyDetails() { 221 return details_; 222 } 223 224 bool IsReadOnly() { return details_.IsReadOnly(); } 225 bool IsDontDelete() { return details_.IsDontDelete(); } 226 bool IsDontEnum() { return details_.IsDontEnum(); } 227 bool IsDeleted() { return details_.IsDeleted(); } 228 bool IsFound() { return lookup_type_ != NOT_FOUND; } 229 230 // Is the result is a property excluding transitions and the null 231 // descriptor? 232 bool IsProperty() { 233 return IsFound() && (type() < FIRST_PHANTOM_PROPERTY_TYPE); 234 } 235 236 // Is the result a property or a transition? 237 bool IsPropertyOrTransition() { 238 return IsFound() && (type() != NULL_DESCRIPTOR); 239 } 240 241 bool IsCacheable() { return cacheable_; } 242 void DisallowCaching() { cacheable_ = false; } 243 244 Object* GetLazyValue() { 245 switch (type()) { 246 case FIELD: 247 return holder()->FastPropertyAt(GetFieldIndex()); 248 case NORMAL: { 249 Object* value; 250 value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry()); 251 if (holder()->IsGlobalObject()) { 252 value = JSGlobalPropertyCell::cast(value)->value(); 253 } 254 return value; 255 } 256 case CONSTANT_FUNCTION: 257 return GetConstantFunction(); 258 default: 259 return Smi::FromInt(0); 260 } 261 } 262 263 Map* GetTransitionMap() { 264 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 265 ASSERT(type() == MAP_TRANSITION || type() == CONSTANT_TRANSITION); 266 return Map::cast(GetValue()); 267 } 268 269 Map* GetTransitionMapFromMap(Map* map) { 270 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 271 ASSERT(type() == MAP_TRANSITION); 272 return Map::cast(map->instance_descriptors()->GetValue(number_)); 273 } 274 275 int GetFieldIndex() { 276 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 277 ASSERT(type() == FIELD); 278 return Descriptor::IndexFromValue(GetValue()); 279 } 280 281 int GetLocalFieldIndexFromMap(Map* map) { 282 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 283 ASSERT(type() == FIELD); 284 return Descriptor::IndexFromValue( 285 map->instance_descriptors()->GetValue(number_)) - 286 map->inobject_properties(); 287 } 288 289 int GetDictionaryEntry() { 290 ASSERT(lookup_type_ == DICTIONARY_TYPE); 291 return number_; 292 } 293 294 JSFunction* GetConstantFunction() { 295 ASSERT(type() == CONSTANT_FUNCTION); 296 return JSFunction::cast(GetValue()); 297 } 298 299 JSFunction* GetConstantFunctionFromMap(Map* map) { 300 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 301 ASSERT(type() == CONSTANT_FUNCTION); 302 return JSFunction::cast(map->instance_descriptors()->GetValue(number_)); 303 } 304 305 Object* GetCallbackObject() { 306 if (lookup_type_ == CONSTANT_TYPE) { 307 // For now we only have the __proto__ as constant type. 308 return Heap::prototype_accessors(); 309 } 310 return GetValue(); 311 } 312 313#ifdef OBJECT_PRINT 314 void Print(FILE* out); 315#endif 316 317 Object* GetValue() { 318 if (lookup_type_ == DESCRIPTOR_TYPE) { 319 DescriptorArray* descriptors = holder()->map()->instance_descriptors(); 320 return descriptors->GetValue(number_); 321 } 322 // In the dictionary case, the data is held in the value field. 323 ASSERT(lookup_type_ == DICTIONARY_TYPE); 324 return holder()->GetNormalizedProperty(this); 325 } 326 327 private: 328 JSObject* holder_; 329 int number_; 330 bool cacheable_; 331 PropertyDetails details_; 332}; 333 334 335} } // namespace v8::internal 336 337#endif // V8_PROPERTY_H_ 338