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