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 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 Address addr = pc() - Assembler::kCallTargetAddressOffset; | 127 Address addr = pc() - Assembler::kCallTargetAddressOffset; |
128 // Return the address in the original code. This is the place where | 128 // Return the address in the original code. This is the place where |
129 // the call which has been overwritten by the DebugBreakXXX resides | 129 // the call which has been overwritten by the DebugBreakXXX resides |
130 // and the place where the inline cache system should look. | 130 // and the place where the inline cache system should look. |
131 intptr_t delta = | 131 intptr_t delta = |
132 original_code->instruction_start() - code->instruction_start(); | 132 original_code->instruction_start() - code->instruction_start(); |
133 return addr + delta; | 133 return addr + delta; |
134 } | 134 } |
135 #endif | 135 #endif |
136 | 136 |
| 137 |
| 138 static bool HasNormalObjectsInPrototypeChain(LookupResult* lookup, |
| 139 Object* receiver) { |
| 140 Object* end = lookup->IsProperty() ? lookup->holder() : Heap::null_value(); |
| 141 for (Object* current = receiver; |
| 142 current != end; |
| 143 current = current->GetPrototype()) { |
| 144 if (current->IsJSObject() && |
| 145 !JSObject::cast(current)->HasFastProperties() && |
| 146 !current->IsJSGlobalProxy() && |
| 147 !current->IsJSGlobalObject()) { |
| 148 return true; |
| 149 } |
| 150 } |
| 151 |
| 152 return false; |
| 153 } |
| 154 |
| 155 |
137 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { | 156 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { |
138 IC::State state = target->ic_state(); | 157 IC::State state = target->ic_state(); |
139 | 158 |
140 if (state != MONOMORPHIC) return state; | 159 if (state != MONOMORPHIC) return state; |
141 if (receiver->IsUndefined() || receiver->IsNull()) return state; | 160 if (receiver->IsUndefined() || receiver->IsNull()) return state; |
142 | 161 |
143 Map* map = GetCodeCacheMapForObject(receiver); | 162 InlineCacheHolderFlag cache_holder = |
| 163 Code::ExtractCacheHolderFromFlags(target->flags()); |
| 164 |
| 165 |
| 166 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { |
| 167 // The stub was generated for JSObject but called for non-JSObject. |
| 168 // IC::GetCodeCacheMap is not applicable. |
| 169 return MONOMORPHIC; |
| 170 } else if (cache_holder == PROTOTYPE_MAP && |
| 171 receiver->GetPrototype()->IsNull()) { |
| 172 // IC::GetCodeCacheMap is not applicable. |
| 173 return MONOMORPHIC; |
| 174 } |
| 175 Map* map = IC::GetCodeCacheMap(receiver, cache_holder); |
144 | 176 |
145 // Decide whether the inline cache failed because of changes to the | 177 // Decide whether the inline cache failed because of changes to the |
146 // receiver itself or changes to one of its prototypes. | 178 // receiver itself or changes to one of its prototypes. |
147 // | 179 // |
148 // If there are changes to the receiver itself, the map of the | 180 // If there are changes to the receiver itself, the map of the |
149 // receiver will have changed and the current target will not be in | 181 // receiver will have changed and the current target will not be in |
150 // the receiver map's code cache. Therefore, if the current target | 182 // the receiver map's code cache. Therefore, if the current target |
151 // is in the receiver map's code cache, the inline cache failed due | 183 // is in the receiver map's code cache, the inline cache failed due |
152 // to prototype check failure. | 184 // to prototype check failure. |
153 int index = map->IndexInCodeCache(name, target); | 185 int index = map->IndexInCodeCache(name, target); |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
480 } | 512 } |
481 | 513 |
482 // Try to find a suitable function delegate for the object at hand. | 514 // Try to find a suitable function delegate for the object at hand. |
483 result = TryCallAsFunction(result); | 515 result = TryCallAsFunction(result); |
484 return result->IsJSFunction() ? | 516 return result->IsJSFunction() ? |
485 result : TypeError("property_not_function", object, name); | 517 result : TypeError("property_not_function", object, name); |
486 } | 518 } |
487 | 519 |
488 | 520 |
489 void CallICBase::UpdateCaches(LookupResult* lookup, | 521 void CallICBase::UpdateCaches(LookupResult* lookup, |
490 State state, | 522 State state, |
491 Handle<Object> object, | 523 Handle<Object> object, |
492 Handle<String> name) { | 524 Handle<String> name) { |
493 // Bail out if we didn't find a result. | 525 // Bail out if we didn't find a result. |
494 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | 526 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
495 | 527 |
| 528 #ifndef V8_TARGET_ARCH_IA32 |
| 529 // Normal objects only implemented for IA32 by now. |
| 530 if (HasNormalObjectsInPrototypeChain(lookup, *object)) return; |
| 531 #else |
| 532 if (lookup->holder() != *object && |
| 533 HasNormalObjectsInPrototypeChain(lookup, object->GetPrototype())) { |
| 534 // Suppress optimization for prototype chains with slow properties objects |
| 535 // in the middle. |
| 536 return; |
| 537 } |
| 538 #endif |
| 539 |
496 // Compute the number of arguments. | 540 // Compute the number of arguments. |
497 int argc = target()->arguments_count(); | 541 int argc = target()->arguments_count(); |
498 InLoopFlag in_loop = target()->ic_in_loop(); | 542 InLoopFlag in_loop = target()->ic_in_loop(); |
499 Object* code = NULL; | 543 Object* code = NULL; |
500 | 544 |
501 if (state == UNINITIALIZED) { | 545 if (state == UNINITIALIZED) { |
502 // This is the first time we execute this inline cache. | 546 // This is the first time we execute this inline cache. |
503 // Set the target to the pre monomorphic stub to delay | 547 // Set the target to the pre monomorphic stub to delay |
504 // setting the monomorphic state. | 548 // setting the monomorphic state. |
505 code = StubCache::ComputeCallPreMonomorphic(argc, in_loop, kind_); | 549 code = StubCache::ComputeCallPreMonomorphic(argc, in_loop, kind_); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
583 // simply avoid updating the caches. | 627 // simply avoid updating the caches. |
584 if (code == NULL || code->IsFailure()) return; | 628 if (code == NULL || code->IsFailure()) return; |
585 | 629 |
586 // Patch the call site depending on the state of the cache. | 630 // Patch the call site depending on the state of the cache. |
587 if (state == UNINITIALIZED || | 631 if (state == UNINITIALIZED || |
588 state == PREMONOMORPHIC || | 632 state == PREMONOMORPHIC || |
589 state == MONOMORPHIC || | 633 state == MONOMORPHIC || |
590 state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 634 state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
591 set_target(Code::cast(code)); | 635 set_target(Code::cast(code)); |
592 } else if (state == MEGAMORPHIC) { | 636 } else if (state == MEGAMORPHIC) { |
| 637 // Cache code holding map should be consistent with |
| 638 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. |
| 639 Map* map = JSObject::cast(object->IsJSObject() ? *object : |
| 640 object->GetPrototype())->map(); |
| 641 |
593 // Update the stub cache. | 642 // Update the stub cache. |
594 StubCache::Set(*name, GetCodeCacheMapForObject(*object), Code::cast(code)); | 643 StubCache::Set(*name, map, Code::cast(code)); |
595 } | 644 } |
596 | 645 |
597 #ifdef DEBUG | 646 #ifdef DEBUG |
598 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", | 647 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", |
599 name, state, target(), in_loop ? " (in-loop)" : ""); | 648 name, state, target(), in_loop ? " (in-loop)" : ""); |
600 #endif | 649 #endif |
601 } | 650 } |
602 | 651 |
603 | 652 |
604 Object* KeyedCallIC::LoadFunction(State state, | 653 Object* KeyedCallIC::LoadFunction(State state, |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
788 Handle<Object> object, | 837 Handle<Object> object, |
789 Handle<String> name) { | 838 Handle<String> name) { |
790 // Bail out if the result is not cacheable. | 839 // Bail out if the result is not cacheable. |
791 if (!lookup->IsCacheable()) return; | 840 if (!lookup->IsCacheable()) return; |
792 | 841 |
793 // Loading properties from values is not common, so don't try to | 842 // Loading properties from values is not common, so don't try to |
794 // deal with non-JS objects here. | 843 // deal with non-JS objects here. |
795 if (!object->IsJSObject()) return; | 844 if (!object->IsJSObject()) return; |
796 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 845 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
797 | 846 |
| 847 if (HasNormalObjectsInPrototypeChain(lookup, *object)) return; |
| 848 |
798 // Compute the code stub for this load. | 849 // Compute the code stub for this load. |
799 Object* code = NULL; | 850 Object* code = NULL; |
800 if (state == UNINITIALIZED) { | 851 if (state == UNINITIALIZED) { |
801 // This is the first time we execute this inline cache. | 852 // This is the first time we execute this inline cache. |
802 // Set the target to the pre monomorphic stub to delay | 853 // Set the target to the pre monomorphic stub to delay |
803 // setting the monomorphic state. | 854 // setting the monomorphic state. |
804 code = pre_monomorphic_stub(); | 855 code = pre_monomorphic_stub(); |
805 } else if (!lookup->IsProperty()) { | 856 } else if (!lookup->IsProperty()) { |
806 // Nonexistent property. The result is undefined. | 857 // Nonexistent property. The result is undefined. |
807 code = StubCache::ComputeLoadNonexistent(*name, *receiver); | 858 code = StubCache::ComputeLoadNonexistent(*name, *receiver); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
864 // simply avoid updating the caches. | 915 // simply avoid updating the caches. |
865 if (code == NULL || code->IsFailure()) return; | 916 if (code == NULL || code->IsFailure()) return; |
866 | 917 |
867 // Patch the call site depending on the state of the cache. | 918 // Patch the call site depending on the state of the cache. |
868 if (state == UNINITIALIZED || state == PREMONOMORPHIC || | 919 if (state == UNINITIALIZED || state == PREMONOMORPHIC || |
869 state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 920 state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
870 set_target(Code::cast(code)); | 921 set_target(Code::cast(code)); |
871 } else if (state == MONOMORPHIC) { | 922 } else if (state == MONOMORPHIC) { |
872 set_target(megamorphic_stub()); | 923 set_target(megamorphic_stub()); |
873 } else if (state == MEGAMORPHIC) { | 924 } else if (state == MEGAMORPHIC) { |
874 // Update the stub cache. | 925 // Cache code holding map should be consistent with |
875 StubCache::Set(*name, GetCodeCacheMapForObject(*object), Code::cast(code)); | 926 // GenerateMonomorphicCacheProbe. |
| 927 Map* map = JSObject::cast(object->IsJSObject() ? *object : |
| 928 object->GetPrototype())->map(); |
| 929 |
| 930 StubCache::Set(*name, map, Code::cast(code)); |
876 } | 931 } |
877 | 932 |
878 #ifdef DEBUG | 933 #ifdef DEBUG |
879 TraceIC("LoadIC", name, state, target()); | 934 TraceIC("LoadIC", name, state, target()); |
880 #endif | 935 #endif |
881 } | 936 } |
882 | 937 |
883 | 938 |
884 Object* KeyedLoadIC::Load(State state, | 939 Object* KeyedLoadIC::Load(State state, |
885 Handle<Object> object, | 940 Handle<Object> object, |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1011 | 1066 |
1012 | 1067 |
1013 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, | 1068 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, |
1014 Handle<Object> object, Handle<String> name) { | 1069 Handle<Object> object, Handle<String> name) { |
1015 // Bail out if we didn't find a result. | 1070 // Bail out if we didn't find a result. |
1016 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | 1071 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
1017 | 1072 |
1018 if (!object->IsJSObject()) return; | 1073 if (!object->IsJSObject()) return; |
1019 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1074 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
1020 | 1075 |
| 1076 if (HasNormalObjectsInPrototypeChain(lookup, *object)) return; |
| 1077 |
1021 // Compute the code stub for this load. | 1078 // Compute the code stub for this load. |
1022 Object* code = NULL; | 1079 Object* code = NULL; |
1023 | 1080 |
1024 if (state == UNINITIALIZED) { | 1081 if (state == UNINITIALIZED) { |
1025 // This is the first time we execute this inline cache. | 1082 // This is the first time we execute this inline cache. |
1026 // Set the target to the pre monomorphic stub to delay | 1083 // Set the target to the pre monomorphic stub to delay |
1027 // setting the monomorphic state. | 1084 // setting the monomorphic state. |
1028 code = pre_monomorphic_stub(); | 1085 code = pre_monomorphic_stub(); |
1029 } else { | 1086 } else { |
1030 // Compute a monomorphic stub. | 1087 // Compute a monomorphic stub. |
(...skipping 590 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1621 #undef ADDR | 1678 #undef ADDR |
1622 }; | 1679 }; |
1623 | 1680 |
1624 | 1681 |
1625 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 1682 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
1626 return IC_utilities[id]; | 1683 return IC_utilities[id]; |
1627 } | 1684 } |
1628 | 1685 |
1629 | 1686 |
1630 } } // namespace v8::internal | 1687 } } // namespace v8::internal |
OLD | NEW |