1 // Copyright 2012 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 #include "allocation.h" 32 #include "transitions.h" 33 34 namespace v8 { 35 namespace internal { 36 37 38 // Abstraction for elements in instance-descriptor arrays. 39 // 40 // Each descriptor has a key, property attributes, property type, 41 // property index (in the actual instance-descriptor array) and 42 // optionally a piece of data. 43 // 44 45 class Descriptor BASE_EMBEDDED { 46 public: 47 MUST_USE_RESULT MaybeObject* KeyToUniqueName() { 48 if (!key_->IsUniqueName()) { 49 MaybeObject* maybe_result = HEAP->InternalizeString(String::cast(key_)); 50 if (!maybe_result->To(&key_)) return maybe_result; 51 } 52 return key_; 53 } 54 55 Name* GetKey() { return key_; } 56 Object* GetValue() { return value_; } 57 PropertyDetails GetDetails() { return details_; } 58 59 #ifdef OBJECT_PRINT 60 void Print(FILE* out); 61 #endif 62 63 void SetSortedKeyIndex(int index) { details_ = details_.set_pointer(index); } 64 65 private: 66 Name* key_; 67 Object* value_; 68 PropertyDetails details_; 69 70 protected: 71 Descriptor() : details_(Smi::FromInt(0)) {} 72 73 void Init(Name* key, Object* value, PropertyDetails details) { 74 key_ = key; 75 value_ = value; 76 details_ = details; 77 } 78 79 Descriptor(Name* key, Object* value, PropertyDetails details) 80 : key_(key), 81 value_(value), 82 details_(details) { } 83 84 Descriptor(Name* key, 85 Object* value, 86 PropertyAttributes attributes, 87 PropertyType type, 88 Representation representation, 89 int field_index = 0) 90 : key_(key), 91 value_(value), 92 details_(attributes, type, representation, field_index) { } 93 94 friend class DescriptorArray; 95 }; 96 97 98 class FieldDescriptor: public Descriptor { 99 public: 100 FieldDescriptor(Name* key, 101 int field_index, 102 PropertyAttributes attributes, 103 Representation representation) 104 : Descriptor(key, Smi::FromInt(0), attributes, 105 FIELD, representation, field_index) {} 106 }; 107 108 109 class ConstantDescriptor: public Descriptor { 110 public: 111 ConstantDescriptor(Name* key, 112 Object* value, 113 PropertyAttributes attributes) 114 : Descriptor(key, value, attributes, CONSTANT, 115 value->OptimalRepresentation()) {} 116 }; 117 118 119 class CallbacksDescriptor: public Descriptor { 120 public: 121 CallbacksDescriptor(Name* key, 122 Object* foreign, 123 PropertyAttributes attributes) 124 : Descriptor(key, foreign, attributes, CALLBACKS, 125 Representation::Tagged()) {} 126 }; 127 128 129 // Holds a property index value distinguishing if it is a field index or an 130 // index inside the object header. 131 class PropertyIndex { 132 public: 133 static PropertyIndex NewFieldIndex(int index) { 134 return PropertyIndex(index, false); 135 } 136 static PropertyIndex NewHeaderIndex(int index) { 137 return PropertyIndex(index, true); 138 } 139 140 bool is_field_index() { return (index_ & kHeaderIndexBit) == 0; } 141 bool is_header_index() { return (index_ & kHeaderIndexBit) != 0; } 142 143 int field_index() { 144 ASSERT(is_field_index()); 145 return value(); 146 } 147 int header_index() { 148 ASSERT(is_header_index()); 149 return value(); 150 } 151 152 bool is_inobject(Handle<JSObject> holder) { 153 if (is_header_index()) return true; 154 return field_index() < holder->map()->inobject_properties(); 155 } 156 157 int translate(Handle<JSObject> holder) { 158 if (is_header_index()) return header_index(); 159 int index = field_index() - holder->map()->inobject_properties(); 160 if (index >= 0) return index; 161 return index + holder->map()->instance_size() / kPointerSize; 162 } 163 164 private: 165 static const int kHeaderIndexBit = 1 << 31; 166 static const int kIndexMask = ~kHeaderIndexBit; 167 168 int value() { return index_ & kIndexMask; } 169 170 PropertyIndex(int index, bool is_header_based) 171 : index_(index | (is_header_based ? kHeaderIndexBit : 0)) { 172 ASSERT(index <= kIndexMask); 173 } 174 175 int index_; 176 }; 177 178 179 class LookupResult BASE_EMBEDDED { 180 public: 181 explicit LookupResult(Isolate* isolate) 182 : isolate_(isolate), 183 next_(isolate->top_lookup_result()), 184 lookup_type_(NOT_FOUND), 185 holder_(NULL), 186 cacheable_(true), 187 details_(NONE, NONEXISTENT, Representation::None()) { 188 isolate->SetTopLookupResult(this); 189 } 190 191 ~LookupResult() { 192 ASSERT(isolate()->top_lookup_result() == this); 193 isolate()->SetTopLookupResult(next_); 194 } 195 196 Isolate* isolate() const { return isolate_; } 197 198 void DescriptorResult(JSObject* holder, PropertyDetails details, int number) { 199 lookup_type_ = DESCRIPTOR_TYPE; 200 holder_ = holder; 201 details_ = details; 202 number_ = number; 203 } 204 205 bool CanHoldValue(Handle<Object> value) { 206 if (IsNormal()) return true; 207 ASSERT(!IsTransition()); 208 return value->FitsRepresentation(details_.representation()); 209 } 210 211 void TransitionResult(JSObject* holder, int number) { 212 lookup_type_ = TRANSITION_TYPE; 213 details_ = PropertyDetails(NONE, TRANSITION, Representation::None()); 214 holder_ = holder; 215 number_ = number; 216 } 217 218 void DictionaryResult(JSObject* holder, int entry) { 219 lookup_type_ = DICTIONARY_TYPE; 220 holder_ = holder; 221 details_ = holder->property_dictionary()->DetailsAt(entry); 222 number_ = entry; 223 } 224 225 void HandlerResult(JSProxy* proxy) { 226 lookup_type_ = HANDLER_TYPE; 227 holder_ = proxy; 228 details_ = PropertyDetails(NONE, HANDLER, Representation::Tagged()); 229 cacheable_ = false; 230 } 231 232 void InterceptorResult(JSObject* holder) { 233 lookup_type_ = INTERCEPTOR_TYPE; 234 holder_ = holder; 235 details_ = PropertyDetails(NONE, INTERCEPTOR, Representation::Tagged()); 236 } 237 238 void NotFound() { 239 lookup_type_ = NOT_FOUND; 240 details_ = PropertyDetails(NONE, NONEXISTENT, Representation::None()); 241 holder_ = NULL; 242 } 243 244 JSObject* holder() { 245 ASSERT(IsFound()); 246 return JSObject::cast(holder_); 247 } 248 249 JSProxy* proxy() { 250 ASSERT(IsFound()); 251 return JSProxy::cast(holder_); 252 } 253 254 PropertyType type() { 255 ASSERT(IsFound()); 256 return details_.type(); 257 } 258 259 Representation representation() { 260 ASSERT(IsFound()); 261 ASSERT(!IsTransition()); 262 ASSERT(details_.type() != NONEXISTENT); 263 return details_.representation(); 264 } 265 266 PropertyAttributes GetAttributes() { 267 ASSERT(!IsTransition()); 268 ASSERT(IsFound()); 269 ASSERT(details_.type() != NONEXISTENT); 270 return details_.attributes(); 271 } 272 273 PropertyDetails GetPropertyDetails() { 274 ASSERT(!IsTransition()); 275 return details_; 276 } 277 278 bool IsFastPropertyType() { 279 ASSERT(IsFound()); 280 return IsTransition() || type() != NORMAL; 281 } 282 283 // Property callbacks does not include transitions to callbacks. 284 bool IsPropertyCallbacks() { 285 ASSERT(!(details_.type() == CALLBACKS && !IsFound())); 286 return details_.type() == CALLBACKS; 287 } 288 289 bool IsReadOnly() { 290 ASSERT(IsFound()); 291 ASSERT(!IsTransition()); 292 ASSERT(details_.type() != NONEXISTENT); 293 return details_.IsReadOnly(); 294 } 295 296 bool IsField() { 297 ASSERT(!(details_.type() == FIELD && !IsFound())); 298 return details_.type() == FIELD; 299 } 300 301 bool IsNormal() { 302 ASSERT(!(details_.type() == NORMAL && !IsFound())); 303 return details_.type() == NORMAL; 304 } 305 306 bool IsConstant() { 307 ASSERT(!(details_.type() == CONSTANT && !IsFound())); 308 return details_.type() == CONSTANT; 309 } 310 311 bool IsConstantFunction() { 312 return IsConstant() && GetValue()->IsJSFunction(); 313 } 314 315 bool IsDontDelete() { return details_.IsDontDelete(); } 316 bool IsDontEnum() { return details_.IsDontEnum(); } 317 bool IsFound() { return lookup_type_ != NOT_FOUND; } 318 bool IsTransition() { return lookup_type_ == TRANSITION_TYPE; } 319 bool IsHandler() { return lookup_type_ == HANDLER_TYPE; } 320 bool IsInterceptor() { return lookup_type_ == INTERCEPTOR_TYPE; } 321 322 // Is the result is a property excluding transitions and the null descriptor? 323 bool IsProperty() { 324 return IsFound() && !IsTransition(); 325 } 326 327 bool IsDataProperty() { 328 switch (type()) { 329 case FIELD: 330 case NORMAL: 331 case CONSTANT: 332 return true; 333 case CALLBACKS: { 334 Object* callback = GetCallbackObject(); 335 return callback->IsAccessorInfo() || callback->IsForeign(); 336 } 337 case HANDLER: 338 case INTERCEPTOR: 339 case TRANSITION: 340 case NONEXISTENT: 341 return false; 342 } 343 UNREACHABLE(); 344 return false; 345 } 346 347 bool IsCacheable() { return cacheable_; } 348 void DisallowCaching() { cacheable_ = false; } 349 350 Object* GetLazyValue() { 351 switch (type()) { 352 case FIELD: 353 return holder()->RawFastPropertyAt(GetFieldIndex().field_index()); 354 case NORMAL: { 355 Object* value; 356 value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry()); 357 if (holder()->IsGlobalObject()) { 358 value = PropertyCell::cast(value)->value(); 359 } 360 return value; 361 } 362 case CONSTANT: 363 return GetConstant(); 364 case CALLBACKS: 365 case HANDLER: 366 case INTERCEPTOR: 367 case TRANSITION: 368 case NONEXISTENT: 369 return isolate()->heap()->the_hole_value(); 370 } 371 UNREACHABLE(); 372 return NULL; 373 } 374 375 Map* GetTransitionTarget(Map* map) { 376 ASSERT(IsTransition()); 377 TransitionArray* transitions = map->transitions(); 378 return transitions->GetTarget(number_); 379 } 380 381 Map* GetTransitionTarget() { 382 return GetTransitionTarget(holder()->map()); 383 } 384 385 PropertyDetails GetTransitionDetails(Map* map) { 386 ASSERT(IsTransition()); 387 TransitionArray* transitions = map->transitions(); 388 return transitions->GetTargetDetails(number_); 389 } 390 391 PropertyDetails GetTransitionDetails() { 392 return GetTransitionDetails(holder()->map()); 393 } 394 395 bool IsTransitionToField(Map* map) { 396 return IsTransition() && GetTransitionDetails(map).type() == FIELD; 397 } 398 399 bool IsTransitionToConstant(Map* map) { 400 return IsTransition() && GetTransitionDetails(map).type() == CONSTANT; 401 } 402 403 Map* GetTransitionMap() { 404 ASSERT(IsTransition()); 405 return Map::cast(GetValue()); 406 } 407 408 Map* GetTransitionMapFromMap(Map* map) { 409 ASSERT(IsTransition()); 410 return map->transitions()->GetTarget(number_); 411 } 412 413 int GetTransitionIndex() { 414 ASSERT(IsTransition()); 415 return number_; 416 } 417 418 int GetDescriptorIndex() { 419 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 420 return number_; 421 } 422 423 PropertyIndex GetFieldIndex() { 424 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 425 ASSERT(IsField()); 426 return PropertyIndex::NewFieldIndex(GetFieldIndexFromMap(holder()->map())); 427 } 428 429 int GetLocalFieldIndexFromMap(Map* map) { 430 ASSERT(IsField()); 431 return GetFieldIndexFromMap(map) - map->inobject_properties(); 432 } 433 434 int GetDictionaryEntry() { 435 ASSERT(lookup_type_ == DICTIONARY_TYPE); 436 return number_; 437 } 438 439 JSFunction* GetConstantFunction() { 440 ASSERT(type() == CONSTANT); 441 return JSFunction::cast(GetValue()); 442 } 443 444 Object* GetConstantFromMap(Map* map) { 445 ASSERT(type() == CONSTANT); 446 return GetValueFromMap(map); 447 } 448 449 JSFunction* GetConstantFunctionFromMap(Map* map) { 450 return JSFunction::cast(GetConstantFromMap(map)); 451 } 452 453 Object* GetConstant() { 454 ASSERT(type() == CONSTANT); 455 return GetValue(); 456 } 457 458 Object* GetCallbackObject() { 459 ASSERT(type() == CALLBACKS && !IsTransition()); 460 return GetValue(); 461 } 462 463 #ifdef OBJECT_PRINT 464 void Print(FILE* out); 465 #endif 466 467 Object* GetValue() { 468 if (lookup_type_ == DESCRIPTOR_TYPE) { 469 return GetValueFromMap(holder()->map()); 470 } 471 // In the dictionary case, the data is held in the value field. 472 ASSERT(lookup_type_ == DICTIONARY_TYPE); 473 return holder()->GetNormalizedProperty(this); 474 } 475 476 Object* GetValueFromMap(Map* map) const { 477 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 478 ASSERT(number_ < map->NumberOfOwnDescriptors()); 479 return map->instance_descriptors()->GetValue(number_); 480 } 481 482 int GetFieldIndexFromMap(Map* map) const { 483 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); 484 ASSERT(number_ < map->NumberOfOwnDescriptors()); 485 return map->instance_descriptors()->GetFieldIndex(number_); 486 } 487 488 void Iterate(ObjectVisitor* visitor); 489 490 private: 491 Isolate* isolate_; 492 LookupResult* next_; 493 494 // Where did we find the result; 495 enum { 496 NOT_FOUND, 497 DESCRIPTOR_TYPE, 498 TRANSITION_TYPE, 499 DICTIONARY_TYPE, 500 HANDLER_TYPE, 501 INTERCEPTOR_TYPE 502 } lookup_type_; 503 504 JSReceiver* holder_; 505 int number_; 506 bool cacheable_; 507 PropertyDetails details_; 508 }; 509 510 511 } } // namespace v8::internal 512 513 #endif // V8_PROPERTY_H_ 514