Chromium Code Reviews| 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 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 472 ExternalReference ref = ExternalReference( | 472 ExternalReference ref = ExternalReference( |
| 473 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); | 473 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); |
| 474 __ TailCallRuntime(ref, 5, 1); | 474 __ TailCallRuntime(ref, 5, 1); |
| 475 } | 475 } |
| 476 | 476 |
| 477 private: | 477 private: |
| 478 Register name_; | 478 Register name_; |
| 479 }; | 479 }; |
| 480 | 480 |
| 481 | 481 |
| 482 // Holds information about possible function call optimizations. | |
| 483 class CallOptimization BASE_EMBEDDED { | |
| 484 public: | |
| 485 explicit CallOptimization(LookupResult* lookup) | |
| 486 : constant_function_(NULL), | |
| 487 is_simple_api_call_(false), | |
| 488 expected_receiver_type_(NULL), | |
| 489 api_call_info_(NULL) { | |
| 490 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | |
| 491 | |
| 492 // We only optimize constant function calls. | |
| 493 if (lookup->type() != CONSTANT_FUNCTION) return; | |
| 494 | |
| 495 Initialize(lookup->GetConstantFunction()); | |
| 496 } | |
| 497 | |
| 498 explicit CallOptimization(JSFunction* function) { | |
| 499 Initialize(function); | |
| 500 } | |
| 501 | |
| 502 bool is_constant_call() const { | |
| 503 return constant_function_ != NULL; | |
| 504 } | |
| 505 | |
| 506 JSFunction* constant_function() const { | |
| 507 ASSERT(constant_function_ != NULL); | |
| 508 return constant_function_; | |
| 509 } | |
| 510 | |
| 511 bool is_simple_api_call() const { | |
| 512 return is_simple_api_call_; | |
| 513 } | |
| 514 | |
| 515 FunctionTemplateInfo* expected_receiver_type() const { | |
| 516 ASSERT(is_simple_api_call_); | |
| 517 return expected_receiver_type_; | |
| 518 } | |
| 519 | |
| 520 CallHandlerInfo* api_call_info() const { | |
| 521 ASSERT(is_simple_api_call_); | |
| 522 return api_call_info_; | |
| 523 } | |
| 524 | |
| 525 // Returns the depth of the object having the expected type in the | |
| 526 // prototype chain between the two arguments. | |
| 527 int GetPrototypeDepthOfExpectedType(JSObject* object, | |
| 528 JSObject* holder) const { | |
| 529 ASSERT(is_simple_api_call_); | |
| 530 if (expected_receiver_type_ == NULL) return 0; | |
| 531 int depth = 0; | |
| 532 while (object != holder) { | |
| 533 if (object->IsInstanceOf(expected_receiver_type_)) return depth; | |
| 534 object = JSObject::cast(object->GetPrototype()); | |
| 535 ++depth; | |
| 536 } | |
| 537 if (holder->IsInstanceOf(expected_receiver_type_)) return depth; | |
| 538 return kInvalidProtoDepth; | |
| 539 } | |
| 540 | |
| 541 private: | |
| 542 void Initialize(JSFunction* function) { | |
| 543 if (!function->is_compiled()) return; | |
| 544 | |
| 545 constant_function_ = function; | |
| 546 is_simple_api_call_ = false; | |
| 547 | |
| 548 AnalyzePossibleApiFunction(function); | |
| 549 } | |
| 550 | |
| 551 // Determines whether the given function can be called using the | |
| 552 // fast api call builtin. | |
| 553 void AnalyzePossibleApiFunction(JSFunction* function) { | |
| 554 SharedFunctionInfo* sfi = function->shared(); | |
| 555 if (sfi->function_data()->IsUndefined()) return; | |
| 556 FunctionTemplateInfo* info = | |
| 557 FunctionTemplateInfo::cast(sfi->function_data()); | |
| 558 | |
| 559 // Require a C++ callback. | |
| 560 if (info->call_code()->IsUndefined()) return; | |
| 561 api_call_info_ = CallHandlerInfo::cast(info->call_code()); | |
| 562 | |
| 563 // Accept signatures that either have no restrictions at all or | |
| 564 // only have restrictions on the receiver. | |
| 565 if (!info->signature()->IsUndefined()) { | |
| 566 SignatureInfo* signature = SignatureInfo::cast(info->signature()); | |
| 567 if (!signature->args()->IsUndefined()) return; | |
| 568 if (!signature->receiver()->IsUndefined()) { | |
| 569 expected_receiver_type_ = | |
| 570 FunctionTemplateInfo::cast(signature->receiver()); | |
| 571 } | |
| 572 } | |
| 573 | |
| 574 is_simple_api_call_ = true; | |
| 575 } | |
| 576 | |
| 577 JSFunction* constant_function_; | |
| 578 bool is_simple_api_call_; | |
| 579 FunctionTemplateInfo* expected_receiver_type_; | |
| 580 CallHandlerInfo* api_call_info_; | |
| 581 }; | |
| 582 | |
| 583 | |
| 584 // Reserves space for the extra arguments to FastHandleApiCall in the | |
| 585 // caller's frame. | |
| 586 // | |
| 587 // These arguments are set by CheckPrototypes and GenerateFastApiCall. | |
| 588 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { | |
| 589 // ----------- S t a t e ------------- | |
| 590 // -- esp[0] : return address | |
| 591 // -- esp[4] : last argument in the internal frame of the caller | |
| 592 // ----------------------------------- | |
| 593 __ pop(scratch); | |
| 594 __ push(Immediate(Smi::FromInt(0))); | |
| 595 __ push(Immediate(Smi::FromInt(0))); | |
| 596 __ push(Immediate(Smi::FromInt(0))); | |
| 597 __ push(Immediate(Smi::FromInt(0))); | |
| 598 __ push(scratch); | |
| 599 } | |
| 600 | |
| 601 | |
| 602 // Undoes the effects of ReserveSpaceForFastApiCall. | |
| 603 static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { | |
| 604 // ----------- S t a t e ------------- | |
| 605 // -- esp[0] : return address | |
| 606 // -- esp[4] : last fast api call extra argument | |
| 607 // -- ... | |
| 608 // -- esp[16] : first fast api call extra argument | |
| 609 // -- esp[20] : last argument in the internal frame | |
| 610 // ----------------------------------- | |
| 611 __ pop(scratch); | |
| 612 __ add(Operand(esp), Immediate(kPointerSize * 4)); | |
| 613 __ push(scratch); | |
| 614 } | |
| 615 | |
| 616 | |
| 617 // Generates call to FastHandleApiCall builtin. | |
| 618 static void GenerateFastApiCall(MacroAssembler* masm, | |
| 619 const CallOptimization& optimization, | |
| 620 int argc) { | |
| 621 // ----------- S t a t e ------------- | |
| 622 // -- esp[0] : return address | |
| 623 // -- esp[4] : object passing the type check | |
| 624 // (last fast api call extra argument, | |
| 625 // set by CheckPrototypes) | |
| 626 // -- esp[8] : api call data | |
| 627 // -- esp[12] : api callback | |
| 628 // -- esp[16] : api function | |
| 629 // (first fast api call extra argument) | |
| 630 // -- esp[20] : last argument | |
| 631 // -- ... | |
| 632 // -- esp[(argc + 5) * 4] : first argument | |
| 633 // -- esp[(argc + 6) * 4] : receiver | |
| 634 // ----------------------------------- | |
| 635 | |
| 636 // Get the function and setup the context. | |
| 637 JSFunction* function = optimization.constant_function(); | |
| 638 __ mov(edi, Immediate(Handle<JSFunction>(function))); | |
| 639 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | |
| 640 | |
| 641 // Pass the additional arguments FastHandleApiCall expects. | |
| 642 __ mov(Operand(esp, 4 * kPointerSize), edi); | |
| 643 bool info_loaded = false; | |
| 644 Object* callback = optimization.api_call_info()->callback(); | |
| 645 if (Heap::InNewSpace(callback)) { | |
| 646 info_loaded = true; | |
| 647 __ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info())); | |
| 648 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kCallbackOffset)); | |
| 649 __ mov(Operand(esp, 3 * kPointerSize), ebx); | |
| 650 } else { | |
| 651 __ mov(Operand(esp, 3 * kPointerSize), Immediate(Handle<Object>(callback))); | |
| 652 } | |
| 653 Object* call_data = optimization.api_call_info()->data(); | |
| 654 if (Heap::InNewSpace(call_data)) { | |
| 655 if (!info_loaded) { | |
| 656 __ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info())); | |
| 657 } | |
| 658 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset)); | |
| 659 __ mov(Operand(esp, 2 * kPointerSize), ebx); | |
| 660 } else { | |
| 661 __ mov(Operand(esp, 2 * kPointerSize), | |
| 662 Immediate(Handle<Object>(call_data))); | |
| 663 } | |
| 664 | |
| 665 // Set the number of arguments. | |
| 666 __ mov(eax, Immediate(argc + 4)); | |
| 667 | |
| 668 // Jump to the fast api call builtin (tail call). | |
| 669 Handle<Code> code = Handle<Code>( | |
| 670 Builtins::builtin(Builtins::FastHandleApiCall)); | |
| 671 ParameterCount expected(0); | |
| 672 __ InvokeCode(code, expected, expected, | |
| 673 RelocInfo::CODE_TARGET, JUMP_FUNCTION); | |
| 674 } | |
| 675 | |
| 676 | |
| 482 class CallInterceptorCompiler BASE_EMBEDDED { | 677 class CallInterceptorCompiler BASE_EMBEDDED { |
| 483 public: | 678 public: |
| 484 CallInterceptorCompiler(const ParameterCount& arguments, Register name) | 679 CallInterceptorCompiler(StubCompiler* stub_compiler, |
| 485 : arguments_(arguments), argc_(arguments.immediate()), name_(name) {} | 680 const ParameterCount& arguments, |
| 486 | 681 Register name) |
| 682 : stub_compiler_(stub_compiler), | |
| 683 arguments_(arguments), | |
| 684 argc_(arguments.immediate()), | |
| 685 name_(name) {} | |
| 686 | |
| 687 void Compile(MacroAssembler* masm, | |
| 688 JSObject* object, | |
| 689 JSObject* holder, | |
| 690 String* name, | |
| 691 LookupResult* lookup, | |
| 692 Register receiver, | |
| 693 Register scratch1, | |
| 694 Register scratch2, | |
| 695 Label* miss) { | |
| 696 ASSERT(holder->HasNamedInterceptor()); | |
| 697 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | |
| 698 | |
| 699 // Check that the receiver isn't a smi. | |
| 700 __ test(receiver, Immediate(kSmiTagMask)); | |
| 701 __ j(zero, miss, not_taken); | |
| 702 | |
| 703 CallOptimization optimization(lookup); | |
| 704 | |
| 705 if (optimization.is_constant_call() && | |
| 706 !Top::CanHaveSpecialFunctions(holder)) { | |
| 707 CompileCacheable(masm, | |
| 708 object, | |
| 709 receiver, | |
| 710 scratch1, | |
| 711 scratch2, | |
| 712 holder, | |
| 713 lookup, | |
| 714 name, | |
| 715 optimization, | |
| 716 miss); | |
| 717 } else { | |
| 718 CompileRegular(masm, | |
| 719 object, | |
| 720 receiver, | |
| 721 scratch1, | |
| 722 scratch2, | |
| 723 name, | |
| 724 holder, | |
| 725 miss); | |
| 726 } | |
| 727 } | |
| 728 | |
| 729 private: | |
| 487 void CompileCacheable(MacroAssembler* masm, | 730 void CompileCacheable(MacroAssembler* masm, |
| 488 StubCompiler* stub_compiler, | 731 JSObject* object, |
| 489 Register receiver, | 732 Register receiver, |
| 490 Register holder, | |
| 491 Register scratch1, | 733 Register scratch1, |
| 492 Register scratch2, | 734 Register scratch2, |
| 493 JSObject* holder_obj, | 735 JSObject* holder_obj, |
| 494 LookupResult* lookup, | 736 LookupResult* lookup, |
| 495 String* name, | 737 String* name, |
| 738 const CallOptimization& optimization, | |
| 496 Label* miss_label) { | 739 Label* miss_label) { |
| 497 JSFunction* function = 0; | 740 ASSERT(optimization.is_constant_call()); |
| 498 bool optimize = false; | 741 |
| 499 // So far the most popular case for failed interceptor is | 742 int depth1 = kInvalidProtoDepth; |
| 500 // CONSTANT_FUNCTION sitting below. | 743 int depth2 = kInvalidProtoDepth; |
| 501 if (lookup->type() == CONSTANT_FUNCTION) { | 744 bool can_do_fast_api_call = false; |
| 502 function = lookup->GetConstantFunction(); | 745 if (optimization.is_simple_api_call() && |
| 503 // JSArray holder is a special case for call constant function | 746 !lookup->holder()->IsGlobalObject()) { |
| 504 // (see the corresponding code). | 747 depth1 = optimization.GetPrototypeDepthOfExpectedType(object, holder_obj); |
| 505 if (function->is_compiled() && !holder_obj->IsJSArray()) { | 748 if (depth1 == kInvalidProtoDepth) { |
| 506 optimize = true; | 749 depth2 = optimization.GetPrototypeDepthOfExpectedType(holder_obj, |
| 750 lookup->holder()); | |
| 507 } | 751 } |
| 508 } | 752 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || |
| 509 | 753 (depth2 != kInvalidProtoDepth); |
| 510 if (!optimize) { | 754 } |
| 511 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); | 755 |
| 512 return; | 756 __ IncrementCounter(&Counters::call_const_interceptor, 1); |
| 513 } | 757 |
| 514 | 758 if (can_do_fast_api_call) { |
| 515 __ EnterInternalFrame(); | 759 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1); |
| 516 __ push(holder); // Save the holder. | 760 ReserveSpaceForFastApiCall(masm, scratch1); |
| 517 __ push(name_); // Save the name. | 761 } |
| 518 | 762 |
| 519 CompileCallLoadPropertyWithInterceptor(masm, | 763 Label miss; |
| 520 receiver, | 764 Register holder = |
| 521 holder, | 765 stub_compiler_->CheckPrototypes(object, receiver, holder_obj, |
| 522 name_, | 766 scratch1, scratch2, name, |
| 523 holder_obj); | 767 depth1, &miss); |
| 524 | 768 |
| 525 __ pop(name_); // Restore the name. | 769 Label regular_invoke; |
| 526 __ pop(receiver); // Restore the holder. | 770 LoadWithInterceptor(masm, receiver, holder, holder_obj, ®ular_invoke); |
| 527 __ LeaveInternalFrame(); | 771 |
| 528 | 772 // Generate code for the failed interceptor case. |
| 529 __ cmp(eax, Factory::no_interceptor_result_sentinel()); | 773 |
| 530 Label invoke; | 774 // Check the lookup is still valid. |
| 531 __ j(not_equal, &invoke); | 775 stub_compiler_->CheckPrototypes(holder_obj, receiver, |
| 532 | 776 lookup->holder(), |
| 533 stub_compiler->CheckPrototypes(holder_obj, receiver, | 777 scratch1, scratch2, name, |
| 534 lookup->holder(), scratch1, | 778 depth2, &miss); |
| 535 scratch2, | 779 |
| 536 name, | |
| 537 miss_label); | |
| 538 if (lookup->holder()->IsGlobalObject()) { | 780 if (lookup->holder()->IsGlobalObject()) { |
| 781 ASSERT(!can_do_fast_api_call); | |
| 539 __ mov(edx, Operand(esp, (argc_ + 1) * kPointerSize)); | 782 __ mov(edx, Operand(esp, (argc_ + 1) * kPointerSize)); |
| 540 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 783 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
| 541 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edx); | 784 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edx); |
| 542 } | 785 } |
| 543 | 786 |
| 544 ASSERT(function->is_compiled()); | 787 if (can_do_fast_api_call) { |
| 545 // Get the function and setup the context. | 788 GenerateFastApiCall(masm, optimization, argc_); |
| 546 __ mov(edi, Immediate(Handle<JSFunction>(function))); | 789 } else { |
| 547 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 790 // Get the function and setup the context. |
| 548 | 791 JSFunction* function = optimization.constant_function(); |
| 549 // Jump to the cached code (tail call). | 792 __ mov(edi, Immediate(Handle<JSFunction>(function))); |
| 550 Handle<Code> code(function->code()); | 793 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
| 551 ParameterCount expected(function->shared()->formal_parameter_count()); | 794 |
| 552 __ InvokeCode(code, expected, arguments_, | 795 // Jump to the cached code (tail call). |
| 553 RelocInfo::CODE_TARGET, JUMP_FUNCTION); | 796 ASSERT(function->is_compiled()); |
| 554 | 797 Handle<Code> code(function->code()); |
| 555 __ bind(&invoke); | 798 ParameterCount expected(function->shared()->formal_parameter_count()); |
| 799 __ InvokeCode(code, expected, arguments_, | |
| 800 RelocInfo::CODE_TARGET, JUMP_FUNCTION); | |
| 801 } | |
| 802 | |
| 803 __ bind(&miss); | |
|
antonm
2010/02/08 12:07:38
feel free to ignore, but in case when !can_do_fast
Vitaly Repeshko
2010/02/09 16:15:24
Done.
| |
| 804 if (can_do_fast_api_call) { | |
| 805 FreeSpaceForFastApiCall(masm, scratch1); | |
| 806 } | |
| 807 __ jmp(miss_label); | |
| 808 | |
| 809 __ bind(®ular_invoke); | |
| 810 if (can_do_fast_api_call) { | |
| 811 FreeSpaceForFastApiCall(masm, scratch1); | |
| 812 } | |
| 556 } | 813 } |
| 557 | 814 |
| 558 void CompileRegular(MacroAssembler* masm, | 815 void CompileRegular(MacroAssembler* masm, |
| 816 JSObject* object, | |
| 559 Register receiver, | 817 Register receiver, |
| 560 Register holder, | 818 Register scratch1, |
| 561 Register scratch, | 819 Register scratch2, |
| 820 String* name, | |
| 562 JSObject* holder_obj, | 821 JSObject* holder_obj, |
| 563 Label* miss_label) { | 822 Label* miss_label) { |
| 823 Register holder = | |
| 824 stub_compiler_->CheckPrototypes(object, receiver, holder_obj, | |
| 825 scratch1, scratch2, name, | |
| 826 miss_label); | |
| 827 | |
| 564 __ EnterInternalFrame(); | 828 __ EnterInternalFrame(); |
| 565 // Save the name_ register across the call. | 829 // Save the name_ register across the call. |
| 566 __ push(name_); | 830 __ push(name_); |
| 567 | 831 |
| 568 PushInterceptorArguments(masm, | 832 PushInterceptorArguments(masm, |
| 569 receiver, | 833 receiver, |
| 570 holder, | 834 holder, |
| 571 name_, | 835 name_, |
| 572 holder_obj); | 836 holder_obj); |
| 573 | 837 |
| 574 ExternalReference ref = ExternalReference( | 838 ExternalReference ref = ExternalReference( |
| 575 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)); | 839 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)); |
| 576 __ mov(eax, Immediate(5)); | 840 __ mov(eax, Immediate(5)); |
| 577 __ mov(ebx, Immediate(ref)); | 841 __ mov(ebx, Immediate(ref)); |
| 578 | 842 |
| 579 CEntryStub stub(1); | 843 CEntryStub stub(1); |
| 580 __ CallStub(&stub); | 844 __ CallStub(&stub); |
| 581 | 845 |
| 582 // Restore the name_ register. | 846 // Restore the name_ register. |
| 583 __ pop(name_); | 847 __ pop(name_); |
| 584 __ LeaveInternalFrame(); | 848 __ LeaveInternalFrame(); |
| 585 } | 849 } |
| 586 | 850 |
| 587 private: | 851 void LoadWithInterceptor(MacroAssembler* masm, |
| 852 Register receiver, | |
| 853 Register holder, | |
| 854 JSObject* holder_obj, | |
| 855 Label* interceptor_succeeded) { | |
| 856 __ EnterInternalFrame(); | |
| 857 __ push(holder); // Save the holder. | |
| 858 __ push(name_); // Save the name. | |
| 859 | |
| 860 CompileCallLoadPropertyWithInterceptor(masm, | |
| 861 receiver, | |
| 862 holder, | |
| 863 name_, | |
| 864 holder_obj); | |
| 865 | |
| 866 __ pop(name_); // Restore the name. | |
| 867 __ pop(receiver); // Restore the holder. | |
| 868 __ LeaveInternalFrame(); | |
| 869 | |
| 870 __ cmp(eax, Factory::no_interceptor_result_sentinel()); | |
| 871 __ j(not_equal, interceptor_succeeded); | |
| 872 } | |
| 873 | |
| 874 StubCompiler* stub_compiler_; | |
| 588 const ParameterCount& arguments_; | 875 const ParameterCount& arguments_; |
| 589 int argc_; | 876 const int argc_; |
| 590 Register name_; | 877 Register name_; |
| 591 }; | 878 }; |
| 592 | 879 |
| 593 | 880 |
| 594 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { | 881 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { |
| 595 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); | 882 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); |
| 596 Code* code = NULL; | 883 Code* code = NULL; |
| 597 if (kind == Code::LOAD_IC) { | 884 if (kind == Code::LOAD_IC) { |
| 598 code = Builtins::builtin(Builtins::LoadIC_Miss); | 885 code = Builtins::builtin(Builtins::LoadIC_Miss); |
| 599 } else { | 886 } else { |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 684 #undef __ | 971 #undef __ |
| 685 #define __ ACCESS_MASM(masm()) | 972 #define __ ACCESS_MASM(masm()) |
| 686 | 973 |
| 687 | 974 |
| 688 Register StubCompiler::CheckPrototypes(JSObject* object, | 975 Register StubCompiler::CheckPrototypes(JSObject* object, |
| 689 Register object_reg, | 976 Register object_reg, |
| 690 JSObject* holder, | 977 JSObject* holder, |
| 691 Register holder_reg, | 978 Register holder_reg, |
| 692 Register scratch, | 979 Register scratch, |
| 693 String* name, | 980 String* name, |
| 981 int push_at_depth, | |
| 694 Label* miss) { | 982 Label* miss) { |
| 695 // Check that the maps haven't changed. | 983 // Check that the maps haven't changed. |
| 696 Register result = | 984 Register result = |
| 697 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss); | 985 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, |
| 986 push_at_depth, miss); | |
| 698 | 987 |
| 699 // If we've skipped any global objects, it's not enough to verify | 988 // If we've skipped any global objects, it's not enough to verify |
| 700 // that their maps haven't changed. | 989 // that their maps haven't changed. |
| 701 while (object != holder) { | 990 while (object != holder) { |
| 702 if (object->IsGlobalObject()) { | 991 if (object->IsGlobalObject()) { |
| 703 GlobalObject* global = GlobalObject::cast(object); | 992 GlobalObject* global = GlobalObject::cast(object); |
| 704 Object* probe = global->EnsurePropertyCell(name); | 993 Object* probe = global->EnsurePropertyCell(name); |
| 705 if (probe->IsFailure()) { | 994 if (probe->IsFailure()) { |
| 706 set_failure(Failure::cast(probe)); | 995 set_failure(Failure::cast(probe)); |
| 707 return result; | 996 return result; |
| 708 } | 997 } |
| 709 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); | 998 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); |
| 710 ASSERT(cell->value()->IsTheHole()); | 999 ASSERT(cell->value()->IsTheHole()); |
| 711 __ mov(scratch, Immediate(Handle<Object>(cell))); | 1000 __ mov(scratch, Immediate(Handle<Object>(cell))); |
| 712 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), | 1001 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), |
| 713 Immediate(Factory::the_hole_value())); | 1002 Immediate(Factory::the_hole_value())); |
| 714 __ j(not_equal, miss, not_taken); | 1003 __ j(not_equal, miss, not_taken); |
| 715 } | 1004 } |
| 716 object = JSObject::cast(object->GetPrototype()); | 1005 object = JSObject::cast(object->GetPrototype()); |
| 717 } | 1006 } |
| 718 | 1007 |
| 719 // Return the register containin the holder. | 1008 // Return the register containing the holder. |
| 720 return result; | 1009 return result; |
| 721 } | 1010 } |
| 722 | 1011 |
| 723 | 1012 |
| 724 void StubCompiler::GenerateLoadField(JSObject* object, | 1013 void StubCompiler::GenerateLoadField(JSObject* object, |
| 725 JSObject* holder, | 1014 JSObject* holder, |
| 726 Register receiver, | 1015 Register receiver, |
| 727 Register scratch1, | 1016 Register scratch1, |
| 728 Register scratch2, | 1017 Register scratch2, |
| 729 int index, | 1018 int index, |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 962 // Check that the receiver isn't a smi. | 1251 // Check that the receiver isn't a smi. |
| 963 if (check != NUMBER_CHECK) { | 1252 if (check != NUMBER_CHECK) { |
| 964 __ test(edx, Immediate(kSmiTagMask)); | 1253 __ test(edx, Immediate(kSmiTagMask)); |
| 965 __ j(zero, &miss, not_taken); | 1254 __ j(zero, &miss, not_taken); |
| 966 } | 1255 } |
| 967 | 1256 |
| 968 // Make sure that it's okay not to patch the on stack receiver | 1257 // Make sure that it's okay not to patch the on stack receiver |
| 969 // unless we're doing a receiver map check. | 1258 // unless we're doing a receiver map check. |
| 970 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); | 1259 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); |
| 971 | 1260 |
| 1261 CallOptimization optimization(function); | |
| 1262 int depth = kInvalidProtoDepth; | |
| 1263 | |
| 972 switch (check) { | 1264 switch (check) { |
| 973 case RECEIVER_MAP_CHECK: | 1265 case RECEIVER_MAP_CHECK: |
| 1266 __ IncrementCounter(&Counters::call_const, 1); | |
| 1267 | |
| 1268 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) { | |
| 1269 depth = optimization.GetPrototypeDepthOfExpectedType( | |
| 1270 JSObject::cast(object), holder); | |
| 1271 } | |
| 1272 | |
| 1273 if (depth != kInvalidProtoDepth) { | |
| 1274 __ IncrementCounter(&Counters::call_const_fast_api, 1); | |
| 1275 ReserveSpaceForFastApiCall(masm(), eax); | |
| 1276 } | |
| 1277 | |
| 974 // Check that the maps haven't changed. | 1278 // Check that the maps haven't changed. |
| 975 CheckPrototypes(JSObject::cast(object), edx, holder, | 1279 CheckPrototypes(JSObject::cast(object), edx, holder, |
| 976 ebx, eax, name, &miss); | 1280 ebx, eax, name, depth, &miss); |
| 977 | 1281 |
| 978 // Patch the receiver on the stack with the global proxy if | 1282 // Patch the receiver on the stack with the global proxy if |
| 979 // necessary. | 1283 // necessary. |
| 980 if (object->IsGlobalObject()) { | 1284 if (object->IsGlobalObject()) { |
| 1285 ASSERT(depth == kInvalidProtoDepth); | |
| 981 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 1286 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
| 982 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | 1287 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); |
| 983 } | 1288 } |
| 984 break; | 1289 break; |
| 985 | 1290 |
| 986 case STRING_CHECK: | 1291 case STRING_CHECK: |
| 987 if (!function->IsBuiltin()) { | 1292 if (!function->IsBuiltin()) { |
| 988 // Calling non-builtins with a value as receiver requires boxing. | 1293 // Calling non-builtins with a value as receiver requires boxing. |
| 989 __ jmp(&miss); | 1294 __ jmp(&miss); |
| 990 } else { | 1295 } else { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1055 // Check that the object is in fast mode (not dictionary). | 1360 // Check that the object is in fast mode (not dictionary). |
| 1056 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 1361 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
| 1057 Immediate(Factory::fixed_array_map())); | 1362 Immediate(Factory::fixed_array_map())); |
| 1058 __ j(not_equal, &miss, not_taken); | 1363 __ j(not_equal, &miss, not_taken); |
| 1059 break; | 1364 break; |
| 1060 | 1365 |
| 1061 default: | 1366 default: |
| 1062 UNREACHABLE(); | 1367 UNREACHABLE(); |
| 1063 } | 1368 } |
| 1064 | 1369 |
| 1065 // Get the function and setup the context. | 1370 if (depth != kInvalidProtoDepth) { |
| 1066 __ mov(edi, Immediate(Handle<JSFunction>(function))); | 1371 GenerateFastApiCall(masm(), optimization, argc); |
| 1067 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 1372 } else { |
| 1373 // Get the function and setup the context. | |
| 1374 __ mov(edi, Immediate(Handle<JSFunction>(function))); | |
| 1375 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | |
| 1068 | 1376 |
| 1069 // Jump to the cached code (tail call). | 1377 // Jump to the cached code (tail call). |
| 1070 ASSERT(function->is_compiled()); | 1378 ASSERT(function->is_compiled()); |
| 1071 Handle<Code> code(function->code()); | 1379 Handle<Code> code(function->code()); |
| 1072 ParameterCount expected(function->shared()->formal_parameter_count()); | 1380 ParameterCount expected(function->shared()->formal_parameter_count()); |
| 1073 __ InvokeCode(code, expected, arguments(), | 1381 __ InvokeCode(code, expected, arguments(), |
| 1074 RelocInfo::CODE_TARGET, JUMP_FUNCTION); | 1382 RelocInfo::CODE_TARGET, JUMP_FUNCTION); |
| 1383 } | |
| 1075 | 1384 |
| 1076 // Handle call cache miss. | 1385 // Handle call cache miss. |
| 1077 __ bind(&miss); | 1386 __ bind(&miss); |
| 1387 if (depth != kInvalidProtoDepth) { | |
| 1388 FreeSpaceForFastApiCall(masm(), eax); | |
| 1389 } | |
| 1078 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); | 1390 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); |
| 1079 __ jmp(ic, RelocInfo::CODE_TARGET); | 1391 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 1080 | 1392 |
| 1081 // Return the generated code. | 1393 // Return the generated code. |
| 1082 String* function_name = NULL; | 1394 String* function_name = NULL; |
| 1083 if (function->shared()->name()->IsString()) { | 1395 if (function->shared()->name()->IsString()) { |
| 1084 function_name = String::cast(function->shared()->name()); | 1396 function_name = String::cast(function->shared()->name()); |
| 1085 } | 1397 } |
| 1086 return GetCode(CONSTANT_FUNCTION, function_name); | 1398 return GetCode(CONSTANT_FUNCTION, function_name); |
| 1087 } | 1399 } |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 1101 | 1413 |
| 1102 // Get the number of arguments. | 1414 // Get the number of arguments. |
| 1103 const int argc = arguments().immediate(); | 1415 const int argc = arguments().immediate(); |
| 1104 | 1416 |
| 1105 LookupResult lookup; | 1417 LookupResult lookup; |
| 1106 LookupPostInterceptor(holder, name, &lookup); | 1418 LookupPostInterceptor(holder, name, &lookup); |
| 1107 | 1419 |
| 1108 // Get the receiver from the stack. | 1420 // Get the receiver from the stack. |
| 1109 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1421 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1110 | 1422 |
| 1111 CallInterceptorCompiler compiler(arguments(), ecx); | 1423 CallInterceptorCompiler compiler(this, arguments(), ecx); |
| 1112 CompileLoadInterceptor(&compiler, | 1424 compiler.Compile(masm(), |
| 1113 this, | 1425 JSObject::cast(object), |
| 1114 masm(), | 1426 holder, |
| 1115 JSObject::cast(object), | 1427 name, |
| 1116 holder, | 1428 &lookup, |
| 1117 name, | 1429 edx, |
| 1118 &lookup, | 1430 ebx, |
| 1119 edx, | 1431 edi, |
| 1120 ebx, | 1432 &miss); |
| 1121 edi, | |
| 1122 &miss); | |
| 1123 | 1433 |
| 1124 // Restore receiver. | 1434 // Restore receiver. |
| 1125 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1435 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1126 | 1436 |
| 1127 // Check that the function really is a function. | 1437 // Check that the function really is a function. |
| 1128 __ test(eax, Immediate(kSmiTagMask)); | 1438 __ test(eax, Immediate(kSmiTagMask)); |
| 1129 __ j(zero, &miss, not_taken); | 1439 __ j(zero, &miss, not_taken); |
| 1130 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); | 1440 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); |
| 1131 __ j(not_equal, &miss, not_taken); | 1441 __ j(not_equal, &miss, not_taken); |
| 1132 | 1442 |
| (...skipping 809 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1942 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); | 2252 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); |
| 1943 | 2253 |
| 1944 // Return the generated code. | 2254 // Return the generated code. |
| 1945 return GetCode(); | 2255 return GetCode(); |
| 1946 } | 2256 } |
| 1947 | 2257 |
| 1948 | 2258 |
| 1949 #undef __ | 2259 #undef __ |
| 1950 | 2260 |
| 1951 } } // namespace v8::internal | 2261 } } // namespace v8::internal |
| OLD | NEW |