OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_X87 | 7 #if V8_TARGET_ARCH_X87 |
8 | 8 |
9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
10 #include "src/deoptimizer.h" | 10 #include "src/deoptimizer.h" |
(...skipping 747 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
758 // 1 ~ return address. | 758 // 1 ~ return address. |
759 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); | 759 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); |
760 __ JumpIfSmi(edi, &non_function); | 760 __ JumpIfSmi(edi, &non_function); |
761 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | 761 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
762 __ j(not_equal, &slow); | 762 __ j(not_equal, &slow); |
763 | 763 |
764 | 764 |
765 // 3a. Patch the first argument if necessary when calling a function. | 765 // 3a. Patch the first argument if necessary when calling a function. |
766 Label shift_arguments; | 766 Label shift_arguments; |
767 __ Move(edx, Immediate(0)); // indicate regular JS_FUNCTION | 767 __ Move(edx, Immediate(0)); // indicate regular JS_FUNCTION |
768 { Label convert_to_object, use_global_receiver, patch_receiver; | 768 { Label convert_to_object, use_global_proxy, patch_receiver; |
769 // Change context eagerly in case we need the global receiver. | 769 // Change context eagerly in case we need the global receiver. |
770 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 770 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
771 | 771 |
772 // Do not transform the receiver for strict mode functions. | 772 // Do not transform the receiver for strict mode functions. |
773 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 773 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
774 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset), | 774 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset), |
775 1 << SharedFunctionInfo::kStrictModeBitWithinByte); | 775 1 << SharedFunctionInfo::kStrictModeBitWithinByte); |
776 __ j(not_equal, &shift_arguments); | 776 __ j(not_equal, &shift_arguments); |
777 | 777 |
778 // Do not transform the receiver for natives (shared already in ebx). | 778 // Do not transform the receiver for natives (shared already in ebx). |
779 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kNativeByteOffset), | 779 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kNativeByteOffset), |
780 1 << SharedFunctionInfo::kNativeBitWithinByte); | 780 1 << SharedFunctionInfo::kNativeBitWithinByte); |
781 __ j(not_equal, &shift_arguments); | 781 __ j(not_equal, &shift_arguments); |
782 | 782 |
783 // Compute the receiver in sloppy mode. | 783 // Compute the receiver in sloppy mode. |
784 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument. | 784 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument. |
785 | 785 |
786 // Call ToObject on the receiver if it is not an object, or use the | 786 // Call ToObject on the receiver if it is not an object, or use the |
787 // global object if it is null or undefined. | 787 // global object if it is null or undefined. |
788 __ JumpIfSmi(ebx, &convert_to_object); | 788 __ JumpIfSmi(ebx, &convert_to_object); |
789 __ cmp(ebx, factory->null_value()); | 789 __ cmp(ebx, factory->null_value()); |
790 __ j(equal, &use_global_receiver); | 790 __ j(equal, &use_global_proxy); |
791 __ cmp(ebx, factory->undefined_value()); | 791 __ cmp(ebx, factory->undefined_value()); |
792 __ j(equal, &use_global_receiver); | 792 __ j(equal, &use_global_proxy); |
793 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); | 793 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); |
794 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx); | 794 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx); |
795 __ j(above_equal, &shift_arguments); | 795 __ j(above_equal, &shift_arguments); |
796 | 796 |
797 __ bind(&convert_to_object); | 797 __ bind(&convert_to_object); |
798 | 798 |
799 { // In order to preserve argument count. | 799 { // In order to preserve argument count. |
800 FrameScope scope(masm, StackFrame::INTERNAL); | 800 FrameScope scope(masm, StackFrame::INTERNAL); |
801 __ SmiTag(eax); | 801 __ SmiTag(eax); |
802 __ push(eax); | 802 __ push(eax); |
803 | 803 |
804 __ push(ebx); | 804 __ push(ebx); |
805 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 805 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
806 __ mov(ebx, eax); | 806 __ mov(ebx, eax); |
807 __ Move(edx, Immediate(0)); // restore | 807 __ Move(edx, Immediate(0)); // restore |
808 | 808 |
809 __ pop(eax); | 809 __ pop(eax); |
810 __ SmiUntag(eax); | 810 __ SmiUntag(eax); |
811 } | 811 } |
812 | 812 |
813 // Restore the function to edi. | 813 // Restore the function to edi. |
814 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); | 814 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); |
815 __ jmp(&patch_receiver); | 815 __ jmp(&patch_receiver); |
816 | 816 |
817 __ bind(&use_global_receiver); | 817 __ bind(&use_global_proxy); |
818 __ mov(ebx, | 818 __ mov(ebx, |
819 Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); | 819 Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
820 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); | 820 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalProxyOffset)); |
821 | 821 |
822 __ bind(&patch_receiver); | 822 __ bind(&patch_receiver); |
823 __ mov(Operand(esp, eax, times_4, 0), ebx); | 823 __ mov(Operand(esp, eax, times_4, 0), ebx); |
824 | 824 |
825 __ jmp(&shift_arguments); | 825 __ jmp(&shift_arguments); |
826 } | 826 } |
827 | 827 |
828 // 3b. Check for function proxy. | 828 // 3b. Check for function proxy. |
829 __ bind(&slow); | 829 __ bind(&slow); |
830 __ Move(edx, Immediate(1)); // indicate function proxy | 830 __ Move(edx, Immediate(1)); // indicate function proxy |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
936 const int kLimitOffset = | 936 const int kLimitOffset = |
937 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; | 937 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; |
938 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; | 938 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; |
939 __ push(eax); // limit | 939 __ push(eax); // limit |
940 __ push(Immediate(0)); // index | 940 __ push(Immediate(0)); // index |
941 | 941 |
942 // Get the receiver. | 942 // Get the receiver. |
943 __ mov(ebx, Operand(ebp, kReceiverOffset)); | 943 __ mov(ebx, Operand(ebp, kReceiverOffset)); |
944 | 944 |
945 // Check that the function is a JS function (otherwise it must be a proxy). | 945 // Check that the function is a JS function (otherwise it must be a proxy). |
946 Label push_receiver, use_global_receiver; | 946 Label push_receiver, use_global_proxy; |
947 __ mov(edi, Operand(ebp, kFunctionOffset)); | 947 __ mov(edi, Operand(ebp, kFunctionOffset)); |
948 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | 948 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
949 __ j(not_equal, &push_receiver); | 949 __ j(not_equal, &push_receiver); |
950 | 950 |
951 // Change context eagerly to get the right global object if necessary. | 951 // Change context eagerly to get the right global object if necessary. |
952 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 952 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
953 | 953 |
954 // Compute the receiver. | 954 // Compute the receiver. |
955 // Do not transform the receiver for strict mode functions. | 955 // Do not transform the receiver for strict mode functions. |
956 Label call_to_object; | 956 Label call_to_object; |
957 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 957 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
958 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset), | 958 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset), |
959 1 << SharedFunctionInfo::kStrictModeBitWithinByte); | 959 1 << SharedFunctionInfo::kStrictModeBitWithinByte); |
960 __ j(not_equal, &push_receiver); | 960 __ j(not_equal, &push_receiver); |
961 | 961 |
962 Factory* factory = masm->isolate()->factory(); | 962 Factory* factory = masm->isolate()->factory(); |
963 | 963 |
964 // Do not transform the receiver for natives (shared already in ecx). | 964 // Do not transform the receiver for natives (shared already in ecx). |
965 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset), | 965 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset), |
966 1 << SharedFunctionInfo::kNativeBitWithinByte); | 966 1 << SharedFunctionInfo::kNativeBitWithinByte); |
967 __ j(not_equal, &push_receiver); | 967 __ j(not_equal, &push_receiver); |
968 | 968 |
969 // Compute the receiver in sloppy mode. | 969 // Compute the receiver in sloppy mode. |
970 // Call ToObject on the receiver if it is not an object, or use the | 970 // Call ToObject on the receiver if it is not an object, or use the |
971 // global object if it is null or undefined. | 971 // global object if it is null or undefined. |
972 __ JumpIfSmi(ebx, &call_to_object); | 972 __ JumpIfSmi(ebx, &call_to_object); |
973 __ cmp(ebx, factory->null_value()); | 973 __ cmp(ebx, factory->null_value()); |
974 __ j(equal, &use_global_receiver); | 974 __ j(equal, &use_global_proxy); |
975 __ cmp(ebx, factory->undefined_value()); | 975 __ cmp(ebx, factory->undefined_value()); |
976 __ j(equal, &use_global_receiver); | 976 __ j(equal, &use_global_proxy); |
977 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); | 977 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); |
978 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx); | 978 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx); |
979 __ j(above_equal, &push_receiver); | 979 __ j(above_equal, &push_receiver); |
980 | 980 |
981 __ bind(&call_to_object); | 981 __ bind(&call_to_object); |
982 __ push(ebx); | 982 __ push(ebx); |
983 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 983 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
984 __ mov(ebx, eax); | 984 __ mov(ebx, eax); |
985 __ jmp(&push_receiver); | 985 __ jmp(&push_receiver); |
986 | 986 |
987 __ bind(&use_global_receiver); | 987 __ bind(&use_global_proxy); |
988 __ mov(ebx, | 988 __ mov(ebx, |
989 Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); | 989 Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
990 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); | 990 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalProxyOffset)); |
991 | 991 |
992 // Push the receiver. | 992 // Push the receiver. |
993 __ bind(&push_receiver); | 993 __ bind(&push_receiver); |
994 __ push(ebx); | 994 __ push(ebx); |
995 | 995 |
996 // Copy all arguments from the array to the stack. | 996 // Copy all arguments from the array to the stack. |
997 Label entry, loop; | 997 Label entry, loop; |
998 Register receiver = LoadIC::ReceiverRegister(); | 998 Register receiver = LoadIC::ReceiverRegister(); |
999 Register key = LoadIC::NameRegister(); | 999 Register key = LoadIC::NameRegister(); |
1000 __ mov(key, Operand(ebp, kIndexOffset)); | 1000 __ mov(key, Operand(ebp, kIndexOffset)); |
(...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1445 | 1445 |
1446 __ bind(&ok); | 1446 __ bind(&ok); |
1447 __ ret(0); | 1447 __ ret(0); |
1448 } | 1448 } |
1449 | 1449 |
1450 #undef __ | 1450 #undef __ |
1451 } | 1451 } |
1452 } // namespace v8::internal | 1452 } // namespace v8::internal |
1453 | 1453 |
1454 #endif // V8_TARGET_ARCH_X87 | 1454 #endif // V8_TARGET_ARCH_X87 |
OLD | NEW |