| 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 |