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

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

Issue 7623011: Implement function proxies (except for their use as constructors). (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed second round of comments. Created 9 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/v8natives.js ('k') | src/x64/code-stubs-x64.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 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 637 matching lines...) Expand 10 before | Expand all | Expand 10 after
648 __ j(not_zero, &done); 648 __ j(not_zero, &done);
649 __ pop(rbx); 649 __ pop(rbx);
650 __ Push(FACTORY->undefined_value()); 650 __ Push(FACTORY->undefined_value());
651 __ push(rbx); 651 __ push(rbx);
652 __ incq(rax); 652 __ incq(rax);
653 __ bind(&done); 653 __ bind(&done);
654 } 654 }
655 655
656 // 2. Get the function to call (passed as receiver) from the stack, check 656 // 2. Get the function to call (passed as receiver) from the stack, check
657 // if it is a function. 657 // if it is a function.
658 Label non_function; 658 Label slow, non_function;
659 // The function to call is at position n+1 on the stack. 659 // The function to call is at position n+1 on the stack.
660 __ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize)); 660 __ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize));
661 __ JumpIfSmi(rdi, &non_function); 661 __ JumpIfSmi(rdi, &non_function);
662 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); 662 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
663 __ j(not_equal, &non_function); 663 __ j(not_equal, &slow);
664 664
665 // 3a. Patch the first argument if necessary when calling a function. 665 // 3a. Patch the first argument if necessary when calling a function.
666 Label shift_arguments; 666 Label shift_arguments;
667 __ Set(rdx, 0); // indicate regular JS_FUNCTION
667 { Label convert_to_object, use_global_receiver, patch_receiver; 668 { Label convert_to_object, use_global_receiver, patch_receiver;
668 // Change context eagerly in case we need the global receiver. 669 // Change context eagerly in case we need the global receiver.
669 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); 670 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
670 671
671 // Do not transform the receiver for strict mode functions. 672 // Do not transform the receiver for strict mode functions.
672 __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); 673 __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
673 __ testb(FieldOperand(rbx, SharedFunctionInfo::kStrictModeByteOffset), 674 __ testb(FieldOperand(rbx, SharedFunctionInfo::kStrictModeByteOffset),
674 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte)); 675 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
675 __ j(not_equal, &shift_arguments); 676 __ j(not_equal, &shift_arguments);
676 677
(...skipping 17 matching lines...) Expand all
694 __ j(above_equal, &shift_arguments); 695 __ j(above_equal, &shift_arguments);
695 696
696 __ bind(&convert_to_object); 697 __ bind(&convert_to_object);
697 __ EnterInternalFrame(); // In order to preserve argument count. 698 __ EnterInternalFrame(); // In order to preserve argument count.
698 __ Integer32ToSmi(rax, rax); 699 __ Integer32ToSmi(rax, rax);
699 __ push(rax); 700 __ push(rax);
700 701
701 __ push(rbx); 702 __ push(rbx);
702 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 703 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
703 __ movq(rbx, rax); 704 __ movq(rbx, rax);
705 __ Set(rdx, 0); // indicate regular JS_FUNCTION
704 706
705 __ pop(rax); 707 __ pop(rax);
706 __ SmiToInteger32(rax, rax); 708 __ SmiToInteger32(rax, rax);
707 __ LeaveInternalFrame(); 709 __ LeaveInternalFrame();
708 // Restore the function to rdi. 710 // Restore the function to rdi.
709 __ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize)); 711 __ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize));
710 __ jmp(&patch_receiver, Label::kNear); 712 __ jmp(&patch_receiver, Label::kNear);
711 713
712 // Use the global receiver object from the called function as the 714 // Use the global receiver object from the called function as the
713 // receiver. 715 // receiver.
714 __ bind(&use_global_receiver); 716 __ bind(&use_global_receiver);
715 const int kGlobalIndex = 717 const int kGlobalIndex =
716 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; 718 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
717 __ movq(rbx, FieldOperand(rsi, kGlobalIndex)); 719 __ movq(rbx, FieldOperand(rsi, kGlobalIndex));
718 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalContextOffset)); 720 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalContextOffset));
719 __ movq(rbx, FieldOperand(rbx, kGlobalIndex)); 721 __ movq(rbx, FieldOperand(rbx, kGlobalIndex));
720 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); 722 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
721 723
722 __ bind(&patch_receiver); 724 __ bind(&patch_receiver);
723 __ movq(Operand(rsp, rax, times_pointer_size, 0), rbx); 725 __ movq(Operand(rsp, rax, times_pointer_size, 0), rbx);
724 726
725 __ jmp(&shift_arguments); 727 __ jmp(&shift_arguments);
726 } 728 }
727 729
730 // 3b. Check for function proxy.
731 __ bind(&slow);
732 __ Set(rdx, 1); // indicate function proxy
733 __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
734 __ j(equal, &shift_arguments);
735 __ bind(&non_function);
736 __ Set(rdx, 2); // indicate non-function
728 737
729 // 3b. Patch the first argument when calling a non-function. The 738 // 3c. Patch the first argument when calling a non-function. The
730 // CALL_NON_FUNCTION builtin expects the non-function callee as 739 // CALL_NON_FUNCTION builtin expects the non-function callee as
731 // receiver, so overwrite the first argument which will ultimately 740 // receiver, so overwrite the first argument which will ultimately
732 // become the receiver. 741 // become the receiver.
733 __ bind(&non_function);
734 __ movq(Operand(rsp, rax, times_pointer_size, 0), rdi); 742 __ movq(Operand(rsp, rax, times_pointer_size, 0), rdi);
735 __ Set(rdi, 0);
736 743
737 // 4. Shift arguments and return address one slot down on the stack 744 // 4. Shift arguments and return address one slot down on the stack
738 // (overwriting the original receiver). Adjust argument count to make 745 // (overwriting the original receiver). Adjust argument count to make
739 // the original first argument the new receiver. 746 // the original first argument the new receiver.
740 __ bind(&shift_arguments); 747 __ bind(&shift_arguments);
741 { Label loop; 748 { Label loop;
742 __ movq(rcx, rax); 749 __ movq(rcx, rax);
743 __ bind(&loop); 750 __ bind(&loop);
744 __ movq(rbx, Operand(rsp, rcx, times_pointer_size, 0)); 751 __ movq(rbx, Operand(rsp, rcx, times_pointer_size, 0));
745 __ movq(Operand(rsp, rcx, times_pointer_size, 1 * kPointerSize), rbx); 752 __ movq(Operand(rsp, rcx, times_pointer_size, 1 * kPointerSize), rbx);
746 __ decq(rcx); 753 __ decq(rcx);
747 __ j(not_sign, &loop); // While non-negative (to copy return address). 754 __ j(not_sign, &loop); // While non-negative (to copy return address).
748 __ pop(rbx); // Discard copy of return address. 755 __ pop(rbx); // Discard copy of return address.
749 __ decq(rax); // One fewer argument (first argument is new receiver). 756 __ decq(rax); // One fewer argument (first argument is new receiver).
750 } 757 }
751 758
752 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin. 759 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
753 { Label function; 760 // or a function proxy via CALL_FUNCTION_PROXY.
754 __ testq(rdi, rdi); 761 { Label function, non_proxy;
755 __ j(not_zero, &function); 762 __ testq(rdx, rdx);
763 __ j(zero, &function);
756 __ Set(rbx, 0); 764 __ Set(rbx, 0);
765 __ SetCallKind(rcx, CALL_AS_METHOD);
766 __ cmpq(rdx, Immediate(1));
767 __ j(not_equal, &non_proxy);
768
769 __ pop(rdx); // return address
770 __ push(rdi); // re-add proxy object as additional argument
771 __ push(rdx);
772 __ incq(rax);
773 __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY);
774 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
775 RelocInfo::CODE_TARGET);
776
777 __ bind(&non_proxy);
757 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); 778 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
758 __ SetCallKind(rcx, CALL_AS_METHOD);
759 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), 779 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
760 RelocInfo::CODE_TARGET); 780 RelocInfo::CODE_TARGET);
761 __ bind(&function); 781 __ bind(&function);
762 } 782 }
763 783
764 // 5b. Get the code to call from the function and check that the number of 784 // 5b. Get the code to call from the function and check that the number of
765 // expected arguments matches what we're providing. If so, jump 785 // expected arguments matches what we're providing. If so, jump
766 // (tail-call) to the code in register edx without checking arguments. 786 // (tail-call) to the code in register edx without checking arguments.
767 __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); 787 __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
768 __ movsxlq(rbx, 788 __ movsxlq(rbx,
(...skipping 21 matching lines...) Expand all
790 __ EnterInternalFrame(); 810 __ EnterInternalFrame();
791 // Stack frame: 811 // Stack frame:
792 // rbp: Old base pointer 812 // rbp: Old base pointer
793 // rbp[1]: return address 813 // rbp[1]: return address
794 // rbp[2]: function arguments 814 // rbp[2]: function arguments
795 // rbp[3]: receiver 815 // rbp[3]: receiver
796 // rbp[4]: function 816 // rbp[4]: function
797 static const int kArgumentsOffset = 2 * kPointerSize; 817 static const int kArgumentsOffset = 2 * kPointerSize;
798 static const int kReceiverOffset = 3 * kPointerSize; 818 static const int kReceiverOffset = 3 * kPointerSize;
799 static const int kFunctionOffset = 4 * kPointerSize; 819 static const int kFunctionOffset = 4 * kPointerSize;
820
800 __ push(Operand(rbp, kFunctionOffset)); 821 __ push(Operand(rbp, kFunctionOffset));
801 __ push(Operand(rbp, kArgumentsOffset)); 822 __ push(Operand(rbp, kArgumentsOffset));
802 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); 823 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
803 824
804 // Check the stack for overflow. We are not trying need to catch 825 // Check the stack for overflow. We are not trying to catch
805 // interruptions (e.g. debug break and preemption) here, so the "real stack 826 // interruptions (e.g. debug break and preemption) here, so the "real stack
806 // limit" is checked. 827 // limit" is checked.
807 Label okay; 828 Label okay;
808 __ LoadRoot(kScratchRegister, Heap::kRealStackLimitRootIndex); 829 __ LoadRoot(kScratchRegister, Heap::kRealStackLimitRootIndex);
809 __ movq(rcx, rsp); 830 __ movq(rcx, rsp);
810 // Make rcx the space we have left. The stack might already be overflowed 831 // Make rcx the space we have left. The stack might already be overflowed
811 // here which will cause rcx to become negative. 832 // here which will cause rcx to become negative.
812 __ subq(rcx, kScratchRegister); 833 __ subq(rcx, kScratchRegister);
813 // Make rdx the space we need for the array when it is unrolled onto the 834 // Make rdx the space we need for the array when it is unrolled onto the
814 // stack. 835 // stack.
815 __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rax, kPointerSizeLog2); 836 __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rax, kPointerSizeLog2);
816 // Check if the arguments will overflow the stack. 837 // Check if the arguments will overflow the stack.
817 __ cmpq(rcx, rdx); 838 __ cmpq(rcx, rdx);
818 __ j(greater, &okay); // Signed comparison. 839 __ j(greater, &okay); // Signed comparison.
819 840
820 // Out of stack space. 841 // Out of stack space.
821 __ push(Operand(rbp, kFunctionOffset)); 842 __ push(Operand(rbp, kFunctionOffset));
822 __ push(rax); 843 __ push(rax);
823 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); 844 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
824 __ bind(&okay); 845 __ bind(&okay);
825 // End of stack check. 846 // End of stack check.
826 847
827 // Push current index and limit. 848 // Push current index and limit.
828 const int kLimitOffset = 849 const int kLimitOffset =
829 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; 850 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
830 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; 851 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
831 __ push(rax); // limit 852 __ push(rax); // limit
832 __ push(Immediate(0)); // index 853 __ push(Immediate(0)); // index
833 854
834 // Change context eagerly to get the right global object if 855 // Get the receiver.
835 // necessary. 856 __ movq(rbx, Operand(rbp, kReceiverOffset));
857
858 // Check that the function is a JS function (otherwise it must be a proxy).
859 Label push_receiver;
836 __ movq(rdi, Operand(rbp, kFunctionOffset)); 860 __ movq(rdi, Operand(rbp, kFunctionOffset));
861 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
862 __ j(not_equal, &push_receiver);
863
864 // Change context eagerly to get the right global object if necessary.
837 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); 865 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
838 866
839 // Compute the receiver.
840 Label call_to_object, use_global_receiver, push_receiver;
841 __ movq(rbx, Operand(rbp, kReceiverOffset));
842
843 // Do not transform the receiver for strict mode functions. 867 // Do not transform the receiver for strict mode functions.
868 Label call_to_object, use_global_receiver;
844 __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); 869 __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
845 __ testb(FieldOperand(rdx, SharedFunctionInfo::kStrictModeByteOffset), 870 __ testb(FieldOperand(rdx, SharedFunctionInfo::kStrictModeByteOffset),
846 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte)); 871 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
847 __ j(not_equal, &push_receiver); 872 __ j(not_equal, &push_receiver);
848 873
849 // Do not transform the receiver for natives. 874 // Do not transform the receiver for natives.
850 __ testb(FieldOperand(rdx, SharedFunctionInfo::kNativeByteOffset), 875 __ testb(FieldOperand(rdx, SharedFunctionInfo::kNativeByteOffset),
851 Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte)); 876 Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte));
852 __ j(not_equal, &push_receiver); 877 __ j(not_equal, &push_receiver);
853 878
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
906 // Update the index on the stack and in register rax. 931 // Update the index on the stack and in register rax.
907 __ movq(rax, Operand(rbp, kIndexOffset)); 932 __ movq(rax, Operand(rbp, kIndexOffset));
908 __ SmiAddConstant(rax, rax, Smi::FromInt(1)); 933 __ SmiAddConstant(rax, rax, Smi::FromInt(1));
909 __ movq(Operand(rbp, kIndexOffset), rax); 934 __ movq(Operand(rbp, kIndexOffset), rax);
910 935
911 __ bind(&entry); 936 __ bind(&entry);
912 __ cmpq(rax, Operand(rbp, kLimitOffset)); 937 __ cmpq(rax, Operand(rbp, kLimitOffset));
913 __ j(not_equal, &loop); 938 __ j(not_equal, &loop);
914 939
915 // Invoke the function. 940 // Invoke the function.
941 Label call_proxy;
916 ParameterCount actual(rax); 942 ParameterCount actual(rax);
917 __ SmiToInteger32(rax, rax); 943 __ SmiToInteger32(rax, rax);
918 __ movq(rdi, Operand(rbp, kFunctionOffset)); 944 __ movq(rdi, Operand(rbp, kFunctionOffset));
945 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
946 __ j(not_equal, &call_proxy);
919 __ InvokeFunction(rdi, actual, CALL_FUNCTION, 947 __ InvokeFunction(rdi, actual, CALL_FUNCTION,
920 NullCallWrapper(), CALL_AS_METHOD); 948 NullCallWrapper(), CALL_AS_METHOD);
921 949
922 __ LeaveInternalFrame(); 950 __ LeaveInternalFrame();
923 __ ret(3 * kPointerSize); // remove function, receiver, and arguments 951 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
952
953 // Invoke the function proxy.
954 __ bind(&call_proxy);
955 __ push(rdi); // add function proxy as last argument
956 __ incq(rax);
957 __ Set(rbx, 0);
958 __ SetCallKind(rcx, CALL_AS_METHOD);
959 __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY);
960 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
961 RelocInfo::CODE_TARGET);
962
963 __ LeaveInternalFrame();
964 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
924 } 965 }
925 966
926 967
927 // Number of empty elements to allocate for an empty array. 968 // Number of empty elements to allocate for an empty array.
928 static const int kPreallocatedArrayElements = 4; 969 static const int kPreallocatedArrayElements = 4;
929 970
930 971
931 // Allocate an empty JSArray. The allocated array is put into the result 972 // Allocate an empty JSArray. The allocated array is put into the result
932 // register. If the parameter initial_capacity is larger than zero an elements 973 // register. If the parameter initial_capacity is larger than zero an elements
933 // backing store is allocated with this size and filled with the hole values. 974 // backing store is allocated with this size and filled with the hole values.
(...skipping 580 matching lines...) Expand 10 before | Expand all | Expand 10 after
1514 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR); 1555 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR);
1515 generator.Generate(); 1556 generator.Generate();
1516 } 1557 }
1517 1558
1518 1559
1519 #undef __ 1560 #undef __
1520 1561
1521 } } // namespace v8::internal 1562 } } // namespace v8::internal
1522 1563
1523 #endif // V8_TARGET_ARCH_X64 1564 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/v8natives.js ('k') | src/x64/code-stubs-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698