| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef V8_PROPERTY_H_ | 5 #ifndef V8_PROPERTY_H_ |
| 6 #define V8_PROPERTY_H_ | 6 #define V8_PROPERTY_H_ |
| 7 | 7 |
| 8 #include "isolate.h" | 8 #include "isolate.h" |
| 9 | 9 |
| 10 namespace v8 { | 10 namespace v8 { |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 void DescriptorResult(JSObject* holder, PropertyDetails details, int number) { | 173 void DescriptorResult(JSObject* holder, PropertyDetails details, int number) { |
| 174 lookup_type_ = DESCRIPTOR_TYPE; | 174 lookup_type_ = DESCRIPTOR_TYPE; |
| 175 holder_ = holder; | 175 holder_ = holder; |
| 176 transition_ = NULL; | 176 transition_ = NULL; |
| 177 details_ = details; | 177 details_ = details; |
| 178 number_ = number; | 178 number_ = number; |
| 179 } | 179 } |
| 180 | 180 |
| 181 bool CanHoldValue(Handle<Object> value) { | 181 bool CanHoldValue(Handle<Object> value) { |
| 182 if (IsNormal()) return true; | 182 if (IsNormal()) return true; |
| 183 ASSERT(!IsTransition()); | |
| 184 return value->FitsRepresentation(details_.representation()); | 183 return value->FitsRepresentation(details_.representation()); |
| 185 } | 184 } |
| 186 | 185 |
| 187 void TransitionResult(JSObject* holder, Map* target) { | 186 void TransitionResult(JSObject* holder, Map* target) { |
| 188 lookup_type_ = TRANSITION_TYPE; | 187 lookup_type_ = TRANSITION_TYPE; |
| 189 details_ = PropertyDetails(NONE, TRANSITION, Representation::None()); | 188 number_ = target->LastAdded(); |
| 189 details_ = target->instance_descriptors()->GetDetails(number_); |
| 190 holder_ = holder; | 190 holder_ = holder; |
| 191 transition_ = target; | 191 transition_ = target; |
| 192 number_ = 0xAAAA; | |
| 193 } | 192 } |
| 194 | 193 |
| 195 void DictionaryResult(JSObject* holder, int entry) { | 194 void DictionaryResult(JSObject* holder, int entry) { |
| 196 lookup_type_ = DICTIONARY_TYPE; | 195 lookup_type_ = DICTIONARY_TYPE; |
| 197 holder_ = holder; | 196 holder_ = holder; |
| 198 transition_ = NULL; | 197 transition_ = NULL; |
| 199 details_ = holder->property_dictionary()->DetailsAt(entry); | 198 details_ = holder->property_dictionary()->DetailsAt(entry); |
| 200 number_ = entry; | 199 number_ = entry; |
| 201 } | 200 } |
| 202 | 201 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 232 return JSProxy::cast(holder_); | 231 return JSProxy::cast(holder_); |
| 233 } | 232 } |
| 234 | 233 |
| 235 PropertyType type() const { | 234 PropertyType type() const { |
| 236 ASSERT(IsFound()); | 235 ASSERT(IsFound()); |
| 237 return details_.type(); | 236 return details_.type(); |
| 238 } | 237 } |
| 239 | 238 |
| 240 Representation representation() const { | 239 Representation representation() const { |
| 241 ASSERT(IsFound()); | 240 ASSERT(IsFound()); |
| 242 ASSERT(!IsTransition()); | |
| 243 ASSERT(details_.type() != NONEXISTENT); | 241 ASSERT(details_.type() != NONEXISTENT); |
| 244 return details_.representation(); | 242 return details_.representation(); |
| 245 } | 243 } |
| 246 | 244 |
| 247 PropertyAttributes GetAttributes() const { | 245 PropertyAttributes GetAttributes() const { |
| 248 ASSERT(!IsTransition()); | |
| 249 ASSERT(IsFound()); | 246 ASSERT(IsFound()); |
| 250 ASSERT(details_.type() != NONEXISTENT); | 247 ASSERT(details_.type() != NONEXISTENT); |
| 251 return details_.attributes(); | 248 return details_.attributes(); |
| 252 } | 249 } |
| 253 | 250 |
| 254 PropertyDetails GetPropertyDetails() const { | 251 PropertyDetails GetPropertyDetails() const { |
| 255 ASSERT(!IsTransition()); | |
| 256 return details_; | 252 return details_; |
| 257 } | 253 } |
| 258 | 254 |
| 259 bool IsFastPropertyType() const { | 255 bool IsFastPropertyType() const { |
| 260 ASSERT(IsFound()); | 256 ASSERT(IsFound()); |
| 261 return IsTransition() || type() != NORMAL; | 257 return IsTransition() || type() != NORMAL; |
| 262 } | 258 } |
| 263 | 259 |
| 264 // Property callbacks does not include transitions to callbacks. | 260 // Property callbacks does not include transitions to callbacks. |
| 265 bool IsPropertyCallbacks() const { | 261 bool IsPropertyCallbacks() const { |
| 266 ASSERT(!(details_.type() == CALLBACKS && !IsFound())); | 262 ASSERT(!(details_.type() == CALLBACKS && !IsFound())); |
| 267 return details_.type() == CALLBACKS; | 263 return !IsTransition() && details_.type() == CALLBACKS; |
| 268 } | 264 } |
| 269 | 265 |
| 270 bool IsReadOnly() const { | 266 bool IsReadOnly() const { |
| 271 ASSERT(IsFound()); | 267 ASSERT(IsFound()); |
| 272 ASSERT(!IsTransition()); | |
| 273 ASSERT(details_.type() != NONEXISTENT); | 268 ASSERT(details_.type() != NONEXISTENT); |
| 274 return details_.IsReadOnly(); | 269 return details_.IsReadOnly(); |
| 275 } | 270 } |
| 276 | 271 |
| 277 bool IsField() const { | 272 bool IsField() const { |
| 278 ASSERT(!(details_.type() == FIELD && !IsFound())); | 273 ASSERT(!(details_.type() == FIELD && !IsFound())); |
| 279 return details_.type() == FIELD; | 274 return IsDescriptorOrDictionary() && type() == FIELD; |
| 280 } | 275 } |
| 281 | 276 |
| 282 bool IsNormal() const { | 277 bool IsNormal() const { |
| 283 ASSERT(!(details_.type() == NORMAL && !IsFound())); | 278 ASSERT(!(details_.type() == NORMAL && !IsFound())); |
| 284 return details_.type() == NORMAL; | 279 return IsDescriptorOrDictionary() && type() == NORMAL; |
| 285 } | 280 } |
| 286 | 281 |
| 287 bool IsConstant() const { | 282 bool IsConstant() const { |
| 288 ASSERT(!(details_.type() == CONSTANT && !IsFound())); | 283 ASSERT(!(details_.type() == CONSTANT && !IsFound())); |
| 289 return details_.type() == CONSTANT; | 284 return IsDescriptorOrDictionary() && type() == CONSTANT; |
| 290 } | 285 } |
| 291 | 286 |
| 292 bool IsConstantFunction() const { | 287 bool IsConstantFunction() const { |
| 293 return IsConstant() && GetValue()->IsJSFunction(); | 288 return IsConstant() && GetConstant()->IsJSFunction(); |
| 294 } | 289 } |
| 295 | 290 |
| 296 bool IsDontDelete() const { return details_.IsDontDelete(); } | 291 bool IsDontDelete() const { return details_.IsDontDelete(); } |
| 297 bool IsDontEnum() const { return details_.IsDontEnum(); } | 292 bool IsDontEnum() const { return details_.IsDontEnum(); } |
| 298 bool IsFound() const { return lookup_type_ != NOT_FOUND; } | 293 bool IsFound() const { return lookup_type_ != NOT_FOUND; } |
| 294 bool IsDescriptorOrDictionary() const { |
| 295 return lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE; |
| 296 } |
| 299 bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; } | 297 bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; } |
| 300 bool IsHandler() const { return lookup_type_ == HANDLER_TYPE; } | 298 bool IsHandler() const { return lookup_type_ == HANDLER_TYPE; } |
| 301 bool IsInterceptor() const { return lookup_type_ == INTERCEPTOR_TYPE; } | 299 bool IsInterceptor() const { return lookup_type_ == INTERCEPTOR_TYPE; } |
| 302 | 300 |
| 303 // Is the result is a property excluding transitions and the null descriptor? | 301 // Is the result is a property excluding transitions and the null descriptor? |
| 304 bool IsProperty() const { | 302 bool IsProperty() const { |
| 305 return IsFound() && !IsTransition(); | 303 return IsFound() && !IsTransition(); |
| 306 } | 304 } |
| 307 | 305 |
| 308 bool IsDataProperty() const { | 306 bool IsDataProperty() const { |
| 309 switch (type()) { | 307 switch (lookup_type_) { |
| 310 case FIELD: | 308 case NOT_FOUND: |
| 311 case NORMAL: | 309 case TRANSITION_TYPE: |
| 312 case CONSTANT: | 310 case HANDLER_TYPE: |
| 313 return true; | 311 case INTERCEPTOR_TYPE: |
| 314 case CALLBACKS: { | |
| 315 Object* callback = GetCallbackObject(); | |
| 316 return callback->IsAccessorInfo() || callback->IsForeign(); | |
| 317 } | |
| 318 case HANDLER: | |
| 319 case INTERCEPTOR: | |
| 320 case TRANSITION: | |
| 321 case NONEXISTENT: | |
| 322 return false; | 312 return false; |
| 313 |
| 314 case DESCRIPTOR_TYPE: |
| 315 case DICTIONARY_TYPE: |
| 316 switch (type()) { |
| 317 case FIELD: |
| 318 case NORMAL: |
| 319 case CONSTANT: |
| 320 return true; |
| 321 case CALLBACKS: { |
| 322 Object* callback = GetCallbackObject(); |
| 323 return callback->IsAccessorInfo() || callback->IsForeign(); |
| 324 } |
| 325 case HANDLER: |
| 326 case INTERCEPTOR: |
| 327 case NONEXISTENT: |
| 328 UNREACHABLE(); |
| 329 return false; |
| 330 } |
| 323 } | 331 } |
| 324 UNREACHABLE(); | 332 UNREACHABLE(); |
| 325 return false; | 333 return false; |
| 326 } | 334 } |
| 327 | 335 |
| 328 bool IsCacheable() const { return cacheable_; } | 336 bool IsCacheable() const { return cacheable_; } |
| 329 void DisallowCaching() { cacheable_ = false; } | 337 void DisallowCaching() { cacheable_ = false; } |
| 330 | 338 |
| 331 Object* GetLazyValue() const { | 339 Object* GetLazyValue() const { |
| 332 switch (type()) { | 340 switch (lookup_type_) { |
| 333 case FIELD: | 341 case NOT_FOUND: |
| 334 return holder()->RawFastPropertyAt(GetFieldIndex().field_index()); | 342 case TRANSITION_TYPE: |
| 335 case NORMAL: { | 343 case HANDLER_TYPE: |
| 336 Object* value; | 344 case INTERCEPTOR_TYPE: |
| 337 value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry()); | 345 return isolate()->heap()->the_hole_value(); |
| 338 if (holder()->IsGlobalObject()) { | 346 |
| 339 value = PropertyCell::cast(value)->value(); | 347 case DESCRIPTOR_TYPE: |
| 348 case DICTIONARY_TYPE: |
| 349 switch (type()) { |
| 350 case FIELD: |
| 351 return holder()->RawFastPropertyAt(GetFieldIndex().field_index()); |
| 352 case NORMAL: { |
| 353 Object* value = holder()->property_dictionary()->ValueAt( |
| 354 GetDictionaryEntry()); |
| 355 if (holder()->IsGlobalObject()) { |
| 356 value = PropertyCell::cast(value)->value(); |
| 357 } |
| 358 return value; |
| 359 } |
| 360 case CONSTANT: |
| 361 return GetConstant(); |
| 362 case CALLBACKS: |
| 363 return isolate()->heap()->the_hole_value(); |
| 364 case HANDLER: |
| 365 case INTERCEPTOR: |
| 366 case NONEXISTENT: |
| 367 UNREACHABLE(); |
| 368 return NULL; |
| 340 } | 369 } |
| 341 return value; | |
| 342 } | |
| 343 case CONSTANT: | |
| 344 return GetConstant(); | |
| 345 case CALLBACKS: | |
| 346 case HANDLER: | |
| 347 case INTERCEPTOR: | |
| 348 case TRANSITION: | |
| 349 case NONEXISTENT: | |
| 350 return isolate()->heap()->the_hole_value(); | |
| 351 } | 370 } |
| 352 UNREACHABLE(); | 371 UNREACHABLE(); |
| 353 return NULL; | 372 return NULL; |
| 354 } | 373 } |
| 355 | 374 |
| 356 Map* GetTransitionTarget() const { | 375 Map* GetTransitionTarget() const { |
| 376 ASSERT(IsTransition()); |
| 357 return transition_; | 377 return transition_; |
| 358 } | 378 } |
| 359 | 379 |
| 360 PropertyDetails GetTransitionDetails() const { | |
| 361 ASSERT(IsTransition()); | |
| 362 return transition_->GetLastDescriptorDetails(); | |
| 363 } | |
| 364 | |
| 365 bool IsTransitionToField() const { | 380 bool IsTransitionToField() const { |
| 366 return IsTransition() && GetTransitionDetails().type() == FIELD; | 381 return IsTransition() && details_.type() == FIELD; |
| 367 } | 382 } |
| 368 | 383 |
| 369 bool IsTransitionToConstant() const { | 384 bool IsTransitionToConstant() const { |
| 370 return IsTransition() && GetTransitionDetails().type() == CONSTANT; | 385 return IsTransition() && details_.type() == CONSTANT; |
| 371 } | 386 } |
| 372 | 387 |
| 373 int GetDescriptorIndex() const { | 388 int GetDescriptorIndex() const { |
| 374 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); | 389 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); |
| 375 return number_; | 390 return number_; |
| 376 } | 391 } |
| 377 | 392 |
| 378 PropertyIndex GetFieldIndex() const { | 393 PropertyIndex GetFieldIndex() const { |
| 379 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); | 394 ASSERT(lookup_type_ == DESCRIPTOR_TYPE || |
| 395 lookup_type_ == TRANSITION_TYPE); |
| 380 return PropertyIndex::NewFieldIndex(GetFieldIndexFromMap(holder()->map())); | 396 return PropertyIndex::NewFieldIndex(GetFieldIndexFromMap(holder()->map())); |
| 381 } | 397 } |
| 382 | 398 |
| 383 int GetLocalFieldIndexFromMap(Map* map) const { | 399 int GetLocalFieldIndexFromMap(Map* map) const { |
| 384 return GetFieldIndexFromMap(map) - map->inobject_properties(); | 400 return GetFieldIndexFromMap(map) - map->inobject_properties(); |
| 385 } | 401 } |
| 386 | 402 |
| 387 int GetDictionaryEntry() const { | 403 int GetDictionaryEntry() const { |
| 388 ASSERT(lookup_type_ == DICTIONARY_TYPE); | 404 ASSERT(lookup_type_ == DICTIONARY_TYPE); |
| 389 return number_; | 405 return number_; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 402 JSFunction* GetConstantFunctionFromMap(Map* map) const { | 418 JSFunction* GetConstantFunctionFromMap(Map* map) const { |
| 403 return JSFunction::cast(GetConstantFromMap(map)); | 419 return JSFunction::cast(GetConstantFromMap(map)); |
| 404 } | 420 } |
| 405 | 421 |
| 406 Object* GetConstant() const { | 422 Object* GetConstant() const { |
| 407 ASSERT(type() == CONSTANT); | 423 ASSERT(type() == CONSTANT); |
| 408 return GetValue(); | 424 return GetValue(); |
| 409 } | 425 } |
| 410 | 426 |
| 411 Object* GetCallbackObject() const { | 427 Object* GetCallbackObject() const { |
| 412 ASSERT(type() == CALLBACKS && !IsTransition()); | 428 ASSERT(!IsTransition()); |
| 429 ASSERT(type() == CALLBACKS); |
| 413 return GetValue(); | 430 return GetValue(); |
| 414 } | 431 } |
| 415 | 432 |
| 416 #ifdef OBJECT_PRINT | 433 #ifdef OBJECT_PRINT |
| 417 void Print(FILE* out); | 434 void Print(FILE* out); |
| 418 #endif | 435 #endif |
| 419 | 436 |
| 420 Object* GetValue() const { | 437 Object* GetValue() const { |
| 421 if (lookup_type_ == DESCRIPTOR_TYPE) { | 438 if (lookup_type_ == DESCRIPTOR_TYPE) { |
| 422 return GetValueFromMap(holder()->map()); | 439 return GetValueFromMap(holder()->map()); |
| 440 } else if (lookup_type_ == TRANSITION_TYPE) { |
| 441 return GetValueFromMap(transition_); |
| 423 } | 442 } |
| 424 // In the dictionary case, the data is held in the value field. | 443 // In the dictionary case, the data is held in the value field. |
| 425 ASSERT(lookup_type_ == DICTIONARY_TYPE); | 444 ASSERT(lookup_type_ == DICTIONARY_TYPE); |
| 426 return holder()->GetNormalizedProperty(this); | 445 return holder()->GetNormalizedProperty(this); |
| 427 } | 446 } |
| 428 | 447 |
| 429 Object* GetValueFromMap(Map* map) const { | 448 Object* GetValueFromMap(Map* map) const { |
| 430 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); | 449 ASSERT(lookup_type_ == DESCRIPTOR_TYPE || |
| 450 lookup_type_ == TRANSITION_TYPE); |
| 431 ASSERT(number_ < map->NumberOfOwnDescriptors()); | 451 ASSERT(number_ < map->NumberOfOwnDescriptors()); |
| 432 return map->instance_descriptors()->GetValue(number_); | 452 return map->instance_descriptors()->GetValue(number_); |
| 433 } | 453 } |
| 434 | 454 |
| 435 int GetFieldIndexFromMap(Map* map) const { | 455 int GetFieldIndexFromMap(Map* map) const { |
| 436 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); | 456 ASSERT(lookup_type_ == DESCRIPTOR_TYPE || |
| 457 lookup_type_ == TRANSITION_TYPE); |
| 437 ASSERT(number_ < map->NumberOfOwnDescriptors()); | 458 ASSERT(number_ < map->NumberOfOwnDescriptors()); |
| 438 return map->instance_descriptors()->GetFieldIndex(number_); | 459 return map->instance_descriptors()->GetFieldIndex(number_); |
| 439 } | 460 } |
| 440 | 461 |
| 441 void Iterate(ObjectVisitor* visitor); | 462 void Iterate(ObjectVisitor* visitor); |
| 442 | 463 |
| 443 private: | 464 private: |
| 444 Isolate* isolate_; | 465 Isolate* isolate_; |
| 445 LookupResult* next_; | 466 LookupResult* next_; |
| 446 | 467 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 457 JSReceiver* holder_; | 478 JSReceiver* holder_; |
| 458 Map* transition_; | 479 Map* transition_; |
| 459 int number_; | 480 int number_; |
| 460 bool cacheable_; | 481 bool cacheable_; |
| 461 PropertyDetails details_; | 482 PropertyDetails details_; |
| 462 }; | 483 }; |
| 463 | 484 |
| 464 } } // namespace v8::internal | 485 } } // namespace v8::internal |
| 465 | 486 |
| 466 #endif // V8_PROPERTY_H_ | 487 #endif // V8_PROPERTY_H_ |
| OLD | NEW |