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 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 !current->IsJSGlobalProxy() && | 147 !current->IsJSGlobalProxy() && |
148 !current->IsJSGlobalObject()) { | 148 !current->IsJSGlobalObject()) { |
149 return true; | 149 return true; |
150 } | 150 } |
151 } | 151 } |
152 | 152 |
153 return false; | 153 return false; |
154 } | 154 } |
155 | 155 |
156 | 156 |
157 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { | 157 static bool TryRemoveInvalidPrototypeDependentStub(Code* target, |
158 IC::State state = target->ic_state(); | 158 Object* receiver, |
159 | 159 Object* name) { |
160 if (state != MONOMORPHIC || !name->IsString()) return state; | |
161 if (receiver->IsUndefined() || receiver->IsNull()) return state; | |
162 | |
163 InlineCacheHolderFlag cache_holder = | 160 InlineCacheHolderFlag cache_holder = |
164 Code::ExtractCacheHolderFromFlags(target->flags()); | 161 Code::ExtractCacheHolderFromFlags(target->flags()); |
165 | 162 |
166 | |
167 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { | 163 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { |
168 // The stub was generated for JSObject but called for non-JSObject. | 164 // The stub was generated for JSObject but called for non-JSObject. |
169 // IC::GetCodeCacheHolder is not applicable. | 165 // IC::GetCodeCacheHolder is not applicable. |
170 return MONOMORPHIC; | 166 return false; |
171 } else if (cache_holder == PROTOTYPE_MAP && | 167 } else if (cache_holder == PROTOTYPE_MAP && |
172 receiver->GetPrototype()->IsNull()) { | 168 receiver->GetPrototype()->IsNull()) { |
173 // IC::GetCodeCacheHolder is not applicable. | 169 // IC::GetCodeCacheHolder is not applicable. |
174 return MONOMORPHIC; | 170 return false; |
175 } | 171 } |
176 Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map(); | 172 Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map(); |
177 | 173 |
178 // Decide whether the inline cache failed because of changes to the | 174 // Decide whether the inline cache failed because of changes to the |
179 // receiver itself or changes to one of its prototypes. | 175 // receiver itself or changes to one of its prototypes. |
180 // | 176 // |
181 // If there are changes to the receiver itself, the map of the | 177 // If there are changes to the receiver itself, the map of the |
182 // receiver will have changed and the current target will not be in | 178 // receiver will have changed and the current target will not be in |
183 // the receiver map's code cache. Therefore, if the current target | 179 // the receiver map's code cache. Therefore, if the current target |
184 // is in the receiver map's code cache, the inline cache failed due | 180 // is in the receiver map's code cache, the inline cache failed due |
185 // to prototype check failure. | 181 // to prototype check failure. |
186 int index = map->IndexInCodeCache(name, target); | 182 int index = map->IndexInCodeCache(name, target); |
187 if (index >= 0) { | 183 if (index >= 0) { |
188 // For keyed load/store/call, the most likely cause of cache failure is | 184 map->RemoveFromCodeCache(String::cast(name), target, index); |
189 // that the key has changed. We do not distinguish between | 185 return true; |
190 // prototype and non-prototype failures for keyed access. | 186 } |
191 Code::Kind kind = target->kind(); | |
192 if (kind == Code::KEYED_LOAD_IC || | |
193 kind == Code::KEYED_STORE_IC || | |
194 kind == Code::KEYED_CALL_IC) { | |
195 return MONOMORPHIC; | |
196 } | |
197 | 187 |
198 // Remove the target from the code cache to avoid hitting the same | 188 return false; |
199 // invalid stub again. | 189 } |
200 map->RemoveFromCodeCache(String::cast(name), target, index); | |
201 | 190 |
| 191 |
| 192 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { |
| 193 IC::State state = target->ic_state(); |
| 194 |
| 195 if (state != MONOMORPHIC || !name->IsString()) return state; |
| 196 if (receiver->IsUndefined() || receiver->IsNull()) return state; |
| 197 |
| 198 // For keyed load/store/call, the most likely cause of cache failure is |
| 199 // that the key has changed. We do not distinguish between |
| 200 // prototype and non-prototype failures for keyed access. |
| 201 Code::Kind kind = target->kind(); |
| 202 if (kind == Code::KEYED_LOAD_IC || |
| 203 kind == Code::KEYED_STORE_IC || |
| 204 kind == Code::KEYED_CALL_IC) { |
| 205 return MONOMORPHIC; |
| 206 } |
| 207 |
| 208 // Remove the target from the code cache if it became invalid |
| 209 // because of changes in the prototype chain to avoid hitting it |
| 210 // again. |
| 211 // Call stubs handle this later to allow extra IC state |
| 212 // transitions. |
| 213 if (kind != Code::CALL_IC && |
| 214 TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) { |
202 return MONOMORPHIC_PROTOTYPE_FAILURE; | 215 return MONOMORPHIC_PROTOTYPE_FAILURE; |
203 } | 216 } |
204 | 217 |
205 // The builtins object is special. It only changes when JavaScript | 218 // The builtins object is special. It only changes when JavaScript |
206 // builtins are loaded lazily. It is important to keep inline | 219 // builtins are loaded lazily. It is important to keep inline |
207 // caches for the builtins object monomorphic. Therefore, if we get | 220 // caches for the builtins object monomorphic. Therefore, if we get |
208 // an inline cache miss for the builtins object after lazily loading | 221 // an inline cache miss for the builtins object after lazily loading |
209 // JavaScript builtins, we return uninitialized as the state to | 222 // JavaScript builtins, we return uninitialized as the state to |
210 // force the inline cache back to monomorphic state. | 223 // force the inline cache back to monomorphic state. |
211 if (receiver->IsJSBuiltinsObject()) { | 224 if (receiver->IsJSBuiltinsObject()) { |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
475 // Change the receiver to the result of calling ToObject on it. | 488 // Change the receiver to the result of calling ToObject on it. |
476 const int argc = this->target()->arguments_count(); | 489 const int argc = this->target()->arguments_count(); |
477 StackFrameLocator locator; | 490 StackFrameLocator locator; |
478 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 491 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
479 int index = frame->ComputeExpressionsCount() - (argc + 1); | 492 int index = frame->ComputeExpressionsCount() - (argc + 1); |
480 frame->SetExpression(index, *Factory::ToObject(object)); | 493 frame->SetExpression(index, *Factory::ToObject(object)); |
481 } | 494 } |
482 | 495 |
483 | 496 |
484 MaybeObject* CallICBase::LoadFunction(State state, | 497 MaybeObject* CallICBase::LoadFunction(State state, |
| 498 Code::ExtraICState extra_ic_state, |
485 Handle<Object> object, | 499 Handle<Object> object, |
486 Handle<String> name) { | 500 Handle<String> name) { |
487 // If the object is undefined or null it's illegal to try to get any | 501 // If the object is undefined or null it's illegal to try to get any |
488 // of its properties; throw a TypeError in that case. | 502 // of its properties; throw a TypeError in that case. |
489 if (object->IsUndefined() || object->IsNull()) { | 503 if (object->IsUndefined() || object->IsNull()) { |
490 return TypeError("non_object_property_call", object, name); | 504 return TypeError("non_object_property_call", object, name); |
491 } | 505 } |
492 | 506 |
493 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | 507 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { |
494 ReceiverToObject(object); | 508 ReceiverToObject(object); |
(...skipping 25 matching lines...) Expand all Loading... |
520 // If the object does not have the requested property, check which | 534 // If the object does not have the requested property, check which |
521 // exception we need to throw. | 535 // exception we need to throw. |
522 if (IsContextual(object)) { | 536 if (IsContextual(object)) { |
523 return ReferenceError("not_defined", name); | 537 return ReferenceError("not_defined", name); |
524 } | 538 } |
525 return TypeError("undefined_method", object, name); | 539 return TypeError("undefined_method", object, name); |
526 } | 540 } |
527 | 541 |
528 // Lookup is valid: Update inline cache and stub cache. | 542 // Lookup is valid: Update inline cache and stub cache. |
529 if (FLAG_use_ic) { | 543 if (FLAG_use_ic) { |
530 UpdateCaches(&lookup, state, object, name); | 544 UpdateCaches(&lookup, state, extra_ic_state, object, name); |
531 } | 545 } |
532 | 546 |
533 // Get the property. | 547 // Get the property. |
534 PropertyAttributes attr; | 548 PropertyAttributes attr; |
535 Object* result; | 549 Object* result; |
536 { MaybeObject* maybe_result = | 550 { MaybeObject* maybe_result = |
537 object->GetProperty(*object, &lookup, *name, &attr); | 551 object->GetProperty(*object, &lookup, *name, &attr); |
538 if (!maybe_result->ToObject(&result)) return maybe_result; | 552 if (!maybe_result->ToObject(&result)) return maybe_result; |
539 } | 553 } |
540 if (lookup.type() == INTERCEPTOR) { | 554 if (lookup.type() == INTERCEPTOR) { |
(...skipping 28 matching lines...) Expand all Loading... |
569 // Try to find a suitable function delegate for the object at hand. | 583 // Try to find a suitable function delegate for the object at hand. |
570 result = TryCallAsFunction(result); | 584 result = TryCallAsFunction(result); |
571 MaybeObject* answer = result; | 585 MaybeObject* answer = result; |
572 if (!result->IsJSFunction()) { | 586 if (!result->IsJSFunction()) { |
573 answer = TypeError("property_not_function", object, name); | 587 answer = TypeError("property_not_function", object, name); |
574 } | 588 } |
575 return answer; | 589 return answer; |
576 } | 590 } |
577 | 591 |
578 | 592 |
| 593 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, |
| 594 Handle<Object> object, |
| 595 Code::ExtraICState* extra_ic_state) { |
| 596 ASSERT(kind_ == Code::CALL_IC); |
| 597 if (lookup->type() != CONSTANT_FUNCTION) return false; |
| 598 JSFunction* function = lookup->GetConstantFunction(); |
| 599 if (!function->shared()->HasBuiltinFunctionId()) return false; |
| 600 |
| 601 // Fetch the arguments passed to the called function. |
| 602 const int argc = target()->arguments_count(); |
| 603 Address entry = Top::c_entry_fp(Top::GetCurrentThread()); |
| 604 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); |
| 605 Arguments args(argc + 1, |
| 606 &Memory::Object_at(fp + |
| 607 StandardFrameConstants::kCallerSPOffset + |
| 608 argc * kPointerSize)); |
| 609 switch (function->shared()->builtin_function_id()) { |
| 610 case kStringCharCodeAt: |
| 611 case kStringCharAt: |
| 612 if (object->IsString()) { |
| 613 String* string = String::cast(*object); |
| 614 // Check that there's the right wrapper in the receiver slot. |
| 615 ASSERT(string == JSValue::cast(args[0])->value()); |
| 616 // If we're in the default (fastest) state and the index is |
| 617 // out of bounds, update the state to record this fact. |
| 618 if (*extra_ic_state == DEFAULT_STRING_STUB && |
| 619 argc >= 1 && args[1]->IsNumber()) { |
| 620 double index; |
| 621 if (args[1]->IsSmi()) { |
| 622 index = Smi::cast(args[1])->value(); |
| 623 } else { |
| 624 ASSERT(args[1]->IsHeapNumber()); |
| 625 index = DoubleToInteger(HeapNumber::cast(args[1])->value()); |
| 626 } |
| 627 if (index < 0 || index >= string->length()) { |
| 628 *extra_ic_state = STRING_INDEX_OUT_OF_BOUNDS; |
| 629 return true; |
| 630 } |
| 631 } |
| 632 } |
| 633 break; |
| 634 default: |
| 635 return false; |
| 636 } |
| 637 return false; |
| 638 } |
| 639 |
| 640 |
| 641 MaybeObject* CallICBase::ComputeMonomorphicStub( |
| 642 LookupResult* lookup, |
| 643 State state, |
| 644 Code::ExtraICState extra_ic_state, |
| 645 Handle<Object> object, |
| 646 Handle<String> name) { |
| 647 int argc = target()->arguments_count(); |
| 648 InLoopFlag in_loop = target()->ic_in_loop(); |
| 649 MaybeObject* maybe_code = NULL; |
| 650 switch (lookup->type()) { |
| 651 case FIELD: { |
| 652 int index = lookup->GetFieldIndex(); |
| 653 maybe_code = StubCache::ComputeCallField(argc, |
| 654 in_loop, |
| 655 kind_, |
| 656 *name, |
| 657 *object, |
| 658 lookup->holder(), |
| 659 index); |
| 660 break; |
| 661 } |
| 662 case CONSTANT_FUNCTION: { |
| 663 // Get the constant function and compute the code stub for this |
| 664 // call; used for rewriting to monomorphic state and making sure |
| 665 // that the code stub is in the stub cache. |
| 666 JSFunction* function = lookup->GetConstantFunction(); |
| 667 maybe_code = StubCache::ComputeCallConstant(argc, |
| 668 in_loop, |
| 669 kind_, |
| 670 extra_ic_state, |
| 671 *name, |
| 672 *object, |
| 673 lookup->holder(), |
| 674 function); |
| 675 break; |
| 676 } |
| 677 case NORMAL: { |
| 678 if (!object->IsJSObject()) return NULL; |
| 679 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 680 |
| 681 if (lookup->holder()->IsGlobalObject()) { |
| 682 GlobalObject* global = GlobalObject::cast(lookup->holder()); |
| 683 JSGlobalPropertyCell* cell = |
| 684 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); |
| 685 if (!cell->value()->IsJSFunction()) return NULL; |
| 686 JSFunction* function = JSFunction::cast(cell->value()); |
| 687 maybe_code = StubCache::ComputeCallGlobal(argc, |
| 688 in_loop, |
| 689 kind_, |
| 690 *name, |
| 691 *receiver, |
| 692 global, |
| 693 cell, |
| 694 function); |
| 695 } else { |
| 696 // There is only one shared stub for calling normalized |
| 697 // properties. It does not traverse the prototype chain, so the |
| 698 // property must be found in the receiver for the stub to be |
| 699 // applicable. |
| 700 if (lookup->holder() != *receiver) return NULL; |
| 701 maybe_code = StubCache::ComputeCallNormal(argc, |
| 702 in_loop, |
| 703 kind_, |
| 704 *name, |
| 705 *receiver); |
| 706 } |
| 707 break; |
| 708 } |
| 709 case INTERCEPTOR: { |
| 710 ASSERT(HasInterceptorGetter(lookup->holder())); |
| 711 maybe_code = StubCache::ComputeCallInterceptor(argc, |
| 712 kind_, |
| 713 *name, |
| 714 *object, |
| 715 lookup->holder()); |
| 716 break; |
| 717 } |
| 718 default: |
| 719 maybe_code = NULL; |
| 720 break; |
| 721 } |
| 722 return maybe_code; |
| 723 } |
| 724 |
| 725 |
579 void CallICBase::UpdateCaches(LookupResult* lookup, | 726 void CallICBase::UpdateCaches(LookupResult* lookup, |
580 State state, | 727 State state, |
| 728 Code::ExtraICState extra_ic_state, |
581 Handle<Object> object, | 729 Handle<Object> object, |
582 Handle<String> name) { | 730 Handle<String> name) { |
583 // Bail out if we didn't find a result. | 731 // Bail out if we didn't find a result. |
584 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | 732 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
585 | 733 |
586 if (lookup->holder() != *object && | 734 if (lookup->holder() != *object && |
587 HasNormalObjectsInPrototypeChain(lookup, object->GetPrototype())) { | 735 HasNormalObjectsInPrototypeChain(lookup, object->GetPrototype())) { |
588 // Suppress optimization for prototype chains with slow properties objects | 736 // Suppress optimization for prototype chains with slow properties objects |
589 // in the middle. | 737 // in the middle. |
590 return; | 738 return; |
591 } | 739 } |
592 | 740 |
593 // Compute the number of arguments. | 741 // Compute the number of arguments. |
594 int argc = target()->arguments_count(); | 742 int argc = target()->arguments_count(); |
595 InLoopFlag in_loop = target()->ic_in_loop(); | 743 InLoopFlag in_loop = target()->ic_in_loop(); |
596 MaybeObject* maybe_code = NULL; | 744 MaybeObject* maybe_code = NULL; |
597 Object* code; | 745 bool had_proto_failure = false; |
598 if (state == UNINITIALIZED) { | 746 if (state == UNINITIALIZED) { |
599 // This is the first time we execute this inline cache. | 747 // This is the first time we execute this inline cache. |
600 // Set the target to the pre monomorphic stub to delay | 748 // Set the target to the pre monomorphic stub to delay |
601 // setting the monomorphic state. | 749 // setting the monomorphic state. |
602 maybe_code = StubCache::ComputeCallPreMonomorphic(argc, in_loop, kind_); | 750 maybe_code = StubCache::ComputeCallPreMonomorphic(argc, in_loop, kind_); |
603 } else if (state == MONOMORPHIC) { | 751 } else if (state == MONOMORPHIC) { |
604 maybe_code = StubCache::ComputeCallMegamorphic(argc, in_loop, kind_); | 752 if (kind_ == Code::CALL_IC && |
| 753 TryUpdateExtraICState(lookup, object, &extra_ic_state)) { |
| 754 maybe_code = ComputeMonomorphicStub(lookup, |
| 755 state, |
| 756 extra_ic_state, |
| 757 object, |
| 758 name); |
| 759 } else if (kind_ == Code::CALL_IC && |
| 760 TryRemoveInvalidPrototypeDependentStub(target(), |
| 761 *object, |
| 762 *name)) { |
| 763 had_proto_failure = true; |
| 764 maybe_code = ComputeMonomorphicStub(lookup, |
| 765 state, |
| 766 extra_ic_state, |
| 767 object, |
| 768 name); |
| 769 } else { |
| 770 maybe_code = StubCache::ComputeCallMegamorphic(argc, in_loop, kind_); |
| 771 } |
605 } else { | 772 } else { |
606 // Compute monomorphic stub. | 773 maybe_code = ComputeMonomorphicStub(lookup, |
607 switch (lookup->type()) { | 774 state, |
608 case FIELD: { | 775 extra_ic_state, |
609 int index = lookup->GetFieldIndex(); | 776 object, |
610 maybe_code = StubCache::ComputeCallField(argc, | 777 name); |
611 in_loop, | |
612 kind_, | |
613 *name, | |
614 *object, | |
615 lookup->holder(), | |
616 index); | |
617 break; | |
618 } | |
619 case CONSTANT_FUNCTION: { | |
620 // Get the constant function and compute the code stub for this | |
621 // call; used for rewriting to monomorphic state and making sure | |
622 // that the code stub is in the stub cache. | |
623 JSFunction* function = lookup->GetConstantFunction(); | |
624 maybe_code = StubCache::ComputeCallConstant(argc, | |
625 in_loop, | |
626 kind_, | |
627 *name, | |
628 *object, | |
629 lookup->holder(), | |
630 function); | |
631 break; | |
632 } | |
633 case NORMAL: { | |
634 if (!object->IsJSObject()) return; | |
635 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
636 | |
637 if (lookup->holder()->IsGlobalObject()) { | |
638 GlobalObject* global = GlobalObject::cast(lookup->holder()); | |
639 JSGlobalPropertyCell* cell = | |
640 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); | |
641 if (!cell->value()->IsJSFunction()) return; | |
642 JSFunction* function = JSFunction::cast(cell->value()); | |
643 maybe_code = StubCache::ComputeCallGlobal(argc, | |
644 in_loop, | |
645 kind_, | |
646 *name, | |
647 *receiver, | |
648 global, | |
649 cell, | |
650 function); | |
651 } else { | |
652 // There is only one shared stub for calling normalized | |
653 // properties. It does not traverse the prototype chain, so the | |
654 // property must be found in the receiver for the stub to be | |
655 // applicable. | |
656 if (lookup->holder() != *receiver) return; | |
657 maybe_code = StubCache::ComputeCallNormal(argc, | |
658 in_loop, | |
659 kind_, | |
660 *name, | |
661 *receiver); | |
662 } | |
663 break; | |
664 } | |
665 case INTERCEPTOR: { | |
666 ASSERT(HasInterceptorGetter(lookup->holder())); | |
667 maybe_code = StubCache::ComputeCallInterceptor(argc, | |
668 kind_, | |
669 *name, | |
670 *object, | |
671 lookup->holder()); | |
672 break; | |
673 } | |
674 default: | |
675 return; | |
676 } | |
677 } | 778 } |
678 | 779 |
679 // If we're unable to compute the stub (not enough memory left), we | 780 // If we're unable to compute the stub (not enough memory left), we |
680 // simply avoid updating the caches. | 781 // simply avoid updating the caches. |
| 782 Object* code; |
681 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | 783 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; |
682 | 784 |
683 // Patch the call site depending on the state of the cache. | 785 // Patch the call site depending on the state of the cache. |
684 if (state == UNINITIALIZED || | 786 if (state == UNINITIALIZED || |
685 state == PREMONOMORPHIC || | 787 state == PREMONOMORPHIC || |
686 state == MONOMORPHIC || | 788 state == MONOMORPHIC || |
687 state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 789 state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
688 set_target(Code::cast(code)); | 790 set_target(Code::cast(code)); |
689 } else if (state == MEGAMORPHIC) { | 791 } else if (state == MEGAMORPHIC) { |
690 // Cache code holding map should be consistent with | 792 // Cache code holding map should be consistent with |
691 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. | 793 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. |
692 Map* map = JSObject::cast(object->IsJSObject() ? *object : | 794 Map* map = JSObject::cast(object->IsJSObject() ? *object : |
693 object->GetPrototype())->map(); | 795 object->GetPrototype())->map(); |
694 | 796 |
695 // Update the stub cache. | 797 // Update the stub cache. |
696 StubCache::Set(*name, map, Code::cast(code)); | 798 StubCache::Set(*name, map, Code::cast(code)); |
697 } | 799 } |
698 | 800 |
| 801 USE(had_proto_failure); |
699 #ifdef DEBUG | 802 #ifdef DEBUG |
| 803 if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE; |
700 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", | 804 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", |
701 name, state, target(), in_loop ? " (in-loop)" : ""); | 805 name, state, target(), in_loop ? " (in-loop)" : ""); |
702 #endif | 806 #endif |
703 } | 807 } |
704 | 808 |
705 | 809 |
706 MaybeObject* KeyedCallIC::LoadFunction(State state, | 810 MaybeObject* KeyedCallIC::LoadFunction(State state, |
707 Handle<Object> object, | 811 Handle<Object> object, |
708 Handle<Object> key) { | 812 Handle<Object> key) { |
709 if (key->IsSymbol()) { | 813 if (key->IsSymbol()) { |
710 return CallICBase::LoadFunction(state, object, Handle<String>::cast(key)); | 814 return CallICBase::LoadFunction(state, |
| 815 Code::kNoExtraICState, |
| 816 object, |
| 817 Handle<String>::cast(key)); |
711 } | 818 } |
712 | 819 |
713 if (object->IsUndefined() || object->IsNull()) { | 820 if (object->IsUndefined() || object->IsNull()) { |
714 return TypeError("non_object_property_call", object, key); | 821 return TypeError("non_object_property_call", object, key); |
715 } | 822 } |
716 | 823 |
717 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | 824 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { |
718 ReceiverToObject(object); | 825 ReceiverToObject(object); |
719 } | 826 } |
720 | 827 |
(...skipping 913 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1634 return *function_handle; | 1741 return *function_handle; |
1635 } | 1742 } |
1636 | 1743 |
1637 | 1744 |
1638 // Used from ic-<arch>.cc. | 1745 // Used from ic-<arch>.cc. |
1639 MUST_USE_RESULT MaybeObject* CallIC_Miss(Arguments args) { | 1746 MUST_USE_RESULT MaybeObject* CallIC_Miss(Arguments args) { |
1640 NoHandleAllocation na; | 1747 NoHandleAllocation na; |
1641 ASSERT(args.length() == 2); | 1748 ASSERT(args.length() == 2); |
1642 CallIC ic; | 1749 CallIC ic; |
1643 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1750 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1751 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 1752 MaybeObject* maybe_result = ic.LoadFunction(state, |
| 1753 extra_ic_state, |
| 1754 args.at<Object>(0), |
| 1755 args.at<String>(1)); |
1644 Object* result; | 1756 Object* result; |
1645 { MaybeObject* maybe_result = | 1757 if (!maybe_result->ToObject(&result)) return maybe_result; |
1646 ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1)); | |
1647 if (!maybe_result->ToObject(&result)) return maybe_result; | |
1648 } | |
1649 | 1758 |
1650 // The first time the inline cache is updated may be the first time the | 1759 // The first time the inline cache is updated may be the first time the |
1651 // function it references gets called. If the function was lazily compiled | 1760 // function it references gets called. If the function was lazily compiled |
1652 // then the first call will trigger a compilation. We check for this case | 1761 // then the first call will trigger a compilation. We check for this case |
1653 // and we do the compilation immediately, instead of waiting for the stub | 1762 // and we do the compilation immediately, instead of waiting for the stub |
1654 // currently attached to the JSFunction object to trigger compilation. We | 1763 // currently attached to the JSFunction object to trigger compilation. We |
1655 // do this in the case where we know that the inline cache is inside a loop, | 1764 // do this in the case where we know that the inline cache is inside a loop, |
1656 // because then we know that we want to optimize the function. | 1765 // because then we know that we want to optimize the function. |
1657 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { | 1766 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { |
1658 return result; | 1767 return result; |
(...skipping 505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2164 #undef ADDR | 2273 #undef ADDR |
2165 }; | 2274 }; |
2166 | 2275 |
2167 | 2276 |
2168 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2277 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2169 return IC_utilities[id]; | 2278 return IC_utilities[id]; |
2170 } | 2279 } |
2171 | 2280 |
2172 | 2281 |
2173 } } // namespace v8::internal | 2282 } } // namespace v8::internal |
OLD | NEW |