| 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 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 !current->IsJSGlobalProxy() && | 151 !current->IsJSGlobalProxy() && |
| 152 !current->IsJSGlobalObject()) { | 152 !current->IsJSGlobalObject()) { |
| 153 return true; | 153 return true; |
| 154 } | 154 } |
| 155 } | 155 } |
| 156 | 156 |
| 157 return false; | 157 return false; |
| 158 } | 158 } |
| 159 | 159 |
| 160 | 160 |
| 161 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { | 161 static bool TryRemoveInvalidPrototypeDependentStub(Code* target, |
| 162 IC::State state = target->ic_state(); | 162 Object* receiver, |
| 163 | 163 Object* name) { |
| 164 if (state != MONOMORPHIC || !name->IsString()) return state; | |
| 165 if (receiver->IsUndefined() || receiver->IsNull()) return state; | |
| 166 | |
| 167 InlineCacheHolderFlag cache_holder = | 164 InlineCacheHolderFlag cache_holder = |
| 168 Code::ExtractCacheHolderFromFlags(target->flags()); | 165 Code::ExtractCacheHolderFromFlags(target->flags()); |
| 169 | 166 |
| 170 | |
| 171 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { | 167 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { |
| 172 // The stub was generated for JSObject but called for non-JSObject. | 168 // The stub was generated for JSObject but called for non-JSObject. |
| 173 // IC::GetCodeCacheHolder is not applicable. | 169 // IC::GetCodeCacheHolder is not applicable. |
| 174 return MONOMORPHIC; | 170 return false; |
| 175 } else if (cache_holder == PROTOTYPE_MAP && | 171 } else if (cache_holder == PROTOTYPE_MAP && |
| 176 receiver->GetPrototype()->IsNull()) { | 172 receiver->GetPrototype()->IsNull()) { |
| 177 // IC::GetCodeCacheHolder is not applicable. | 173 // IC::GetCodeCacheHolder is not applicable. |
| 178 return MONOMORPHIC; | 174 return false; |
| 179 } | 175 } |
| 180 Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map(); | 176 Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map(); |
| 181 | 177 |
| 182 // Decide whether the inline cache failed because of changes to the | 178 // Decide whether the inline cache failed because of changes to the |
| 183 // receiver itself or changes to one of its prototypes. | 179 // receiver itself or changes to one of its prototypes. |
| 184 // | 180 // |
| 185 // If there are changes to the receiver itself, the map of the | 181 // If there are changes to the receiver itself, the map of the |
| 186 // receiver will have changed and the current target will not be in | 182 // receiver will have changed and the current target will not be in |
| 187 // the receiver map's code cache. Therefore, if the current target | 183 // the receiver map's code cache. Therefore, if the current target |
| 188 // is in the receiver map's code cache, the inline cache failed due | 184 // is in the receiver map's code cache, the inline cache failed due |
| 189 // to prototype check failure. | 185 // to prototype check failure. |
| 190 int index = map->IndexInCodeCache(name, target); | 186 int index = map->IndexInCodeCache(name, target); |
| 191 if (index >= 0) { | 187 if (index >= 0) { |
| 192 // For keyed load/store/call, the most likely cause of cache failure is | 188 map->RemoveFromCodeCache(String::cast(name), target, index); |
| 193 // that the key has changed. We do not distinguish between | 189 return true; |
| 194 // prototype and non-prototype failures for keyed access. | 190 } |
| 195 Code::Kind kind = target->kind(); | |
| 196 if (kind == Code::KEYED_LOAD_IC || | |
| 197 kind == Code::KEYED_STORE_IC || | |
| 198 kind == Code::KEYED_CALL_IC) { | |
| 199 return MONOMORPHIC; | |
| 200 } | |
| 201 | 191 |
| 202 // Remove the target from the code cache to avoid hitting the same | 192 return false; |
| 203 // invalid stub again. | 193 } |
| 204 map->RemoveFromCodeCache(String::cast(name), target, index); | |
| 205 | 194 |
| 195 |
| 196 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { |
| 197 IC::State state = target->ic_state(); |
| 198 |
| 199 if (state != MONOMORPHIC || !name->IsString()) return state; |
| 200 if (receiver->IsUndefined() || receiver->IsNull()) return state; |
| 201 |
| 202 // For keyed load/store/call, the most likely cause of cache failure is |
| 203 // that the key has changed. We do not distinguish between |
| 204 // prototype and non-prototype failures for keyed access. |
| 205 Code::Kind kind = target->kind(); |
| 206 if (kind == Code::KEYED_LOAD_IC || |
| 207 kind == Code::KEYED_STORE_IC || |
| 208 kind == Code::KEYED_CALL_IC) { |
| 209 return MONOMORPHIC; |
| 210 } |
| 211 |
| 212 // Remove the target from the code cache if it became invalid |
| 213 // because of changes in the prototype chain to avoid hitting it |
| 214 // again. |
| 215 // Call stubs handle this later to allow extra IC state |
| 216 // transitions. |
| 217 if (kind != Code::CALL_IC && |
| 218 TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) { |
| 206 return MONOMORPHIC_PROTOTYPE_FAILURE; | 219 return MONOMORPHIC_PROTOTYPE_FAILURE; |
| 207 } | 220 } |
| 208 | 221 |
| 209 // The builtins object is special. It only changes when JavaScript | 222 // The builtins object is special. It only changes when JavaScript |
| 210 // builtins are loaded lazily. It is important to keep inline | 223 // builtins are loaded lazily. It is important to keep inline |
| 211 // caches for the builtins object monomorphic. Therefore, if we get | 224 // caches for the builtins object monomorphic. Therefore, if we get |
| 212 // an inline cache miss for the builtins object after lazily loading | 225 // an inline cache miss for the builtins object after lazily loading |
| 213 // JavaScript builtins, we return uninitialized as the state to | 226 // JavaScript builtins, we return uninitialized as the state to |
| 214 // force the inline cache back to monomorphic state. | 227 // force the inline cache back to monomorphic state. |
| 215 if (receiver->IsJSBuiltinsObject()) { | 228 if (receiver->IsJSBuiltinsObject()) { |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 PatchInlinedStore(address, HEAP->fixed_array_map()); | 367 PatchInlinedStore(address, HEAP->fixed_array_map()); |
| 355 } | 368 } |
| 356 | 369 |
| 357 | 370 |
| 358 void KeyedStoreIC::Clear(Address address, Code* target) { | 371 void KeyedStoreIC::Clear(Address address, Code* target) { |
| 359 if (target->ic_state() == UNINITIALIZED) return; | 372 if (target->ic_state() == UNINITIALIZED) return; |
| 360 SetTargetAtAddress(address, initialize_stub()); | 373 SetTargetAtAddress(address, initialize_stub()); |
| 361 } | 374 } |
| 362 | 375 |
| 363 | 376 |
| 364 Code* KeyedLoadIC::external_array_stub(JSObject::ElementsKind elements_kind) { | |
| 365 switch (elements_kind) { | |
| 366 case JSObject::EXTERNAL_BYTE_ELEMENTS: | |
| 367 return isolate()->builtins()->builtin( | |
| 368 Builtins::KeyedLoadIC_ExternalByteArray); | |
| 369 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
| 370 return isolate()->builtins()->builtin( | |
| 371 Builtins::KeyedLoadIC_ExternalUnsignedByteArray); | |
| 372 case JSObject::EXTERNAL_SHORT_ELEMENTS: | |
| 373 return isolate()->builtins()->builtin( | |
| 374 Builtins::KeyedLoadIC_ExternalShortArray); | |
| 375 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
| 376 return isolate()->builtins()->builtin( | |
| 377 Builtins::KeyedLoadIC_ExternalUnsignedShortArray); | |
| 378 case JSObject::EXTERNAL_INT_ELEMENTS: | |
| 379 return isolate()->builtins()->builtin( | |
| 380 Builtins::KeyedLoadIC_ExternalIntArray); | |
| 381 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
| 382 return isolate()->builtins()->builtin( | |
| 383 Builtins::KeyedLoadIC_ExternalUnsignedIntArray); | |
| 384 case JSObject::EXTERNAL_FLOAT_ELEMENTS: | |
| 385 return isolate()->builtins()->builtin( | |
| 386 Builtins::KeyedLoadIC_ExternalFloatArray); | |
| 387 default: | |
| 388 UNREACHABLE(); | |
| 389 return NULL; | |
| 390 } | |
| 391 } | |
| 392 | |
| 393 | |
| 394 Code* KeyedStoreIC::external_array_stub(JSObject::ElementsKind elements_kind) { | |
| 395 switch (elements_kind) { | |
| 396 case JSObject::EXTERNAL_BYTE_ELEMENTS: | |
| 397 return isolate()->builtins()->builtin( | |
| 398 Builtins::KeyedStoreIC_ExternalByteArray); | |
| 399 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
| 400 return isolate()->builtins()->builtin( | |
| 401 Builtins::KeyedStoreIC_ExternalUnsignedByteArray); | |
| 402 case JSObject::EXTERNAL_SHORT_ELEMENTS: | |
| 403 return isolate()->builtins()->builtin( | |
| 404 Builtins::KeyedStoreIC_ExternalShortArray); | |
| 405 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
| 406 return isolate()->builtins()->builtin( | |
| 407 Builtins::KeyedStoreIC_ExternalUnsignedShortArray); | |
| 408 case JSObject::EXTERNAL_INT_ELEMENTS: | |
| 409 return isolate()->builtins()->builtin( | |
| 410 Builtins::KeyedStoreIC_ExternalIntArray); | |
| 411 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
| 412 return isolate()->builtins()->builtin( | |
| 413 Builtins::KeyedStoreIC_ExternalUnsignedIntArray); | |
| 414 case JSObject::EXTERNAL_FLOAT_ELEMENTS: | |
| 415 return isolate()->builtins()->builtin( | |
| 416 Builtins::KeyedStoreIC_ExternalFloatArray); | |
| 417 default: | |
| 418 UNREACHABLE(); | |
| 419 return NULL; | |
| 420 } | |
| 421 } | |
| 422 | |
| 423 | |
| 424 static bool HasInterceptorGetter(JSObject* object) { | 377 static bool HasInterceptorGetter(JSObject* object) { |
| 425 return !object->GetNamedInterceptor()->getter()->IsUndefined(); | 378 return !object->GetNamedInterceptor()->getter()->IsUndefined(); |
| 426 } | 379 } |
| 427 | 380 |
| 428 | 381 |
| 429 static void LookupForRead(Object* object, | 382 static void LookupForRead(Object* object, |
| 430 String* name, | 383 String* name, |
| 431 LookupResult* lookup) { | 384 LookupResult* lookup) { |
| 432 AssertNoAllocation no_gc; // pointers must stay valid | 385 AssertNoAllocation no_gc; // pointers must stay valid |
| 433 | 386 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 493 // Change the receiver to the result of calling ToObject on it. | 446 // Change the receiver to the result of calling ToObject on it. |
| 494 const int argc = this->target()->arguments_count(); | 447 const int argc = this->target()->arguments_count(); |
| 495 StackFrameLocator locator; | 448 StackFrameLocator locator; |
| 496 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 449 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
| 497 int index = frame->ComputeExpressionsCount() - (argc + 1); | 450 int index = frame->ComputeExpressionsCount() - (argc + 1); |
| 498 frame->SetExpression(index, *isolate()->factory()->ToObject(object)); | 451 frame->SetExpression(index, *isolate()->factory()->ToObject(object)); |
| 499 } | 452 } |
| 500 | 453 |
| 501 | 454 |
| 502 MaybeObject* CallICBase::LoadFunction(State state, | 455 MaybeObject* CallICBase::LoadFunction(State state, |
| 456 Code::ExtraICState extra_ic_state, |
| 503 Handle<Object> object, | 457 Handle<Object> object, |
| 504 Handle<String> name) { | 458 Handle<String> name) { |
| 505 // If the object is undefined or null it's illegal to try to get any | 459 // If the object is undefined or null it's illegal to try to get any |
| 506 // of its properties; throw a TypeError in that case. | 460 // of its properties; throw a TypeError in that case. |
| 507 if (object->IsUndefined() || object->IsNull()) { | 461 if (object->IsUndefined() || object->IsNull()) { |
| 508 return TypeError("non_object_property_call", object, name); | 462 return TypeError("non_object_property_call", object, name); |
| 509 } | 463 } |
| 510 | 464 |
| 511 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | 465 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { |
| 512 ReceiverToObject(object); | 466 ReceiverToObject(object); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 538 // If the object does not have the requested property, check which | 492 // If the object does not have the requested property, check which |
| 539 // exception we need to throw. | 493 // exception we need to throw. |
| 540 if (IsContextual(object)) { | 494 if (IsContextual(object)) { |
| 541 return ReferenceError("not_defined", name); | 495 return ReferenceError("not_defined", name); |
| 542 } | 496 } |
| 543 return TypeError("undefined_method", object, name); | 497 return TypeError("undefined_method", object, name); |
| 544 } | 498 } |
| 545 | 499 |
| 546 // Lookup is valid: Update inline cache and stub cache. | 500 // Lookup is valid: Update inline cache and stub cache. |
| 547 if (FLAG_use_ic) { | 501 if (FLAG_use_ic) { |
| 548 UpdateCaches(&lookup, state, object, name); | 502 UpdateCaches(&lookup, state, extra_ic_state, object, name); |
| 549 } | 503 } |
| 550 | 504 |
| 551 // Get the property. | 505 // Get the property. |
| 552 PropertyAttributes attr; | 506 PropertyAttributes attr; |
| 553 Object* result; | 507 Object* result; |
| 554 { MaybeObject* maybe_result = | 508 { MaybeObject* maybe_result = |
| 555 object->GetProperty(*object, &lookup, *name, &attr); | 509 object->GetProperty(*object, &lookup, *name, &attr); |
| 556 if (!maybe_result->ToObject(&result)) return maybe_result; | 510 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 557 } | 511 } |
| 558 if (lookup.type() == INTERCEPTOR) { | 512 if (lookup.type() == INTERCEPTOR) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 588 // Try to find a suitable function delegate for the object at hand. | 542 // Try to find a suitable function delegate for the object at hand. |
| 589 result = TryCallAsFunction(result); | 543 result = TryCallAsFunction(result); |
| 590 MaybeObject* answer = result; | 544 MaybeObject* answer = result; |
| 591 if (!result->IsJSFunction()) { | 545 if (!result->IsJSFunction()) { |
| 592 answer = TypeError("property_not_function", object, name); | 546 answer = TypeError("property_not_function", object, name); |
| 593 } | 547 } |
| 594 return answer; | 548 return answer; |
| 595 } | 549 } |
| 596 | 550 |
| 597 | 551 |
| 552 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, |
| 553 Handle<Object> object, |
| 554 Code::ExtraICState* extra_ic_state) { |
| 555 ASSERT(kind_ == Code::CALL_IC); |
| 556 if (lookup->type() != CONSTANT_FUNCTION) return false; |
| 557 JSFunction* function = lookup->GetConstantFunction(); |
| 558 if (!function->shared()->HasBuiltinFunctionId()) return false; |
| 559 |
| 560 // Fetch the arguments passed to the called function. |
| 561 const int argc = target()->arguments_count(); |
| 562 Address entry = isolate()->c_entry_fp(isolate()->thread_local_top()); |
| 563 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); |
| 564 Arguments args(argc + 1, |
| 565 &Memory::Object_at(fp + |
| 566 StandardFrameConstants::kCallerSPOffset + |
| 567 argc * kPointerSize)); |
| 568 switch (function->shared()->builtin_function_id()) { |
| 569 case kStringCharCodeAt: |
| 570 case kStringCharAt: |
| 571 if (object->IsString()) { |
| 572 String* string = String::cast(*object); |
| 573 // Check that there's the right wrapper in the receiver slot. |
| 574 ASSERT(string == JSValue::cast(args[0])->value()); |
| 575 // If we're in the default (fastest) state and the index is |
| 576 // out of bounds, update the state to record this fact. |
| 577 if (*extra_ic_state == DEFAULT_STRING_STUB && |
| 578 argc >= 1 && args[1]->IsNumber()) { |
| 579 double index; |
| 580 if (args[1]->IsSmi()) { |
| 581 index = Smi::cast(args[1])->value(); |
| 582 } else { |
| 583 ASSERT(args[1]->IsHeapNumber()); |
| 584 index = DoubleToInteger(HeapNumber::cast(args[1])->value()); |
| 585 } |
| 586 if (index < 0 || index >= string->length()) { |
| 587 *extra_ic_state = STRING_INDEX_OUT_OF_BOUNDS; |
| 588 return true; |
| 589 } |
| 590 } |
| 591 } |
| 592 break; |
| 593 default: |
| 594 return false; |
| 595 } |
| 596 return false; |
| 597 } |
| 598 |
| 599 |
| 600 MaybeObject* CallICBase::ComputeMonomorphicStub( |
| 601 LookupResult* lookup, |
| 602 State state, |
| 603 Code::ExtraICState extra_ic_state, |
| 604 Handle<Object> object, |
| 605 Handle<String> name) { |
| 606 int argc = target()->arguments_count(); |
| 607 InLoopFlag in_loop = target()->ic_in_loop(); |
| 608 MaybeObject* maybe_code = NULL; |
| 609 switch (lookup->type()) { |
| 610 case FIELD: { |
| 611 int index = lookup->GetFieldIndex(); |
| 612 maybe_code = isolate()->stub_cache()->ComputeCallField(argc, |
| 613 in_loop, |
| 614 kind_, |
| 615 *name, |
| 616 *object, |
| 617 lookup->holder(), |
| 618 index); |
| 619 break; |
| 620 } |
| 621 case CONSTANT_FUNCTION: { |
| 622 // Get the constant function and compute the code stub for this |
| 623 // call; used for rewriting to monomorphic state and making sure |
| 624 // that the code stub is in the stub cache. |
| 625 JSFunction* function = lookup->GetConstantFunction(); |
| 626 maybe_code = |
| 627 isolate()->stub_cache()->ComputeCallConstant(argc, |
| 628 in_loop, |
| 629 kind_, |
| 630 extra_ic_state, |
| 631 *name, |
| 632 *object, |
| 633 lookup->holder(), |
| 634 function); |
| 635 break; |
| 636 } |
| 637 case NORMAL: { |
| 638 if (!object->IsJSObject()) return NULL; |
| 639 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 640 |
| 641 if (lookup->holder()->IsGlobalObject()) { |
| 642 GlobalObject* global = GlobalObject::cast(lookup->holder()); |
| 643 JSGlobalPropertyCell* cell = |
| 644 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); |
| 645 if (!cell->value()->IsJSFunction()) return NULL; |
| 646 JSFunction* function = JSFunction::cast(cell->value()); |
| 647 maybe_code = isolate()->stub_cache()->ComputeCallGlobal(argc, |
| 648 in_loop, |
| 649 kind_, |
| 650 *name, |
| 651 *receiver, |
| 652 global, |
| 653 cell, |
| 654 function); |
| 655 } else { |
| 656 // There is only one shared stub for calling normalized |
| 657 // properties. It does not traverse the prototype chain, so the |
| 658 // property must be found in the receiver for the stub to be |
| 659 // applicable. |
| 660 if (lookup->holder() != *receiver) return NULL; |
| 661 maybe_code = isolate()->stub_cache()->ComputeCallNormal(argc, |
| 662 in_loop, |
| 663 kind_, |
| 664 *name, |
| 665 *receiver); |
| 666 } |
| 667 break; |
| 668 } |
| 669 case INTERCEPTOR: { |
| 670 ASSERT(HasInterceptorGetter(lookup->holder())); |
| 671 maybe_code = isolate()->stub_cache()->ComputeCallInterceptor( |
| 672 argc, |
| 673 kind_, |
| 674 *name, |
| 675 *object, |
| 676 lookup->holder()); |
| 677 break; |
| 678 } |
| 679 default: |
| 680 maybe_code = NULL; |
| 681 break; |
| 682 } |
| 683 return maybe_code; |
| 684 } |
| 685 |
| 686 |
| 598 void CallICBase::UpdateCaches(LookupResult* lookup, | 687 void CallICBase::UpdateCaches(LookupResult* lookup, |
| 599 State state, | 688 State state, |
| 689 Code::ExtraICState extra_ic_state, |
| 600 Handle<Object> object, | 690 Handle<Object> object, |
| 601 Handle<String> name) { | 691 Handle<String> name) { |
| 602 // Bail out if we didn't find a result. | 692 // Bail out if we didn't find a result. |
| 603 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | 693 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
| 604 | 694 |
| 605 if (lookup->holder() != *object && | 695 if (lookup->holder() != *object && |
| 606 HasNormalObjectsInPrototypeChain( | 696 HasNormalObjectsInPrototypeChain( |
| 607 isolate(), lookup, object->GetPrototype())) { | 697 isolate(), lookup, object->GetPrototype())) { |
| 608 // Suppress optimization for prototype chains with slow properties objects | 698 // Suppress optimization for prototype chains with slow properties objects |
| 609 // in the middle. | 699 // in the middle. |
| 610 return; | 700 return; |
| 611 } | 701 } |
| 612 | 702 |
| 613 // Compute the number of arguments. | 703 // Compute the number of arguments. |
| 614 int argc = target()->arguments_count(); | 704 int argc = target()->arguments_count(); |
| 615 InLoopFlag in_loop = target()->ic_in_loop(); | 705 InLoopFlag in_loop = target()->ic_in_loop(); |
| 616 MaybeObject* maybe_code = NULL; | 706 MaybeObject* maybe_code = NULL; |
| 617 Object* code; | 707 bool had_proto_failure = false; |
| 618 if (state == UNINITIALIZED) { | 708 if (state == UNINITIALIZED) { |
| 619 // This is the first time we execute this inline cache. | 709 // This is the first time we execute this inline cache. |
| 620 // Set the target to the pre monomorphic stub to delay | 710 // Set the target to the pre monomorphic stub to delay |
| 621 // setting the monomorphic state. | 711 // setting the monomorphic state. |
| 622 maybe_code = isolate()->stub_cache()->ComputeCallPreMonomorphic(argc, | 712 maybe_code = isolate()->stub_cache()->ComputeCallPreMonomorphic(argc, |
| 623 in_loop, | 713 in_loop, |
| 624 kind_); | 714 kind_); |
| 625 } else if (state == MONOMORPHIC) { | 715 } else if (state == MONOMORPHIC) { |
| 626 maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(argc, | 716 if (kind_ == Code::CALL_IC && |
| 627 in_loop, | 717 TryUpdateExtraICState(lookup, object, &extra_ic_state)) { |
| 628 kind_); | 718 maybe_code = ComputeMonomorphicStub(lookup, |
| 719 state, |
| 720 extra_ic_state, |
| 721 object, |
| 722 name); |
| 723 } else if (kind_ == Code::CALL_IC && |
| 724 TryRemoveInvalidPrototypeDependentStub(target(), |
| 725 *object, |
| 726 *name)) { |
| 727 had_proto_failure = true; |
| 728 maybe_code = ComputeMonomorphicStub(lookup, |
| 729 state, |
| 730 extra_ic_state, |
| 731 object, |
| 732 name); |
| 733 } else { |
| 734 maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(argc, |
| 735 in_loop, |
| 736 kind_); |
| 737 } |
| 629 } else { | 738 } else { |
| 630 // Compute monomorphic stub. | 739 maybe_code = ComputeMonomorphicStub(lookup, |
| 631 switch (lookup->type()) { | 740 state, |
| 632 case FIELD: { | 741 extra_ic_state, |
| 633 int index = lookup->GetFieldIndex(); | 742 object, |
| 634 maybe_code = isolate()->stub_cache()->ComputeCallField(argc, | 743 name); |
| 635 in_loop, | |
| 636 kind_, | |
| 637 *name, | |
| 638 *object, | |
| 639 lookup->holder(), | |
| 640 index); | |
| 641 break; | |
| 642 } | |
| 643 case CONSTANT_FUNCTION: { | |
| 644 // Get the constant function and compute the code stub for this | |
| 645 // call; used for rewriting to monomorphic state and making sure | |
| 646 // that the code stub is in the stub cache. | |
| 647 JSFunction* function = lookup->GetConstantFunction(); | |
| 648 maybe_code = isolate()->stub_cache()->ComputeCallConstant( | |
| 649 argc, | |
| 650 in_loop, | |
| 651 kind_, | |
| 652 *name, | |
| 653 *object, | |
| 654 lookup->holder(), | |
| 655 function); | |
| 656 break; | |
| 657 } | |
| 658 case NORMAL: { | |
| 659 if (!object->IsJSObject()) return; | |
| 660 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
| 661 | |
| 662 if (lookup->holder()->IsGlobalObject()) { | |
| 663 GlobalObject* global = GlobalObject::cast(lookup->holder()); | |
| 664 JSGlobalPropertyCell* cell = | |
| 665 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); | |
| 666 if (!cell->value()->IsJSFunction()) return; | |
| 667 JSFunction* function = JSFunction::cast(cell->value()); | |
| 668 maybe_code = isolate()->stub_cache()->ComputeCallGlobal(argc, | |
| 669 in_loop, | |
| 670 kind_, | |
| 671 *name, | |
| 672 *receiver, | |
| 673 global, | |
| 674 cell, | |
| 675 function); | |
| 676 } else { | |
| 677 // There is only one shared stub for calling normalized | |
| 678 // properties. It does not traverse the prototype chain, so the | |
| 679 // property must be found in the receiver for the stub to be | |
| 680 // applicable. | |
| 681 if (lookup->holder() != *receiver) return; | |
| 682 maybe_code = isolate()->stub_cache()->ComputeCallNormal(argc, | |
| 683 in_loop, | |
| 684 kind_, | |
| 685 *name, | |
| 686 *receiver); | |
| 687 } | |
| 688 break; | |
| 689 } | |
| 690 case INTERCEPTOR: { | |
| 691 ASSERT(HasInterceptorGetter(lookup->holder())); | |
| 692 maybe_code = isolate()->stub_cache()->ComputeCallInterceptor( | |
| 693 argc, | |
| 694 kind_, | |
| 695 *name, | |
| 696 *object, | |
| 697 lookup->holder()); | |
| 698 break; | |
| 699 } | |
| 700 default: | |
| 701 return; | |
| 702 } | |
| 703 } | 744 } |
| 704 | 745 |
| 705 // If we're unable to compute the stub (not enough memory left), we | 746 // If we're unable to compute the stub (not enough memory left), we |
| 706 // simply avoid updating the caches. | 747 // simply avoid updating the caches. |
| 748 Object* code; |
| 707 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | 749 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; |
| 708 | 750 |
| 709 // Patch the call site depending on the state of the cache. | 751 // Patch the call site depending on the state of the cache. |
| 710 if (state == UNINITIALIZED || | 752 if (state == UNINITIALIZED || |
| 711 state == PREMONOMORPHIC || | 753 state == PREMONOMORPHIC || |
| 712 state == MONOMORPHIC || | 754 state == MONOMORPHIC || |
| 713 state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 755 state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
| 714 set_target(Code::cast(code)); | 756 set_target(Code::cast(code)); |
| 715 } else if (state == MEGAMORPHIC) { | 757 } else if (state == MEGAMORPHIC) { |
| 716 // Cache code holding map should be consistent with | 758 // Cache code holding map should be consistent with |
| 717 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. | 759 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. |
| 718 Map* map = JSObject::cast(object->IsJSObject() ? *object : | 760 Map* map = JSObject::cast(object->IsJSObject() ? *object : |
| 719 object->GetPrototype())->map(); | 761 object->GetPrototype())->map(); |
| 720 | 762 |
| 721 // Update the stub cache. | 763 // Update the stub cache. |
| 722 isolate()->stub_cache()->Set(*name, map, Code::cast(code)); | 764 isolate()->stub_cache()->Set(*name, map, Code::cast(code)); |
| 723 } | 765 } |
| 724 | 766 |
| 767 USE(had_proto_failure); |
| 725 #ifdef DEBUG | 768 #ifdef DEBUG |
| 769 if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE; |
| 726 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", | 770 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", |
| 727 name, state, target(), in_loop ? " (in-loop)" : ""); | 771 name, state, target(), in_loop ? " (in-loop)" : ""); |
| 728 #endif | 772 #endif |
| 729 } | 773 } |
| 730 | 774 |
| 731 | 775 |
| 732 MaybeObject* KeyedCallIC::LoadFunction(State state, | 776 MaybeObject* KeyedCallIC::LoadFunction(State state, |
| 733 Handle<Object> object, | 777 Handle<Object> object, |
| 734 Handle<Object> key) { | 778 Handle<Object> key) { |
| 735 if (key->IsSymbol()) { | 779 if (key->IsSymbol()) { |
| 736 return CallICBase::LoadFunction(state, object, Handle<String>::cast(key)); | 780 return CallICBase::LoadFunction(state, |
| 781 Code::kNoExtraICState, |
| 782 object, |
| 783 Handle<String>::cast(key)); |
| 737 } | 784 } |
| 738 | 785 |
| 739 if (object->IsUndefined() || object->IsNull()) { | 786 if (object->IsUndefined() || object->IsNull()) { |
| 740 return TypeError("non_object_property_call", object, key); | 787 return TypeError("non_object_property_call", object, key); |
| 741 } | 788 } |
| 742 | 789 |
| 743 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | 790 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { |
| 744 ReceiverToObject(object); | 791 ReceiverToObject(object); |
| 745 } | 792 } |
| 746 | 793 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 785 MaybeObject* LoadIC::Load(State state, | 832 MaybeObject* LoadIC::Load(State state, |
| 786 Handle<Object> object, | 833 Handle<Object> object, |
| 787 Handle<String> name) { | 834 Handle<String> name) { |
| 788 // If the object is undefined or null it's illegal to try to get any | 835 // If the object is undefined or null it's illegal to try to get any |
| 789 // of its properties; throw a TypeError in that case. | 836 // of its properties; throw a TypeError in that case. |
| 790 if (object->IsUndefined() || object->IsNull()) { | 837 if (object->IsUndefined() || object->IsNull()) { |
| 791 return TypeError("non_object_property_load", object, name); | 838 return TypeError("non_object_property_load", object, name); |
| 792 } | 839 } |
| 793 | 840 |
| 794 if (FLAG_use_ic) { | 841 if (FLAG_use_ic) { |
| 842 Code* non_monomorphic_stub = |
| 843 (state == UNINITIALIZED) ? pre_monomorphic_stub() : megamorphic_stub(); |
| 844 |
| 795 // Use specialized code for getting the length of strings and | 845 // Use specialized code for getting the length of strings and |
| 796 // string wrapper objects. The length property of string wrapper | 846 // string wrapper objects. The length property of string wrapper |
| 797 // objects is read-only and therefore always returns the length of | 847 // objects is read-only and therefore always returns the length of |
| 798 // the underlying string value. See ECMA-262 15.5.5.1. | 848 // the underlying string value. See ECMA-262 15.5.5.1. |
| 799 if ((object->IsString() || object->IsStringWrapper()) && | 849 if ((object->IsString() || object->IsStringWrapper()) && |
| 800 name->Equals(isolate()->heap()->length_symbol())) { | 850 name->Equals(isolate()->heap()->length_symbol())) { |
| 801 HandleScope scope(isolate()); | 851 HandleScope scope(isolate()); |
| 852 #ifdef DEBUG |
| 853 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); |
| 854 #endif |
| 855 if (state == PREMONOMORPHIC) { |
| 856 if (object->IsString()) { |
| 857 Map* map = HeapObject::cast(*object)->map(); |
| 858 const int offset = String::kLengthOffset; |
| 859 PatchInlinedLoad(address(), map, offset); |
| 860 set_target(isolate()->builtins()->builtin( |
| 861 Builtins::LoadIC_StringLength)); |
| 862 } else { |
| 863 set_target(isolate()->builtins()->builtin( |
| 864 Builtins::LoadIC_StringWrapperLength)); |
| 865 } |
| 866 } else if (state == MONOMORPHIC && object->IsStringWrapper()) { |
| 867 set_target(isolate()->builtins()->builtin( |
| 868 Builtins::LoadIC_StringWrapperLength)); |
| 869 } else { |
| 870 set_target(non_monomorphic_stub); |
| 871 } |
| 802 // Get the string if we have a string wrapper object. | 872 // Get the string if we have a string wrapper object. |
| 803 if (object->IsJSValue()) { | 873 if (object->IsJSValue()) { |
| 804 object = Handle<Object>(Handle<JSValue>::cast(object)->value(), | 874 object = Handle<Object>(Handle<JSValue>::cast(object)->value(), |
| 805 isolate()); | 875 isolate()); |
| 806 } | 876 } |
| 807 #ifdef DEBUG | |
| 808 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); | |
| 809 #endif | |
| 810 Map* map = HeapObject::cast(*object)->map(); | |
| 811 if (object->IsString()) { | |
| 812 const int offset = String::kLengthOffset; | |
| 813 PatchInlinedLoad(address(), map, offset); | |
| 814 } | |
| 815 | |
| 816 Code* target = NULL; | |
| 817 target = isolate()->builtins()->builtin( | |
| 818 Builtins::LoadIC_StringLength); | |
| 819 set_target(target); | |
| 820 return Smi::FromInt(String::cast(*object)->length()); | 877 return Smi::FromInt(String::cast(*object)->length()); |
| 821 } | 878 } |
| 822 | 879 |
| 823 // Use specialized code for getting the length of arrays. | 880 // Use specialized code for getting the length of arrays. |
| 824 if (object->IsJSArray() && | 881 if (object->IsJSArray() && |
| 825 name->Equals(isolate()->heap()->length_symbol())) { | 882 name->Equals(isolate()->heap()->length_symbol())) { |
| 826 #ifdef DEBUG | 883 #ifdef DEBUG |
| 827 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); | 884 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); |
| 828 #endif | 885 #endif |
| 829 Map* map = HeapObject::cast(*object)->map(); | 886 if (state == PREMONOMORPHIC) { |
| 830 const int offset = JSArray::kLengthOffset; | 887 Map* map = HeapObject::cast(*object)->map(); |
| 831 PatchInlinedLoad(address(), map, offset); | 888 const int offset = JSArray::kLengthOffset; |
| 832 | 889 PatchInlinedLoad(address(), map, offset); |
| 833 Code* target = isolate()->builtins()->builtin( | 890 set_target(isolate()->builtins()->builtin( |
| 834 Builtins::LoadIC_ArrayLength); | 891 Builtins::LoadIC_ArrayLength)); |
| 835 set_target(target); | 892 } else { |
| 893 set_target(non_monomorphic_stub); |
| 894 } |
| 836 return JSArray::cast(*object)->length(); | 895 return JSArray::cast(*object)->length(); |
| 837 } | 896 } |
| 838 | 897 |
| 839 // Use specialized code for getting prototype of functions. | 898 // Use specialized code for getting prototype of functions. |
| 840 if (object->IsJSFunction() && | 899 if (object->IsJSFunction() && |
| 841 name->Equals(isolate()->heap()->prototype_symbol()) && | 900 name->Equals(isolate()->heap()->prototype_symbol()) && |
| 842 JSFunction::cast(*object)->should_have_prototype()) { | 901 JSFunction::cast(*object)->should_have_prototype()) { |
| 843 #ifdef DEBUG | 902 #ifdef DEBUG |
| 844 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); | 903 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); |
| 845 #endif | 904 #endif |
| 846 Code* target = isolate()->builtins()->builtin( | 905 if (state == PREMONOMORPHIC) { |
| 847 Builtins::LoadIC_FunctionPrototype); | 906 set_target(isolate()->builtins()->builtin( |
| 848 set_target(target); | 907 Builtins::LoadIC_FunctionPrototype)); |
| 908 } else { |
| 909 set_target(non_monomorphic_stub); |
| 910 } |
| 849 return Accessors::FunctionGetPrototype(*object, 0); | 911 return Accessors::FunctionGetPrototype(*object, 0); |
| 850 } | 912 } |
| 851 } | 913 } |
| 852 | 914 |
| 853 // Check if the name is trivially convertible to an index and get | 915 // Check if the name is trivially convertible to an index and get |
| 854 // the element if so. | 916 // the element if so. |
| 855 uint32_t index; | 917 uint32_t index; |
| 856 if (name->AsArrayIndex(&index)) return object->GetElement(index); | 918 if (name->AsArrayIndex(&index)) return object->GetElement(index); |
| 857 | 919 |
| 858 // Named lookup in the object. | 920 // Named lookup in the object. |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1064 if (key->IsSymbol()) { | 1126 if (key->IsSymbol()) { |
| 1065 Handle<String> name = Handle<String>::cast(key); | 1127 Handle<String> name = Handle<String>::cast(key); |
| 1066 | 1128 |
| 1067 // If the object is undefined or null it's illegal to try to get any | 1129 // If the object is undefined or null it's illegal to try to get any |
| 1068 // of its properties; throw a TypeError in that case. | 1130 // of its properties; throw a TypeError in that case. |
| 1069 if (object->IsUndefined() || object->IsNull()) { | 1131 if (object->IsUndefined() || object->IsNull()) { |
| 1070 return TypeError("non_object_property_load", object, name); | 1132 return TypeError("non_object_property_load", object, name); |
| 1071 } | 1133 } |
| 1072 | 1134 |
| 1073 if (FLAG_use_ic) { | 1135 if (FLAG_use_ic) { |
| 1136 // TODO(1073): don't ignore the current stub state. |
| 1137 |
| 1074 // Use specialized code for getting the length of strings. | 1138 // Use specialized code for getting the length of strings. |
| 1075 if (object->IsString() && | 1139 if (object->IsString() && |
| 1076 name->Equals(isolate()->heap()->length_symbol())) { | 1140 name->Equals(isolate()->heap()->length_symbol())) { |
| 1077 Handle<String> string = Handle<String>::cast(object); | 1141 Handle<String> string = Handle<String>::cast(object); |
| 1078 Object* code = NULL; | 1142 Object* code = NULL; |
| 1079 { MaybeObject* maybe_code = | 1143 { MaybeObject* maybe_code = |
| 1080 isolate()->stub_cache()->ComputeKeyedLoadStringLength(*name, | 1144 isolate()->stub_cache()->ComputeKeyedLoadStringLength(*name, |
| 1081 *string); | 1145 *string); |
| 1082 if (!maybe_code->ToObject(&code)) return maybe_code; | 1146 if (!maybe_code->ToObject(&code)) return maybe_code; |
| 1083 } | 1147 } |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1172 // the global object). | 1236 // the global object). |
| 1173 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1237 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
| 1174 | 1238 |
| 1175 if (use_ic) { | 1239 if (use_ic) { |
| 1176 Code* stub = generic_stub(); | 1240 Code* stub = generic_stub(); |
| 1177 if (object->IsString() && key->IsNumber()) { | 1241 if (object->IsString() && key->IsNumber()) { |
| 1178 stub = string_stub(); | 1242 stub = string_stub(); |
| 1179 } else if (object->IsJSObject()) { | 1243 } else if (object->IsJSObject()) { |
| 1180 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1244 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1181 if (receiver->HasExternalArrayElements()) { | 1245 if (receiver->HasExternalArrayElements()) { |
| 1182 stub = external_array_stub(receiver->GetElementsKind()); | 1246 MaybeObject* probe = |
| 1247 isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray( |
| 1248 *receiver, false); |
| 1249 stub = |
| 1250 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1183 } else if (receiver->HasIndexedInterceptor()) { | 1251 } else if (receiver->HasIndexedInterceptor()) { |
| 1184 stub = indexed_interceptor_stub(); | 1252 stub = indexed_interceptor_stub(); |
| 1185 } else if (state == UNINITIALIZED && | 1253 } else if (state == UNINITIALIZED && |
| 1186 key->IsSmi() && | 1254 key->IsSmi() && |
| 1187 receiver->map()->has_fast_elements()) { | 1255 receiver->map()->has_fast_elements()) { |
| 1188 StubCache* stub_cache = isolate()->stub_cache(); | 1256 MaybeObject* probe = |
| 1189 MaybeObject* probe = stub_cache->ComputeKeyedLoadSpecialized(*receiver); | 1257 isolate()->stub_cache()->ComputeKeyedLoadSpecialized(*receiver); |
| 1190 stub = | 1258 stub = |
| 1191 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); | 1259 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1192 } | 1260 } |
| 1193 } | 1261 } |
| 1194 if (stub != NULL) set_target(stub); | 1262 if (stub != NULL) set_target(stub); |
| 1195 | 1263 |
| 1196 #ifdef DEBUG | 1264 #ifdef DEBUG |
| 1197 TraceIC("KeyedLoadIC", key, state, target()); | 1265 TraceIC("KeyedLoadIC", key, state, target()); |
| 1198 #endif // DEBUG | 1266 #endif // DEBUG |
| 1199 | 1267 |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1568 // Do not use ICs for objects that require access checks (including | 1636 // Do not use ICs for objects that require access checks (including |
| 1569 // the global object). | 1637 // the global object). |
| 1570 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1638 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
| 1571 ASSERT(!(use_ic && object->IsJSGlobalProxy())); | 1639 ASSERT(!(use_ic && object->IsJSGlobalProxy())); |
| 1572 | 1640 |
| 1573 if (use_ic) { | 1641 if (use_ic) { |
| 1574 Code* stub = generic_stub(); | 1642 Code* stub = generic_stub(); |
| 1575 if (object->IsJSObject()) { | 1643 if (object->IsJSObject()) { |
| 1576 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1644 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1577 if (receiver->HasExternalArrayElements()) { | 1645 if (receiver->HasExternalArrayElements()) { |
| 1578 stub = external_array_stub(receiver->GetElementsKind()); | 1646 MaybeObject* probe = |
| 1647 isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray( |
| 1648 *receiver, true); |
| 1649 stub = |
| 1650 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1579 } else if (state == UNINITIALIZED && | 1651 } else if (state == UNINITIALIZED && |
| 1580 key->IsSmi() && | 1652 key->IsSmi() && |
| 1581 receiver->map()->has_fast_elements()) { | 1653 receiver->map()->has_fast_elements()) { |
| 1582 MaybeObject* probe = | 1654 MaybeObject* probe = |
| 1583 isolate()->stub_cache()->ComputeKeyedStoreSpecialized(*receiver); | 1655 isolate()->stub_cache()->ComputeKeyedStoreSpecialized(*receiver); |
| 1584 stub = | 1656 stub = |
| 1585 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); | 1657 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1586 } | 1658 } |
| 1587 } | 1659 } |
| 1588 if (stub != NULL) set_target(stub); | 1660 if (stub != NULL) set_target(stub); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1683 } | 1755 } |
| 1684 | 1756 |
| 1685 | 1757 |
| 1686 // Used from ic-<arch>.cc. | 1758 // Used from ic-<arch>.cc. |
| 1687 MUST_USE_RESULT MaybeObject* CallIC_Miss(RUNTIME_CALLING_CONVENTION) { | 1759 MUST_USE_RESULT MaybeObject* CallIC_Miss(RUNTIME_CALLING_CONVENTION) { |
| 1688 RUNTIME_GET_ISOLATE; | 1760 RUNTIME_GET_ISOLATE; |
| 1689 NoHandleAllocation na; | 1761 NoHandleAllocation na; |
| 1690 ASSERT(args.length() == 2); | 1762 ASSERT(args.length() == 2); |
| 1691 CallIC ic(isolate); | 1763 CallIC ic(isolate); |
| 1692 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1764 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1765 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 1766 MaybeObject* maybe_result = ic.LoadFunction(state, |
| 1767 extra_ic_state, |
| 1768 args.at<Object>(0), |
| 1769 args.at<String>(1)); |
| 1693 Object* result; | 1770 Object* result; |
| 1694 { MaybeObject* maybe_result = | 1771 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 1695 ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1)); | |
| 1696 if (!maybe_result->ToObject(&result)) return maybe_result; | |
| 1697 } | |
| 1698 | 1772 |
| 1699 // The first time the inline cache is updated may be the first time the | 1773 // The first time the inline cache is updated may be the first time the |
| 1700 // function it references gets called. If the function was lazily compiled | 1774 // function it references gets called. If the function was lazily compiled |
| 1701 // then the first call will trigger a compilation. We check for this case | 1775 // then the first call will trigger a compilation. We check for this case |
| 1702 // and we do the compilation immediately, instead of waiting for the stub | 1776 // and we do the compilation immediately, instead of waiting for the stub |
| 1703 // currently attached to the JSFunction object to trigger compilation. We | 1777 // currently attached to the JSFunction object to trigger compilation. We |
| 1704 // do this in the case where we know that the inline cache is inside a loop, | 1778 // do this in the case where we know that the inline cache is inside a loop, |
| 1705 // because then we know that we want to optimize the function. | 1779 // because then we know that we want to optimize the function. |
| 1706 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { | 1780 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { |
| 1707 return result; | 1781 return result; |
| (...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2090 } | 2164 } |
| 2091 } | 2165 } |
| 2092 if (type == TRBinaryOpIC::INT32 && | 2166 if (type == TRBinaryOpIC::INT32 && |
| 2093 previous_type == TRBinaryOpIC::INT32) { | 2167 previous_type == TRBinaryOpIC::INT32) { |
| 2094 // We must be here because an operation on two INT32 types overflowed. | 2168 // We must be here because an operation on two INT32 types overflowed. |
| 2095 result_type = TRBinaryOpIC::HEAP_NUMBER; | 2169 result_type = TRBinaryOpIC::HEAP_NUMBER; |
| 2096 } | 2170 } |
| 2097 | 2171 |
| 2098 Handle<Code> code = GetTypeRecordingBinaryOpStub(key, type, result_type); | 2172 Handle<Code> code = GetTypeRecordingBinaryOpStub(key, type, result_type); |
| 2099 if (!code.is_null()) { | 2173 if (!code.is_null()) { |
| 2100 TRBinaryOpIC ic(isolate); | |
| 2101 ic.patch(*code); | |
| 2102 if (FLAG_trace_ic) { | 2174 if (FLAG_trace_ic) { |
| 2103 PrintF("[TypeRecordingBinaryOpIC (%s->(%s->%s))#%s]\n", | 2175 PrintF("[TypeRecordingBinaryOpIC (%s->(%s->%s))#%s]\n", |
| 2104 TRBinaryOpIC::GetName(previous_type), | 2176 TRBinaryOpIC::GetName(previous_type), |
| 2105 TRBinaryOpIC::GetName(type), | 2177 TRBinaryOpIC::GetName(type), |
| 2106 TRBinaryOpIC::GetName(result_type), | 2178 TRBinaryOpIC::GetName(result_type), |
| 2107 Token::Name(op)); | 2179 Token::Name(op)); |
| 2108 } | 2180 } |
| 2181 TRBinaryOpIC ic(isolate); |
| 2182 ic.patch(*code); |
| 2109 | 2183 |
| 2110 // Activate inlined smi code. | 2184 // Activate inlined smi code. |
| 2111 if (previous_type == TRBinaryOpIC::UNINITIALIZED) { | 2185 if (previous_type == TRBinaryOpIC::UNINITIALIZED) { |
| 2112 PatchInlinedSmiCode(ic.address()); | 2186 PatchInlinedSmiCode(ic.address()); |
| 2113 } | 2187 } |
| 2114 } | 2188 } |
| 2115 | 2189 |
| 2116 Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>( | 2190 Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>( |
| 2117 isolate->thread_local_top()->context_->builtins(), isolate); | 2191 isolate->thread_local_top()->context_->builtins(), isolate); |
| 2118 Object* builtin = NULL; // Initialization calms down the compiler. | 2192 Object* builtin = NULL; // Initialization calms down the compiler. |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2231 #undef ADDR | 2305 #undef ADDR |
| 2232 }; | 2306 }; |
| 2233 | 2307 |
| 2234 | 2308 |
| 2235 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2309 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2236 return IC_utilities[id]; | 2310 return IC_utilities[id]; |
| 2237 } | 2311 } |
| 2238 | 2312 |
| 2239 | 2313 |
| 2240 } } // namespace v8::internal | 2314 } } // namespace v8::internal |
| OLD | NEW |