| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 417 // Don't clear debug break inline cache as it will remove the break point. | 417 // Don't clear debug break inline cache as it will remove the break point. |
| 418 if (target->is_debug_stub()) return; | 418 if (target->is_debug_stub()) return; |
| 419 | 419 |
| 420 switch (target->kind()) { | 420 switch (target->kind()) { |
| 421 case Code::LOAD_IC: return LoadIC::Clear(isolate, address, target); | 421 case Code::LOAD_IC: return LoadIC::Clear(isolate, address, target); |
| 422 case Code::KEYED_LOAD_IC: | 422 case Code::KEYED_LOAD_IC: |
| 423 return KeyedLoadIC::Clear(isolate, address, target); | 423 return KeyedLoadIC::Clear(isolate, address, target); |
| 424 case Code::STORE_IC: return StoreIC::Clear(isolate, address, target); | 424 case Code::STORE_IC: return StoreIC::Clear(isolate, address, target); |
| 425 case Code::KEYED_STORE_IC: | 425 case Code::KEYED_STORE_IC: |
| 426 return KeyedStoreIC::Clear(isolate, address, target); | 426 return KeyedStoreIC::Clear(isolate, address, target); |
| 427 case Code::CALL_IC: return CallIC::Clear(address, target); | |
| 428 case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); | |
| 429 case Code::COMPARE_IC: return CompareIC::Clear(isolate, address, target); | 427 case Code::COMPARE_IC: return CompareIC::Clear(isolate, address, target); |
| 430 case Code::COMPARE_NIL_IC: return CompareNilIC::Clear(address, target); | 428 case Code::COMPARE_NIL_IC: return CompareNilIC::Clear(address, target); |
| 431 case Code::BINARY_OP_IC: | 429 case Code::BINARY_OP_IC: |
| 432 case Code::TO_BOOLEAN_IC: | 430 case Code::TO_BOOLEAN_IC: |
| 433 // Clearing these is tricky and does not | 431 // Clearing these is tricky and does not |
| 434 // make any performance difference. | 432 // make any performance difference. |
| 435 return; | 433 return; |
| 436 default: UNREACHABLE(); | 434 default: UNREACHABLE(); |
| 437 } | 435 } |
| 438 } | 436 } |
| 439 | 437 |
| 440 | 438 |
| 441 void CallICBase::Clear(Address address, Code* target) { | |
| 442 if (IsCleared(target)) return; | |
| 443 Code* code = target->GetIsolate()->stub_cache()->FindCallInitialize( | |
| 444 target->arguments_count(), target->kind()); | |
| 445 SetTargetAtAddress(address, code); | |
| 446 } | |
| 447 | |
| 448 | |
| 449 void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target) { | 439 void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target) { |
| 450 if (IsCleared(target)) return; | 440 if (IsCleared(target)) return; |
| 451 // Make sure to also clear the map used in inline fast cases. If we | 441 // Make sure to also clear the map used in inline fast cases. If we |
| 452 // do not clear these maps, cached code can keep objects alive | 442 // do not clear these maps, cached code can keep objects alive |
| 453 // through the embedded maps. | 443 // through the embedded maps. |
| 454 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate)); | 444 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate)); |
| 455 } | 445 } |
| 456 | 446 |
| 457 | 447 |
| 458 void LoadIC::Clear(Isolate* isolate, Address address, Code* target) { | 448 void LoadIC::Clear(Isolate* isolate, Address address, Code* target) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 485 Token::Value op; | 475 Token::Value op; |
| 486 ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL, | 476 ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL, |
| 487 &handler_state, &op); | 477 &handler_state, &op); |
| 488 // Only clear CompareICs that can retain objects. | 478 // Only clear CompareICs that can retain objects. |
| 489 if (handler_state != KNOWN_OBJECT) return; | 479 if (handler_state != KNOWN_OBJECT) return; |
| 490 SetTargetAtAddress(address, GetRawUninitialized(isolate, op)); | 480 SetTargetAtAddress(address, GetRawUninitialized(isolate, op)); |
| 491 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); | 481 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); |
| 492 } | 482 } |
| 493 | 483 |
| 494 | 484 |
| 495 Handle<Object> CallICBase::TryCallAsFunction(Handle<Object> object) { | |
| 496 Handle<Object> delegate = Execution::GetFunctionDelegate(isolate(), object); | |
| 497 | |
| 498 if (delegate->IsJSFunction() && !object->IsJSFunctionProxy()) { | |
| 499 // Patch the receiver and use the delegate as the function to | |
| 500 // invoke. This is used for invoking objects as if they were functions. | |
| 501 const int argc = target()->arguments_count(); | |
| 502 StackFrameLocator locator(isolate()); | |
| 503 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | |
| 504 int index = frame->ComputeExpressionsCount() - (argc + 1); | |
| 505 frame->SetExpression(index, *object); | |
| 506 } | |
| 507 | |
| 508 return delegate; | |
| 509 } | |
| 510 | |
| 511 | |
| 512 void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee, | |
| 513 Handle<Object> object) { | |
| 514 while (callee->IsJSFunctionProxy()) { | |
| 515 callee = Handle<Object>(JSFunctionProxy::cast(*callee)->call_trap(), | |
| 516 isolate()); | |
| 517 } | |
| 518 | |
| 519 if (callee->IsJSFunction()) { | |
| 520 Handle<JSFunction> function = Handle<JSFunction>::cast(callee); | |
| 521 if (!function->shared()->is_classic_mode() || function->IsBuiltin()) { | |
| 522 // Do not wrap receiver for strict mode functions or for builtins. | |
| 523 return; | |
| 524 } | |
| 525 } | |
| 526 | |
| 527 // And only wrap string, number or boolean. | |
| 528 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | |
| 529 // Change the receiver to the result of calling ToObject on it. | |
| 530 const int argc = this->target()->arguments_count(); | |
| 531 StackFrameLocator locator(isolate()); | |
| 532 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | |
| 533 int index = frame->ComputeExpressionsCount() - (argc + 1); | |
| 534 frame->SetExpression(index, *isolate()->factory()->ToObject(object)); | |
| 535 } | |
| 536 } | |
| 537 | |
| 538 | |
| 539 static bool MigrateDeprecated(Handle<Object> object) { | 485 static bool MigrateDeprecated(Handle<Object> object) { |
| 540 if (!object->IsJSObject()) return false; | 486 if (!object->IsJSObject()) return false; |
| 541 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 487 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 542 if (!receiver->map()->is_deprecated()) return false; | 488 if (!receiver->map()->is_deprecated()) return false; |
| 543 JSObject::MigrateInstance(Handle<JSObject>::cast(object)); | 489 JSObject::MigrateInstance(Handle<JSObject>::cast(object)); |
| 544 return true; | 490 return true; |
| 545 } | 491 } |
| 546 | 492 |
| 547 | 493 |
| 548 MaybeObject* CallICBase::LoadFunction(Handle<Object> object, | |
| 549 Handle<String> name) { | |
| 550 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic; | |
| 551 | |
| 552 // If the object is undefined or null it's illegal to try to get any | |
| 553 // of its properties; throw a TypeError in that case. | |
| 554 if (object->IsUndefined() || object->IsNull()) { | |
| 555 return TypeError("non_object_property_call", object, name); | |
| 556 } | |
| 557 | |
| 558 // Check if the name is trivially convertible to an index and get | |
| 559 // the element if so. | |
| 560 uint32_t index; | |
| 561 if (name->AsArrayIndex(&index)) { | |
| 562 Handle<Object> result = Object::GetElement(isolate(), object, index); | |
| 563 RETURN_IF_EMPTY_HANDLE(isolate(), result); | |
| 564 if (result->IsJSFunction()) return *result; | |
| 565 | |
| 566 // Try to find a suitable function delegate for the object at hand. | |
| 567 result = TryCallAsFunction(result); | |
| 568 if (result->IsJSFunction()) return *result; | |
| 569 | |
| 570 // Otherwise, it will fail in the lookup step. | |
| 571 } | |
| 572 | |
| 573 // Lookup the property in the object. | |
| 574 LookupResult lookup(isolate()); | |
| 575 LookupForRead(object, name, &lookup); | |
| 576 | |
| 577 if (!lookup.IsFound()) { | |
| 578 // If the object does not have the requested property, check which | |
| 579 // exception we need to throw. | |
| 580 return object->IsGlobalObject() | |
| 581 ? ReferenceError("not_defined", name) | |
| 582 : TypeError("undefined_method", object, name); | |
| 583 } | |
| 584 | |
| 585 // Lookup is valid: Update inline cache and stub cache. | |
| 586 if (use_ic) UpdateCaches(&lookup, object, name); | |
| 587 | |
| 588 // Get the property. | |
| 589 PropertyAttributes attr; | |
| 590 Handle<Object> result = | |
| 591 Object::GetProperty(object, object, &lookup, name, &attr); | |
| 592 RETURN_IF_EMPTY_HANDLE(isolate(), result); | |
| 593 | |
| 594 if (lookup.IsInterceptor() && attr == ABSENT) { | |
| 595 // If the object does not have the requested property, check which | |
| 596 // exception we need to throw. | |
| 597 return object->IsGlobalObject() | |
| 598 ? ReferenceError("not_defined", name) | |
| 599 : TypeError("undefined_method", object, name); | |
| 600 } | |
| 601 | |
| 602 ASSERT(!result->IsTheHole()); | |
| 603 | |
| 604 // Make receiver an object if the callee requires it. Strict mode or builtin | |
| 605 // functions do not wrap the receiver, non-strict functions and objects | |
| 606 // called as functions do. | |
| 607 ReceiverToObjectIfRequired(result, object); | |
| 608 | |
| 609 if (result->IsJSFunction()) { | |
| 610 Handle<JSFunction> function = Handle<JSFunction>::cast(result); | |
| 611 #ifdef ENABLE_DEBUGGER_SUPPORT | |
| 612 // Handle stepping into a function if step into is active. | |
| 613 Debug* debug = isolate()->debug(); | |
| 614 if (debug->StepInActive()) { | |
| 615 // Protect the result in a handle as the debugger can allocate and might | |
| 616 // cause GC. | |
| 617 debug->HandleStepIn(function, object, fp(), false); | |
| 618 } | |
| 619 #endif | |
| 620 return *function; | |
| 621 } | |
| 622 | |
| 623 // Try to find a suitable function delegate for the object at hand. | |
| 624 result = TryCallAsFunction(result); | |
| 625 if (result->IsJSFunction()) return *result; | |
| 626 | |
| 627 return TypeError("property_not_function", object, name); | |
| 628 } | |
| 629 | |
| 630 | |
| 631 Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup, | |
| 632 Handle<Object> object, | |
| 633 Handle<String> name) { | |
| 634 int argc = target()->arguments_count(); | |
| 635 Handle<JSObject> holder(lookup->holder(), isolate()); | |
| 636 switch (lookup->type()) { | |
| 637 case FIELD: { | |
| 638 PropertyIndex index = lookup->GetFieldIndex(); | |
| 639 return isolate()->stub_cache()->ComputeCallField( | |
| 640 argc, kind_, extra_ic_state(), name, object, holder, index); | |
| 641 } | |
| 642 case CONSTANT: { | |
| 643 if (!lookup->IsConstantFunction()) return Handle<Code>::null(); | |
| 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 Handle<JSFunction> function(lookup->GetConstantFunction(), isolate()); | |
| 648 return isolate()->stub_cache()->ComputeCallConstant( | |
| 649 argc, kind_, extra_ic_state(), name, object, holder, function); | |
| 650 } | |
| 651 case NORMAL: { | |
| 652 // If we return a null handle, the IC will not be patched. | |
| 653 if (!object->IsJSObject()) return Handle<Code>::null(); | |
| 654 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
| 655 | |
| 656 if (holder->IsGlobalObject()) { | |
| 657 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); | |
| 658 Handle<PropertyCell> cell( | |
| 659 global->GetPropertyCell(lookup), isolate()); | |
| 660 if (!cell->value()->IsJSFunction()) return Handle<Code>::null(); | |
| 661 Handle<JSFunction> function(JSFunction::cast(cell->value())); | |
| 662 return isolate()->stub_cache()->ComputeCallGlobal( | |
| 663 argc, kind_, extra_ic_state(), name, | |
| 664 receiver, global, cell, function); | |
| 665 } else { | |
| 666 // There is only one shared stub for calling normalized | |
| 667 // properties. It does not traverse the prototype chain, so the | |
| 668 // property must be found in the receiver for the stub to be | |
| 669 // applicable. | |
| 670 if (!holder.is_identical_to(receiver)) return Handle<Code>::null(); | |
| 671 return isolate()->stub_cache()->ComputeCallNormal( | |
| 672 argc, kind_, extra_ic_state()); | |
| 673 } | |
| 674 break; | |
| 675 } | |
| 676 case INTERCEPTOR: | |
| 677 ASSERT(HasInterceptorGetter(*holder)); | |
| 678 return isolate()->stub_cache()->ComputeCallInterceptor( | |
| 679 argc, kind_, extra_ic_state(), name, object, holder); | |
| 680 default: | |
| 681 return Handle<Code>::null(); | |
| 682 } | |
| 683 } | |
| 684 | |
| 685 | |
| 686 Handle<Code> CallICBase::megamorphic_stub() { | |
| 687 return isolate()->stub_cache()->ComputeCallMegamorphic( | |
| 688 target()->arguments_count(), kind_, extra_ic_state()); | |
| 689 } | |
| 690 | |
| 691 | |
| 692 Handle<Code> CallICBase::pre_monomorphic_stub() { | |
| 693 return isolate()->stub_cache()->ComputeCallPreMonomorphic( | |
| 694 target()->arguments_count(), kind_, extra_ic_state()); | |
| 695 } | |
| 696 | |
| 697 | |
| 698 void CallICBase::UpdateCaches(LookupResult* lookup, | |
| 699 Handle<Object> object, | |
| 700 Handle<String> name) { | |
| 701 // Bail out if we didn't find a result. | |
| 702 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | |
| 703 | |
| 704 if (state() == UNINITIALIZED) { | |
| 705 set_target(*pre_monomorphic_stub()); | |
| 706 TRACE_IC("CallIC", name); | |
| 707 return; | |
| 708 } | |
| 709 | |
| 710 Handle<Code> code = ComputeMonomorphicStub(lookup, object, name); | |
| 711 // If there's no appropriate stub we simply avoid updating the caches. | |
| 712 // TODO(verwaest): Install a slow fallback in this case to avoid not learning, | |
| 713 // and deopting Crankshaft code. | |
| 714 if (code.is_null()) return; | |
| 715 | |
| 716 Handle<JSObject> cache_object = object->IsJSObject() | |
| 717 ? Handle<JSObject>::cast(object) | |
| 718 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())), | |
| 719 isolate()); | |
| 720 | |
| 721 PatchCache(CurrentTypeOf(cache_object, isolate()), name, code); | |
| 722 TRACE_IC("CallIC", name); | |
| 723 } | |
| 724 | |
| 725 | |
| 726 MaybeObject* KeyedCallIC::LoadFunction(Handle<Object> object, | |
| 727 Handle<Object> key) { | |
| 728 if (key->IsInternalizedString()) { | |
| 729 return CallICBase::LoadFunction(object, Handle<String>::cast(key)); | |
| 730 } | |
| 731 | |
| 732 if (object->IsUndefined() || object->IsNull()) { | |
| 733 return TypeError("non_object_property_call", object, key); | |
| 734 } | |
| 735 | |
| 736 bool use_ic = MigrateDeprecated(object) | |
| 737 ? false : FLAG_use_ic && !object->IsAccessCheckNeeded(); | |
| 738 | |
| 739 if (use_ic && state() != MEGAMORPHIC) { | |
| 740 ASSERT(!object->IsJSGlobalProxy()); | |
| 741 int argc = target()->arguments_count(); | |
| 742 Handle<Code> stub; | |
| 743 | |
| 744 // Use the KeyedArrayCallStub if the call is of the form array[smi](...), | |
| 745 // where array is an instance of one of the initial array maps (without | |
| 746 // extra named properties). | |
| 747 // TODO(verwaest): Also support keyed calls on instances of other maps. | |
| 748 if (object->IsJSArray() && key->IsSmi()) { | |
| 749 Handle<JSArray> array = Handle<JSArray>::cast(object); | |
| 750 ElementsKind kind = array->map()->elements_kind(); | |
| 751 if (IsFastObjectElementsKind(kind) && | |
| 752 array->map() == isolate()->get_initial_js_array_map(kind)) { | |
| 753 KeyedArrayCallStub stub_gen(IsHoleyElementsKind(kind), argc); | |
| 754 stub = stub_gen.GetCode(isolate()); | |
| 755 } | |
| 756 } | |
| 757 | |
| 758 if (stub.is_null()) { | |
| 759 stub = isolate()->stub_cache()->ComputeCallMegamorphic( | |
| 760 argc, Code::KEYED_CALL_IC, kNoExtraICState); | |
| 761 if (object->IsJSObject()) { | |
| 762 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
| 763 if (receiver->elements()->map() == | |
| 764 isolate()->heap()->non_strict_arguments_elements_map()) { | |
| 765 stub = isolate()->stub_cache()->ComputeCallArguments(argc); | |
| 766 } | |
| 767 } | |
| 768 ASSERT(!stub.is_null()); | |
| 769 } | |
| 770 set_target(*stub); | |
| 771 TRACE_IC("CallIC", key); | |
| 772 } | |
| 773 | |
| 774 Handle<Object> result = GetProperty(isolate(), object, key); | |
| 775 RETURN_IF_EMPTY_HANDLE(isolate(), result); | |
| 776 | |
| 777 // Make receiver an object if the callee requires it. Strict mode or builtin | |
| 778 // functions do not wrap the receiver, non-strict functions and objects | |
| 779 // called as functions do. | |
| 780 ReceiverToObjectIfRequired(result, object); | |
| 781 if (result->IsJSFunction()) return *result; | |
| 782 | |
| 783 result = TryCallAsFunction(result); | |
| 784 if (result->IsJSFunction()) return *result; | |
| 785 | |
| 786 return TypeError("property_not_function", object, key); | |
| 787 } | |
| 788 | |
| 789 | |
| 790 MaybeObject* LoadIC::Load(Handle<Object> object, | 494 MaybeObject* LoadIC::Load(Handle<Object> object, |
| 791 Handle<String> name) { | 495 Handle<String> name) { |
| 792 // If the object is undefined or null it's illegal to try to get any | 496 // If the object is undefined or null it's illegal to try to get any |
| 793 // of its properties; throw a TypeError in that case. | 497 // of its properties; throw a TypeError in that case. |
| 794 if (object->IsUndefined() || object->IsNull()) { | 498 if (object->IsUndefined() || object->IsNull()) { |
| 795 return TypeError("non_object_property_load", object, name); | 499 return TypeError("non_object_property_load", object, name); |
| 796 } | 500 } |
| 797 | 501 |
| 798 if (FLAG_use_ic) { | 502 if (FLAG_use_ic) { |
| 799 // Use specialized code for getting the length of strings and | 503 // Use specialized code for getting the length of strings and |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 873 // Get the property. | 577 // Get the property. |
| 874 Handle<Object> result = | 578 Handle<Object> result = |
| 875 Object::GetProperty(object, object, &lookup, name, &attr); | 579 Object::GetProperty(object, object, &lookup, name, &attr); |
| 876 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 580 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 877 // If the property is not present, check if we need to throw an | 581 // If the property is not present, check if we need to throw an |
| 878 // exception. | 582 // exception. |
| 879 if ((lookup.IsInterceptor() || lookup.IsHandler()) && | 583 if ((lookup.IsInterceptor() || lookup.IsHandler()) && |
| 880 attr == ABSENT && IsUndeclaredGlobal(object)) { | 584 attr == ABSENT && IsUndeclaredGlobal(object)) { |
| 881 return ReferenceError("not_defined", name); | 585 return ReferenceError("not_defined", name); |
| 882 } | 586 } |
| 587 |
| 883 return *result; | 588 return *result; |
| 884 } | 589 } |
| 885 | 590 |
| 886 | 591 |
| 887 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, | 592 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, |
| 888 Handle<Map> new_receiver_map) { | 593 Handle<Map> new_receiver_map) { |
| 889 ASSERT(!new_receiver_map.is_null()); | 594 ASSERT(!new_receiver_map.is_null()); |
| 890 for (int current = 0; current < receiver_maps->length(); ++current) { | 595 for (int current = 0; current < receiver_maps->length(); ++current) { |
| 891 if (!receiver_maps->at(current).is_null() && | 596 if (!receiver_maps->at(current).is_null() && |
| 892 receiver_maps->at(current).is_identical_to(new_receiver_map)) { | 597 receiver_maps->at(current).is_identical_to(new_receiver_map)) { |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1020 Handle<Code> code) { | 725 Handle<Code> code) { |
| 1021 switch (state()) { | 726 switch (state()) { |
| 1022 case UNINITIALIZED: | 727 case UNINITIALIZED: |
| 1023 case PREMONOMORPHIC: | 728 case PREMONOMORPHIC: |
| 1024 case MONOMORPHIC_PROTOTYPE_FAILURE: | 729 case MONOMORPHIC_PROTOTYPE_FAILURE: |
| 1025 UpdateMonomorphicIC(type, code, name); | 730 UpdateMonomorphicIC(type, code, name); |
| 1026 break; | 731 break; |
| 1027 case MONOMORPHIC: { | 732 case MONOMORPHIC: { |
| 1028 // For now, call stubs are allowed to rewrite to the same stub. This | 733 // For now, call stubs are allowed to rewrite to the same stub. This |
| 1029 // happens e.g., when the field does not contain a function. | 734 // happens e.g., when the field does not contain a function. |
| 1030 ASSERT(target()->is_call_stub() || | 735 ASSERT(!target().is_identical_to(code)); |
| 1031 target()->is_keyed_call_stub() || | |
| 1032 !target().is_identical_to(code)); | |
| 1033 Code* old_handler = target()->FindFirstHandler(); | 736 Code* old_handler = target()->FindFirstHandler(); |
| 1034 if (old_handler == *code && IsTransitionOfMonomorphicTarget(type)) { | 737 if (old_handler == *code && IsTransitionOfMonomorphicTarget(type)) { |
| 1035 UpdateMonomorphicIC(type, code, name); | 738 UpdateMonomorphicIC(type, code, name); |
| 1036 break; | 739 break; |
| 1037 } | 740 } |
| 1038 // Fall through. | 741 // Fall through. |
| 1039 } | 742 } |
| 1040 case POLYMORPHIC: | 743 case POLYMORPHIC: |
| 1041 if (!target()->is_keyed_stub()) { | 744 if (!target()->is_keyed_stub()) { |
| 1042 if (UpdatePolymorphicIC(type, name, code)) break; | 745 if (UpdatePolymorphicIC(type, name, code)) break; |
| 1043 CopyICToMegamorphicCache(name); | 746 CopyICToMegamorphicCache(name); |
| 1044 } | 747 } |
| 1045 set_target(*megamorphic_stub()); | 748 set_target(*megamorphic_stub()); |
| 1046 // Fall through. | 749 // Fall through. |
| 1047 case MEGAMORPHIC: | 750 case MEGAMORPHIC: |
| 1048 UpdateMegamorphicCache(*type, *name, *code); | 751 UpdateMegamorphicCache(*type, *name, *code); |
| 1049 break; | 752 break; |
| 1050 case DEBUG_STUB: | 753 case DEBUG_STUB: |
| 1051 break; | 754 break; |
| 1052 case GENERIC: | 755 case GENERIC: |
| 1053 UNREACHABLE(); | 756 UNREACHABLE(); |
| 1054 break; | 757 break; |
| 1055 } | 758 } |
| 1056 } | 759 } |
| 1057 | 760 |
| 1058 | 761 |
| 1059 Handle<Code> LoadIC::initialize_stub(Isolate* isolate, ContextualMode mode) { | 762 Handle<Code> LoadIC::initialize_stub(Isolate* isolate, |
| 1060 Handle<Code> ic = isolate->stub_cache()->ComputeLoad( | 763 ExtraICState extra_state) { |
| 1061 UNINITIALIZED, ComputeExtraICState(mode)); | 764 return isolate->stub_cache()->ComputeLoad(UNINITIALIZED, extra_state); |
| 1062 return ic; | |
| 1063 } | 765 } |
| 1064 | 766 |
| 1065 | 767 |
| 1066 Handle<Code> LoadIC::pre_monomorphic_stub(Isolate* isolate, | 768 Handle<Code> LoadIC::pre_monomorphic_stub(Isolate* isolate, |
| 1067 ContextualMode mode) { | 769 ExtraICState extra_state) { |
| 1068 return isolate->stub_cache()->ComputeLoad( | 770 return isolate->stub_cache()->ComputeLoad(PREMONOMORPHIC, extra_state); |
| 1069 PREMONOMORPHIC, ComputeExtraICState(mode)); | |
| 1070 } | 771 } |
| 1071 | 772 |
| 1072 | 773 |
| 1073 Handle<Code> LoadIC::megamorphic_stub() { | 774 Handle<Code> LoadIC::megamorphic_stub() { |
| 1074 return isolate()->stub_cache()->ComputeLoad( | 775 return isolate()->stub_cache()->ComputeLoad(MEGAMORPHIC, extra_ic_state()); |
| 1075 MEGAMORPHIC, extra_ic_state()); | |
| 1076 } | 776 } |
| 1077 | 777 |
| 1078 | 778 |
| 1079 Handle<Code> LoadIC::SimpleFieldLoad(int offset, | 779 Handle<Code> LoadIC::SimpleFieldLoad(int offset, |
| 1080 bool inobject, | 780 bool inobject, |
| 1081 Representation representation) { | 781 Representation representation) { |
| 1082 if (kind() == Code::LOAD_IC) { | 782 if (kind() == Code::LOAD_IC) { |
| 1083 LoadFieldStub stub(inobject, offset, representation); | 783 LoadFieldStub stub(inobject, offset, representation); |
| 1084 return stub.GetCode(isolate()); | 784 return stub.GetCode(isolate()); |
| 1085 } else { | 785 } else { |
| (...skipping 932 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2018 | 1718 |
| 2019 | 1719 |
| 2020 #undef TRACE_IC | 1720 #undef TRACE_IC |
| 2021 | 1721 |
| 2022 | 1722 |
| 2023 // ---------------------------------------------------------------------------- | 1723 // ---------------------------------------------------------------------------- |
| 2024 // Static IC stub generators. | 1724 // Static IC stub generators. |
| 2025 // | 1725 // |
| 2026 | 1726 |
| 2027 // Used from ic-<arch>.cc. | 1727 // Used from ic-<arch>.cc. |
| 2028 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { | |
| 2029 HandleScope scope(isolate); | |
| 2030 ASSERT(args.length() == 2); | |
| 2031 CallIC ic(isolate); | |
| 2032 Handle<Object> receiver = args.at<Object>(0); | |
| 2033 Handle<String> key = args.at<String>(1); | |
| 2034 ic.UpdateState(receiver, key); | |
| 2035 MaybeObject* maybe_result = ic.LoadFunction(receiver, key); | |
| 2036 JSFunction* raw_function; | |
| 2037 if (!maybe_result->To(&raw_function)) return maybe_result; | |
| 2038 | |
| 2039 // The first time the inline cache is updated may be the first time the | |
| 2040 // function it references gets called. If the function is lazily compiled | |
| 2041 // then the first call will trigger a compilation. We check for this case | |
| 2042 // and we do the compilation immediately, instead of waiting for the stub | |
| 2043 // currently attached to the JSFunction object to trigger compilation. | |
| 2044 if (raw_function->is_compiled()) return raw_function; | |
| 2045 | |
| 2046 Handle<JSFunction> function(raw_function); | |
| 2047 Compiler::EnsureCompiled(function, CLEAR_EXCEPTION); | |
| 2048 return *function; | |
| 2049 } | |
| 2050 | |
| 2051 | |
| 2052 // Used from ic-<arch>.cc. | |
| 2053 RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) { | |
| 2054 HandleScope scope(isolate); | |
| 2055 ASSERT(args.length() == 2); | |
| 2056 KeyedCallIC ic(isolate); | |
| 2057 Handle<Object> receiver = args.at<Object>(0); | |
| 2058 Handle<Object> key = args.at<Object>(1); | |
| 2059 ic.UpdateState(receiver, key); | |
| 2060 MaybeObject* maybe_result = ic.LoadFunction(receiver, key); | |
| 2061 // Result could be a function or a failure. | |
| 2062 JSFunction* raw_function = NULL; | |
| 2063 if (!maybe_result->To(&raw_function)) return maybe_result; | |
| 2064 | |
| 2065 if (raw_function->is_compiled()) return raw_function; | |
| 2066 | |
| 2067 Handle<JSFunction> function(raw_function, isolate); | |
| 2068 Compiler::EnsureCompiled(function, CLEAR_EXCEPTION); | |
| 2069 return *function; | |
| 2070 } | |
| 2071 | |
| 2072 | |
| 2073 // Used from ic-<arch>.cc. | 1728 // Used from ic-<arch>.cc. |
| 2074 RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) { | 1729 RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) { |
| 2075 HandleScope scope(isolate); | 1730 HandleScope scope(isolate); |
| 2076 ASSERT(args.length() == 2); | 1731 ASSERT(args.length() == 2); |
| 2077 LoadIC ic(IC::NO_EXTRA_FRAME, isolate); | 1732 LoadIC ic(IC::NO_EXTRA_FRAME, isolate); |
| 2078 Handle<Object> receiver = args.at<Object>(0); | 1733 Handle<Object> receiver = args.at<Object>(0); |
| 2079 Handle<String> key = args.at<String>(1); | 1734 Handle<String> key = args.at<String>(1); |
| 2080 ic.UpdateState(receiver, key); | 1735 ic.UpdateState(receiver, key); |
| 2081 return ic.Load(receiver, key); | 1736 return ic.Load(receiver, key); |
| 2082 } | 1737 } |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2121 HandleScope scope(isolate); | 1776 HandleScope scope(isolate); |
| 2122 ASSERT(args.length() == 3); | 1777 ASSERT(args.length() == 3); |
| 2123 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate); | 1778 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate); |
| 2124 Handle<Object> receiver = args.at<Object>(0); | 1779 Handle<Object> receiver = args.at<Object>(0); |
| 2125 Handle<String> key = args.at<String>(1); | 1780 Handle<String> key = args.at<String>(1); |
| 2126 ic.UpdateState(receiver, key); | 1781 ic.UpdateState(receiver, key); |
| 2127 return ic.Store(receiver, key, args.at<Object>(2)); | 1782 return ic.Store(receiver, key, args.at<Object>(2)); |
| 2128 } | 1783 } |
| 2129 | 1784 |
| 2130 | 1785 |
| 2131 RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_MissFromStubFailure) { | |
| 2132 HandleScope scope(isolate); | |
| 2133 ASSERT(args.length() == 2); | |
| 2134 KeyedCallIC ic(isolate); | |
| 2135 Arguments* caller_args = reinterpret_cast<Arguments*>(args[0]); | |
| 2136 Handle<Object> key = args.at<Object>(1); | |
| 2137 Handle<Object> receiver((*caller_args)[0], isolate); | |
| 2138 | |
| 2139 ic.UpdateState(receiver, key); | |
| 2140 MaybeObject* maybe_result = ic.LoadFunction(receiver, key); | |
| 2141 // Result could be a function or a failure. | |
| 2142 JSFunction* raw_function = NULL; | |
| 2143 if (!maybe_result->To(&raw_function)) return maybe_result; | |
| 2144 | |
| 2145 if (raw_function->is_compiled()) return raw_function; | |
| 2146 | |
| 2147 Handle<JSFunction> function(raw_function, isolate); | |
| 2148 Compiler::EnsureCompiled(function, CLEAR_EXCEPTION); | |
| 2149 return *function; | |
| 2150 } | |
| 2151 | |
| 2152 | |
| 2153 RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) { | 1786 RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) { |
| 2154 SealHandleScope shs(isolate); | 1787 SealHandleScope shs(isolate); |
| 2155 | 1788 |
| 2156 ASSERT(args.length() == 2); | 1789 ASSERT(args.length() == 2); |
| 2157 JSArray* receiver = JSArray::cast(args[0]); | 1790 JSArray* receiver = JSArray::cast(args[0]); |
| 2158 Object* len = args[1]; | 1791 Object* len = args[1]; |
| 2159 | 1792 |
| 2160 // The generated code should filter out non-Smis before we get here. | 1793 // The generated code should filter out non-Smis before we get here. |
| 2161 ASSERT(len->IsSmi()); | 1794 ASSERT(len->IsSmi()); |
| 2162 | 1795 |
| (...skipping 1009 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3172 #undef ADDR | 2805 #undef ADDR |
| 3173 }; | 2806 }; |
| 3174 | 2807 |
| 3175 | 2808 |
| 3176 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2809 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 3177 return IC_utilities[id]; | 2810 return IC_utilities[id]; |
| 3178 } | 2811 } |
| 3179 | 2812 |
| 3180 | 2813 |
| 3181 } } // namespace v8::internal | 2814 } } // namespace v8::internal |
| OLD | NEW |