Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(293)

Side by Side Diff: src/x64/codegen-x64.cc

Issue 173566: Port apply with arguments optimization to x64. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/x64/codegen-x64.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2009 the V8 project authors. All rights reserved. 1 // Copyright 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 631 matching lines...) Expand 10 before | Expand all | Expand 10 after
642 // instruction that gets patched and coverage code gets in the way. 642 // instruction that gets patched and coverage code gets in the way.
643 masm_->testl(rax, Immediate(-delta_to_patch_site)); 643 masm_->testl(rax, Immediate(-delta_to_patch_site));
644 // Restore value (returned from store IC), key and receiver 644 // Restore value (returned from store IC), key and receiver
645 // registers. 645 // registers.
646 if (!value_.is(rax)) __ movq(value_, rax); 646 if (!value_.is(rax)) __ movq(value_, rax);
647 __ pop(key_); 647 __ pop(key_);
648 __ pop(receiver_); 648 __ pop(receiver_);
649 } 649 }
650 650
651 651
652 class CallFunctionStub: public CodeStub {
653 public:
654 CallFunctionStub(int argc, InLoopFlag in_loop)
655 : argc_(argc), in_loop_(in_loop) { }
656
657 void Generate(MacroAssembler* masm);
658
659 private:
660 int argc_;
661 InLoopFlag in_loop_;
662
663 #ifdef DEBUG
664 void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); }
665 #endif
666
667 Major MajorKey() { return CallFunction; }
668 int MinorKey() { return argc_; }
669 InLoopFlag InLoop() { return in_loop_; }
670 };
671
672
673 void CodeGenerator::CallApplyLazy(Property* apply,
674 Expression* receiver,
675 VariableProxy* arguments,
676 int position) {
677 ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION);
678 ASSERT(arguments->IsArguments());
679
680 JumpTarget slow, done;
681
682 // Load the apply function onto the stack. This will usually
683 // give us a megamorphic load site. Not super, but it works.
684 Reference ref(this, apply);
685 ref.GetValue(NOT_INSIDE_TYPEOF);
686 ASSERT(ref.type() == Reference::NAMED);
687
688 // Load the receiver and the existing arguments object onto the
689 // expression stack. Avoid allocating the arguments object here.
690 Load(receiver);
691 LoadFromSlot(scope_->arguments()->var()->slot(), NOT_INSIDE_TYPEOF);
692
693 // Emit the source position information after having loaded the
694 // receiver and the arguments.
695 CodeForSourcePosition(position);
696
697 // Check if the arguments object has been lazily allocated
698 // already. If so, just use that instead of copying the arguments
699 // from the stack. This also deals with cases where a local variable
700 // named 'arguments' has been introduced.
701 frame_->Dup();
702 Result probe = frame_->Pop();
703 bool try_lazy = true;
704 if (probe.is_constant()) {
705 try_lazy = probe.handle()->IsTheHole();
706 } else {
707 __ Cmp(probe.reg(), Factory::the_hole_value());
708 probe.Unuse();
709 slow.Branch(not_equal);
710 }
711
712 if (try_lazy) {
713 JumpTarget build_args;
714
715 // Get rid of the arguments object probe.
716 frame_->Drop();
717
718 // Before messing with the execution stack, we sync all
719 // elements. This is bound to happen anyway because we're
720 // about to call a function.
721 frame_->SyncRange(0, frame_->element_count() - 1);
722
723 // Check that the receiver really is a JavaScript object.
724 { frame_->PushElementAt(0);
725 Result receiver = frame_->Pop();
726 receiver.ToRegister();
727 __ testl(receiver.reg(), Immediate(kSmiTagMask));
728 build_args.Branch(zero);
729 Result tmp = allocator_->Allocate();
William Hesse 2009/08/27 14:38:25 You can use kScratchRegister here, in CmpObjectTyp
Mads Ager (chromium) 2009/08/27 14:56:31 Done.
730 // We allow all JSObjects including JSFunctions. As long as
731 // JS_FUNCTION_TYPE is the last instance type and it is right
732 // after LAST_JS_OBJECT_TYPE, we do not have to check the upper
733 // bound.
734 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
735 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
736 __ CmpObjectType(receiver.reg(), FIRST_JS_OBJECT_TYPE, tmp.reg());
737 build_args.Branch(below);
738 }
739
740 // Verify that we're invoking Function.prototype.apply.
741 { frame_->PushElementAt(1);
742 Result apply = frame_->Pop();
743 apply.ToRegister();
744 __ testl(apply.reg(), Immediate(kSmiTagMask));
745 build_args.Branch(zero);
746 Result tmp = allocator_->Allocate();
747 __ CmpObjectType(apply.reg(), JS_FUNCTION_TYPE, tmp.reg());
748 build_args.Branch(not_equal);
749 __ movq(tmp.reg(),
750 FieldOperand(apply.reg(), JSFunction::kSharedFunctionInfoOffset));
751 Handle<Code> apply_code(Builtins::builtin(Builtins::FunctionApply));
752 __ Cmp(FieldOperand(tmp.reg(), SharedFunctionInfo::kCodeOffset),
William Hesse 2009/08/27 14:38:25 This Cmp uses kScratchRegister, so you do need tmp
753 apply_code);
754 build_args.Branch(not_equal);
755 }
756
757 // Get the function receiver from the stack. Check that it
758 // really is a function.
759 __ movq(rdi, Operand(rsp, 2 * kPointerSize));
760 __ testl(rdi, Immediate(kSmiTagMask));
761 build_args.Branch(zero);
762 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
763 build_args.Branch(not_equal);
764
765 // Copy the arguments to this function possibly from the
766 // adaptor frame below it.
767 Label invoke, adapted;
768 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
769 __ movq(rcx, Operand(rdx, StandardFrameConstants::kContextOffset));
770 __ cmpq(rcx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
771 __ j(equal, &adapted);
772
773 // No arguments adaptor frame. Copy fixed number of arguments.
774 __ movq(rax, Immediate(scope_->num_parameters()));
775 for (int i = 0; i < scope_->num_parameters(); i++) {
776 __ push(frame_->ParameterAt(i));
777 }
778 __ jmp(&invoke);
779
780 // Arguments adaptor frame present. Copy arguments from there, but
781 // avoid copying too many arguments to avoid stack overflows.
782 __ bind(&adapted);
783 static const uint32_t kArgumentsLimit = 1 * KB;
784 __ movq(rax, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset));
785 __ shrl(rax, Immediate(kSmiTagSize));
786 __ movq(rcx, rax);
787 __ cmpq(rax, Immediate(kArgumentsLimit));
788 build_args.Branch(above);
789
790 // Loop through the arguments pushing them onto the execution
791 // stack. We don't inform the virtual frame of the push, so we don't
792 // have to worry about getting rid of the elements from the virtual
793 // frame.
794 Label loop;
795 __ bind(&loop);
796 __ testl(rcx, rcx);
797 __ j(zero, &invoke);
798 __ push(Operand(rdx, rcx, times_pointer_size, 1 * kPointerSize));
799 __ decl(rcx);
800 __ jmp(&loop);
801
802 // Invoke the function. The virtual frame knows about the receiver
803 // so make sure to forget that explicitly.
804 __ bind(&invoke);
805 ParameterCount actual(rax);
806 __ InvokeFunction(rdi, actual, CALL_FUNCTION);
807 frame_->Forget(1);
808 Result result = allocator()->Allocate(rax);
809 frame_->SetElementAt(0, &result);
810 done.Jump();
811
812 // Slow-case: Allocate the arguments object since we know it isn't
813 // there, and fall-through to the slow-case where we call
814 // Function.prototype.apply.
815 build_args.Bind();
816 Result arguments_object = StoreArgumentsObject(false);
817 frame_->Push(&arguments_object);
818 slow.Bind();
819 }
820
821 // Flip the apply function and the function to call on the stack, so
822 // the function looks like the receiver of the apply call. This way,
823 // the generic Function.prototype.apply implementation can deal with
824 // the call like it usually does.
825 Result a2 = frame_->Pop();
826 Result a1 = frame_->Pop();
827 Result ap = frame_->Pop();
828 Result fn = frame_->Pop();
829 frame_->Push(&ap);
830 frame_->Push(&fn);
831 frame_->Push(&a1);
832 frame_->Push(&a2);
833 CallFunctionStub call_function(2, NOT_IN_LOOP);
834 Result res = frame_->CallStub(&call_function, 3);
835 frame_->Push(&res);
836
837 // All done. Restore context register after call.
838 if (try_lazy) done.Bind();
839 frame_->RestoreContextRegister();
840 }
841
842
652 class DeferredStackCheck: public DeferredCode { 843 class DeferredStackCheck: public DeferredCode {
653 public: 844 public:
654 DeferredStackCheck() { 845 DeferredStackCheck() {
655 set_comment("[ DeferredStackCheck"); 846 set_comment("[ DeferredStackCheck");
656 } 847 }
657 848
658 virtual void Generate(); 849 virtual void Generate();
659 }; 850 };
660 851
661 852
662 void DeferredStackCheck::Generate() { 853 void DeferredStackCheck::Generate() {
663 StackCheckStub stub; 854 StackCheckStub stub;
664 __ CallStub(&stub); 855 __ CallStub(&stub);
665 } 856 }
666 857
667 858
668 void CodeGenerator::CheckStack() { 859 void CodeGenerator::CheckStack() {
669 if (FLAG_check_stack) { 860 if (FLAG_check_stack) {
670 DeferredStackCheck* deferred = new DeferredStackCheck; 861 DeferredStackCheck* deferred = new DeferredStackCheck;
671 ExternalReference stack_guard_limit = 862 ExternalReference stack_guard_limit =
672 ExternalReference::address_of_stack_guard_limit(); 863 ExternalReference::address_of_stack_guard_limit();
673 __ movq(kScratchRegister, stack_guard_limit); 864 __ movq(kScratchRegister, stack_guard_limit);
674 __ cmpq(rsp, Operand(kScratchRegister, 0)); 865 __ cmpq(rsp, Operand(kScratchRegister, 0));
675 deferred->Branch(below); 866 deferred->Branch(below);
676 deferred->BindExit(); 867 deferred->BindExit();
677 } 868 }
678 } 869 }
679 870
680 871
681 class CallFunctionStub: public CodeStub {
682 public:
683 CallFunctionStub(int argc, InLoopFlag in_loop)
684 : argc_(argc), in_loop_(in_loop) { }
685
686 void Generate(MacroAssembler* masm);
687
688 private:
689 int argc_;
690 InLoopFlag in_loop_;
691
692 #ifdef DEBUG
693 void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); }
694 #endif
695
696 Major MajorKey() { return CallFunction; }
697 int MinorKey() { return argc_; }
698 InLoopFlag InLoop() { return in_loop_; }
699 };
700
701
702 void CodeGenerator::VisitAndSpill(Statement* statement) { 872 void CodeGenerator::VisitAndSpill(Statement* statement) {
703 // TODO(X64): No architecture specific code. Move to shared location. 873 // TODO(X64): No architecture specific code. Move to shared location.
704 ASSERT(in_spilled_code()); 874 ASSERT(in_spilled_code());
705 set_in_spilled_code(false); 875 set_in_spilled_code(false);
706 Visit(statement); 876 Visit(statement);
707 if (frame_ != NULL) { 877 if (frame_ != NULL) {
708 frame_->SpillAll(); 878 frame_->SpillAll();
709 } 879 }
710 set_in_spilled_code(true); 880 set_in_spilled_code(true);
711 } 881 }
(...skipping 1893 matching lines...) Expand 10 before | Expand all | Expand 10 after
2605 CallWithArguments(args, node->position()); 2775 CallWithArguments(args, node->position());
2606 } else if (property != NULL) { 2776 } else if (property != NULL) {
2607 // Check if the key is a literal string. 2777 // Check if the key is a literal string.
2608 Literal* literal = property->key()->AsLiteral(); 2778 Literal* literal = property->key()->AsLiteral();
2609 2779
2610 if (literal != NULL && literal->handle()->IsSymbol()) { 2780 if (literal != NULL && literal->handle()->IsSymbol()) {
2611 // ------------------------------------------------------------------ 2781 // ------------------------------------------------------------------
2612 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' 2782 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
2613 // ------------------------------------------------------------------ 2783 // ------------------------------------------------------------------
2614 2784
2615 // TODO(X64): Consider optimizing Function.prototype.apply calls 2785 Handle<String> name = Handle<String>::cast(literal->handle());
2616 // with arguments object. Requires lazy arguments allocation;
2617 // see http://codereview.chromium.org/147075.
2618 2786
2619 // Push the name of the function and the receiver onto the stack. 2787 if (ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION &&
2620 frame_->Push(literal->handle()); 2788 name->IsEqualTo(CStrVector("apply")) &&
2621 Load(property->obj()); 2789 args->length() == 2 &&
2790 args->at(1)->AsVariableProxy() != NULL &&
2791 args->at(1)->AsVariableProxy()->IsArguments()) {
2792 // Use the optimized Function.prototype.apply that avoids
2793 // allocating lazily allocated arguments objects.
2794 CallApplyLazy(property,
2795 args->at(0),
2796 args->at(1)->AsVariableProxy(),
2797 node->position());
2622 2798
2623 // Load the arguments. 2799 } else {
2624 int arg_count = args->length(); 2800 // Push the name of the function and the receiver onto the stack.
2625 for (int i = 0; i < arg_count; i++) { 2801 frame_->Push(name);
2626 Load(args->at(i)); 2802 Load(property->obj());
2803
2804 // Load the arguments.
2805 int arg_count = args->length();
2806 for (int i = 0; i < arg_count; i++) {
2807 Load(args->at(i));
2808 }
2809
2810 // Call the IC initialization code.
2811 CodeForSourcePosition(node->position());
2812 Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET,
2813 arg_count,
2814 loop_nesting());
2815 frame_->RestoreContextRegister();
2816 // Replace the function on the stack with the result.
2817 frame_->SetElementAt(0, &result);
2627 } 2818 }
2628 2819
2629 // Call the IC initialization code.
2630 CodeForSourcePosition(node->position());
2631 Result result =
2632 frame_->CallCallIC(RelocInfo::CODE_TARGET, arg_count, loop_nesting());
2633 frame_->RestoreContextRegister();
2634 // Replace the function on the stack with the result.
2635 frame_->SetElementAt(0, &result);
2636
2637 } else { 2820 } else {
2638 // ------------------------------------------- 2821 // -------------------------------------------
2639 // JavaScript example: 'array[index](1, 2, 3)' 2822 // JavaScript example: 'array[index](1, 2, 3)'
2640 // ------------------------------------------- 2823 // -------------------------------------------
2641 2824
2642 // Load the function to call from the property through a reference. 2825 // Load the function to call from the property through a reference.
2643 Reference ref(this, property); 2826 Reference ref(this, property);
2644 ref.GetValue(NOT_INSIDE_TYPEOF); 2827 ref.GetValue(NOT_INSIDE_TYPEOF);
2645 2828
2646 // Pass receiver to called function. 2829 // Pass receiver to called function.
(...skipping 5054 matching lines...) Expand 10 before | Expand all | Expand 10 after
7701 int CompareStub::MinorKey() { 7884 int CompareStub::MinorKey() {
7702 // Encode the two parameters in a unique 16 bit value. 7885 // Encode the two parameters in a unique 16 bit value.
7703 ASSERT(static_cast<unsigned>(cc_) < (1 << 15)); 7886 ASSERT(static_cast<unsigned>(cc_) < (1 << 15));
7704 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); 7887 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0);
7705 } 7888 }
7706 7889
7707 7890
7708 #undef __ 7891 #undef __
7709 7892
7710 } } // namespace v8::internal 7893 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/x64/codegen-x64.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698