OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 SetTargetAtAddress(address, initialize_stub()); | 258 SetTargetAtAddress(address, initialize_stub()); |
259 } | 259 } |
260 | 260 |
261 | 261 |
262 void KeyedStoreIC::Clear(Address address, Code* target) { | 262 void KeyedStoreIC::Clear(Address address, Code* target) { |
263 if (target->ic_state() == UNINITIALIZED) return; | 263 if (target->ic_state() == UNINITIALIZED) return; |
264 SetTargetAtAddress(address, initialize_stub()); | 264 SetTargetAtAddress(address, initialize_stub()); |
265 } | 265 } |
266 | 266 |
267 | 267 |
| 268 static bool HasInterceptorGetter(JSObject* object) { |
| 269 return !object->GetNamedInterceptor()->getter()->IsUndefined(); |
| 270 } |
| 271 |
| 272 |
| 273 static void LookupForRead(Object* object, |
| 274 String* name, |
| 275 LookupResult* lookup) { |
| 276 object->Lookup(name, lookup); |
| 277 if (lookup->IsNotFound() || lookup->type() != INTERCEPTOR) { |
| 278 return; |
| 279 } |
| 280 |
| 281 JSObject* holder = lookup->holder(); |
| 282 if (HasInterceptorGetter(holder)) { |
| 283 return; |
| 284 } |
| 285 |
| 286 // There is no getter, just skip it and lookup down the proto chain |
| 287 holder->LocalLookupRealNamedProperty(name, lookup); |
| 288 if (lookup->IsValid()) { |
| 289 return; |
| 290 } |
| 291 |
| 292 Object* proto = holder->GetPrototype(); |
| 293 if (proto == Heap::null_value()) { |
| 294 return; |
| 295 } |
| 296 |
| 297 LookupForRead(proto, name, lookup); |
| 298 } |
| 299 |
| 300 |
268 Object* CallIC::TryCallAsFunction(Object* object) { | 301 Object* CallIC::TryCallAsFunction(Object* object) { |
269 HandleScope scope; | 302 HandleScope scope; |
270 Handle<Object> target(object); | 303 Handle<Object> target(object); |
271 Handle<Object> delegate = Execution::GetFunctionDelegate(target); | 304 Handle<Object> delegate = Execution::GetFunctionDelegate(target); |
272 | 305 |
273 if (delegate->IsJSFunction()) { | 306 if (delegate->IsJSFunction()) { |
274 // Patch the receiver and use the delegate as the function to | 307 // Patch the receiver and use the delegate as the function to |
275 // invoke. This is used for invoking objects as if they were | 308 // invoke. This is used for invoking objects as if they were |
276 // functions. | 309 // functions. |
277 const int argc = this->target()->arguments_count(); | 310 const int argc = this->target()->arguments_count(); |
(...skipping 27 matching lines...) Expand all Loading... |
305 | 338 |
306 // Try to find a suitable function delegate for the object at hand. | 339 // Try to find a suitable function delegate for the object at hand. |
307 result = TryCallAsFunction(result); | 340 result = TryCallAsFunction(result); |
308 if (result->IsJSFunction()) return result; | 341 if (result->IsJSFunction()) return result; |
309 | 342 |
310 // Otherwise, it will fail in the lookup step. | 343 // Otherwise, it will fail in the lookup step. |
311 } | 344 } |
312 | 345 |
313 // Lookup the property in the object. | 346 // Lookup the property in the object. |
314 LookupResult lookup; | 347 LookupResult lookup; |
315 object->Lookup(*name, &lookup); | 348 LookupForRead(*object, *name, &lookup); |
316 | 349 |
317 if (!lookup.IsValid()) { | 350 if (!lookup.IsValid()) { |
318 // If the object does not have the requested property, check which | 351 // If the object does not have the requested property, check which |
319 // exception we need to throw. | 352 // exception we need to throw. |
320 if (is_contextual()) { | 353 if (is_contextual()) { |
321 return ReferenceError("not_defined", name); | 354 return ReferenceError("not_defined", name); |
322 } | 355 } |
323 return TypeError("undefined_method", object, name); | 356 return TypeError("undefined_method", object, name); |
324 } | 357 } |
325 | 358 |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 // properties. It does not traverse the prototype chain, so the | 470 // properties. It does not traverse the prototype chain, so the |
438 // property must be found in the receiver for the stub to be | 471 // property must be found in the receiver for the stub to be |
439 // applicable. | 472 // applicable. |
440 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 473 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
441 if (lookup->holder() != *receiver) return; | 474 if (lookup->holder() != *receiver) return; |
442 code = StubCache::ComputeCallNormal(argc, in_loop, *name, *receiver); | 475 code = StubCache::ComputeCallNormal(argc, in_loop, *name, *receiver); |
443 } | 476 } |
444 break; | 477 break; |
445 } | 478 } |
446 case INTERCEPTOR: { | 479 case INTERCEPTOR: { |
| 480 ASSERT(HasInterceptorGetter(lookup->holder())); |
447 code = StubCache::ComputeCallInterceptor(argc, *name, *object, | 481 code = StubCache::ComputeCallInterceptor(argc, *name, *object, |
448 lookup->holder()); | 482 lookup->holder()); |
449 break; | 483 break; |
450 } | 484 } |
451 default: | 485 default: |
452 return; | 486 return; |
453 } | 487 } |
454 } | 488 } |
455 | 489 |
456 // If we're unable to compute the stub (not enough memory left), we | 490 // If we're unable to compute the stub (not enough memory left), we |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
523 } | 557 } |
524 } | 558 } |
525 | 559 |
526 // Check if the name is trivially convertible to an index and get | 560 // Check if the name is trivially convertible to an index and get |
527 // the element if so. | 561 // the element if so. |
528 uint32_t index; | 562 uint32_t index; |
529 if (name->AsArrayIndex(&index)) return object->GetElement(index); | 563 if (name->AsArrayIndex(&index)) return object->GetElement(index); |
530 | 564 |
531 // Named lookup in the object. | 565 // Named lookup in the object. |
532 LookupResult lookup; | 566 LookupResult lookup; |
533 object->Lookup(*name, &lookup); | 567 LookupForRead(*object, *name, &lookup); |
534 | 568 |
535 // If lookup is invalid, check if we need to throw an exception. | 569 // If lookup is invalid, check if we need to throw an exception. |
536 if (!lookup.IsValid()) { | 570 if (!lookup.IsValid()) { |
537 if (FLAG_strict || is_contextual()) { | 571 if (FLAG_strict || is_contextual()) { |
538 return ReferenceError("not_defined", name); | 572 return ReferenceError("not_defined", name); |
539 } | 573 } |
540 LOG(SuspectReadEvent(*name, *object)); | 574 LOG(SuspectReadEvent(*name, *object)); |
541 } | 575 } |
542 | 576 |
543 bool can_be_inlined = | 577 bool can_be_inlined = |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
646 case CALLBACKS: { | 680 case CALLBACKS: { |
647 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; | 681 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; |
648 AccessorInfo* callback = | 682 AccessorInfo* callback = |
649 AccessorInfo::cast(lookup->GetCallbackObject()); | 683 AccessorInfo::cast(lookup->GetCallbackObject()); |
650 if (v8::ToCData<Address>(callback->getter()) == 0) return; | 684 if (v8::ToCData<Address>(callback->getter()) == 0) return; |
651 code = StubCache::ComputeLoadCallback(*name, *receiver, | 685 code = StubCache::ComputeLoadCallback(*name, *receiver, |
652 lookup->holder(), callback); | 686 lookup->holder(), callback); |
653 break; | 687 break; |
654 } | 688 } |
655 case INTERCEPTOR: { | 689 case INTERCEPTOR: { |
| 690 ASSERT(HasInterceptorGetter(lookup->holder())); |
656 code = StubCache::ComputeLoadInterceptor(*name, *receiver, | 691 code = StubCache::ComputeLoadInterceptor(*name, *receiver, |
657 lookup->holder()); | 692 lookup->holder()); |
658 break; | 693 break; |
659 } | 694 } |
660 default: | 695 default: |
661 return; | 696 return; |
662 } | 697 } |
663 } | 698 } |
664 | 699 |
665 // If we're unable to compute the stub (not enough memory left), we | 700 // If we're unable to compute the stub (not enough memory left), we |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
737 uint32_t index = 0; | 772 uint32_t index = 0; |
738 if (name->AsArrayIndex(&index)) { | 773 if (name->AsArrayIndex(&index)) { |
739 HandleScope scope; | 774 HandleScope scope; |
740 // Rewrite to the generic keyed load stub. | 775 // Rewrite to the generic keyed load stub. |
741 if (FLAG_use_ic) set_target(generic_stub()); | 776 if (FLAG_use_ic) set_target(generic_stub()); |
742 return Runtime::GetElementOrCharAt(object, index); | 777 return Runtime::GetElementOrCharAt(object, index); |
743 } | 778 } |
744 | 779 |
745 // Named lookup. | 780 // Named lookup. |
746 LookupResult lookup; | 781 LookupResult lookup; |
747 object->Lookup(*name, &lookup); | 782 LookupForRead(*object, *name, &lookup); |
748 | 783 |
749 // If lookup is invalid, check if we need to throw an exception. | 784 // If lookup is invalid, check if we need to throw an exception. |
750 if (!lookup.IsValid()) { | 785 if (!lookup.IsValid()) { |
751 if (FLAG_strict || is_contextual()) { | 786 if (FLAG_strict || is_contextual()) { |
752 return ReferenceError("not_defined", name); | 787 return ReferenceError("not_defined", name); |
753 } | 788 } |
754 } | 789 } |
755 | 790 |
756 // Update the inline cache. | 791 // Update the inline cache. |
757 if (FLAG_use_ic && lookup.IsLoaded()) { | 792 if (FLAG_use_ic && lookup.IsLoaded()) { |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
831 case CALLBACKS: { | 866 case CALLBACKS: { |
832 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; | 867 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; |
833 AccessorInfo* callback = | 868 AccessorInfo* callback = |
834 AccessorInfo::cast(lookup->GetCallbackObject()); | 869 AccessorInfo::cast(lookup->GetCallbackObject()); |
835 if (v8::ToCData<Address>(callback->getter()) == 0) return; | 870 if (v8::ToCData<Address>(callback->getter()) == 0) return; |
836 code = StubCache::ComputeKeyedLoadCallback(*name, *receiver, | 871 code = StubCache::ComputeKeyedLoadCallback(*name, *receiver, |
837 lookup->holder(), callback); | 872 lookup->holder(), callback); |
838 break; | 873 break; |
839 } | 874 } |
840 case INTERCEPTOR: { | 875 case INTERCEPTOR: { |
| 876 ASSERT(HasInterceptorGetter(lookup->holder())); |
841 code = StubCache::ComputeKeyedLoadInterceptor(*name, *receiver, | 877 code = StubCache::ComputeKeyedLoadInterceptor(*name, *receiver, |
842 lookup->holder()); | 878 lookup->holder()); |
843 break; | 879 break; |
844 } | 880 } |
845 default: { | 881 default: { |
846 // Always rewrite to the generic case so that we do not | 882 // Always rewrite to the generic case so that we do not |
847 // repeatedly try to rewrite. | 883 // repeatedly try to rewrite. |
848 code = generic_stub(); | 884 code = generic_stub(); |
849 break; | 885 break; |
850 } | 886 } |
(...skipping 26 matching lines...) Expand all Loading... |
877 // If the property is read-only, we leave the IC in its current | 913 // If the property is read-only, we leave the IC in its current |
878 // state. | 914 // state. |
879 if (lookup->IsReadOnly()) return false; | 915 if (lookup->IsReadOnly()) return false; |
880 | 916 |
881 if (!lookup->IsLoaded()) return false; | 917 if (!lookup->IsLoaded()) return false; |
882 | 918 |
883 return true; | 919 return true; |
884 } | 920 } |
885 | 921 |
886 | 922 |
887 static bool LookupForStoreIC(JSObject* object, | 923 static bool LookupForWrite(JSObject* object, |
888 String* name, | 924 String* name, |
889 LookupResult* lookup) { | 925 LookupResult* lookup) { |
890 object->LocalLookup(name, lookup); | 926 object->LocalLookup(name, lookup); |
891 if (!StoreICableLookup(lookup)) { | 927 if (!StoreICableLookup(lookup)) { |
892 return false; | 928 return false; |
893 } | 929 } |
894 | 930 |
895 if (lookup->type() == INTERCEPTOR) { | 931 if (lookup->type() == INTERCEPTOR) { |
896 if (object->GetNamedInterceptor()->setter()->IsUndefined()) { | 932 if (object->GetNamedInterceptor()->setter()->IsUndefined()) { |
897 object->LocalLookupRealNamedProperty(name, lookup); | 933 object->LocalLookupRealNamedProperty(name, lookup); |
898 return StoreICableLookup(lookup); | 934 return StoreICableLookup(lookup); |
899 } | 935 } |
(...skipping 22 matching lines...) Expand all Loading... |
922 if (name->AsArrayIndex(&index)) { | 958 if (name->AsArrayIndex(&index)) { |
923 HandleScope scope; | 959 HandleScope scope; |
924 Handle<Object> result = SetElement(receiver, index, value); | 960 Handle<Object> result = SetElement(receiver, index, value); |
925 if (result.is_null()) return Failure::Exception(); | 961 if (result.is_null()) return Failure::Exception(); |
926 return *value; | 962 return *value; |
927 } | 963 } |
928 | 964 |
929 // Lookup the property locally in the receiver. | 965 // Lookup the property locally in the receiver. |
930 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { | 966 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { |
931 LookupResult lookup; | 967 LookupResult lookup; |
932 if (LookupForStoreIC(*receiver, *name, &lookup)) { | 968 if (LookupForWrite(*receiver, *name, &lookup)) { |
933 UpdateCaches(&lookup, state, receiver, name, value); | 969 UpdateCaches(&lookup, state, receiver, name, value); |
934 } | 970 } |
935 } | 971 } |
936 | 972 |
937 // Set the property. | 973 // Set the property. |
938 return receiver->SetProperty(*name, *value, NONE); | 974 return receiver->SetProperty(*name, *value, NONE); |
939 } | 975 } |
940 | 976 |
941 | 977 |
942 void StoreIC::UpdateCaches(LookupResult* lookup, | 978 void StoreIC::UpdateCaches(LookupResult* lookup, |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
988 break; | 1024 break; |
989 } | 1025 } |
990 case CALLBACKS: { | 1026 case CALLBACKS: { |
991 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; | 1027 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; |
992 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); | 1028 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); |
993 if (v8::ToCData<Address>(callback->setter()) == 0) return; | 1029 if (v8::ToCData<Address>(callback->setter()) == 0) return; |
994 code = StubCache::ComputeStoreCallback(*name, *receiver, callback); | 1030 code = StubCache::ComputeStoreCallback(*name, *receiver, callback); |
995 break; | 1031 break; |
996 } | 1032 } |
997 case INTERCEPTOR: { | 1033 case INTERCEPTOR: { |
| 1034 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); |
998 code = StubCache::ComputeStoreInterceptor(*name, *receiver); | 1035 code = StubCache::ComputeStoreInterceptor(*name, *receiver); |
999 break; | 1036 break; |
1000 } | 1037 } |
1001 default: | 1038 default: |
1002 return; | 1039 return; |
1003 } | 1040 } |
1004 | 1041 |
1005 // If we're unable to compute the stub (not enough memory left), we | 1042 // If we're unable to compute the stub (not enough memory left), we |
1006 // simply avoid updating the caches. | 1043 // simply avoid updating the caches. |
1007 if (code->IsFailure()) return; | 1044 if (code->IsFailure()) return; |
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1318 #undef ADDR | 1355 #undef ADDR |
1319 }; | 1356 }; |
1320 | 1357 |
1321 | 1358 |
1322 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 1359 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
1323 return IC_utilities[id]; | 1360 return IC_utilities[id]; |
1324 } | 1361 } |
1325 | 1362 |
1326 | 1363 |
1327 } } // namespace v8::internal | 1364 } } // namespace v8::internal |
OLD | NEW |