OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |