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

Side by Side Diff: src/ia32/code-stubs-ia32.cc

Issue 3338007: Handle argument conversion in StringAddStub. (Closed)
Patch Set: Test added Created 10 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
« no previous file with comments | « src/ia32/code-stubs-ia32.h ('k') | src/ia32/codegen-ia32.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 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 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 850 matching lines...) Expand 10 before | Expand all | Expand 10 after
861 if (static_operands_type_.IsSmi()) { 861 if (static_operands_type_.IsSmi()) {
862 if (FLAG_debug_code) { 862 if (FLAG_debug_code) {
863 __ AbortIfNotSmi(edx); 863 __ AbortIfNotSmi(edx);
864 __ AbortIfNotSmi(eax); 864 __ AbortIfNotSmi(eax);
865 } 865 }
866 FloatingPointHelper::LoadSSE2Smis(masm, ecx); 866 FloatingPointHelper::LoadSSE2Smis(masm, ecx);
867 } else { 867 } else {
868 FloatingPointHelper::LoadSSE2Operands(masm); 868 FloatingPointHelper::LoadSSE2Operands(masm);
869 } 869 }
870 } else { 870 } else {
871 FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime); 871 FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
872 } 872 }
873 873
874 switch (op_) { 874 switch (op_) {
875 case Token::ADD: __ addsd(xmm0, xmm1); break; 875 case Token::ADD: __ addsd(xmm0, xmm1); break;
876 case Token::SUB: __ subsd(xmm0, xmm1); break; 876 case Token::SUB: __ subsd(xmm0, xmm1); break;
877 case Token::MUL: __ mulsd(xmm0, xmm1); break; 877 case Token::MUL: __ mulsd(xmm0, xmm1); break;
878 case Token::DIV: __ divsd(xmm0, xmm1); break; 878 case Token::DIV: __ divsd(xmm0, xmm1); break;
879 default: UNREACHABLE(); 879 default: UNREACHABLE();
880 } 880 }
881 GenerateHeapResultAllocation(masm, &call_runtime); 881 GenerateHeapResultAllocation(masm, &call_runtime);
882 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 882 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
883 GenerateReturn(masm); 883 GenerateReturn(masm);
884 } else { // SSE2 not available, use FPU. 884 } else { // SSE2 not available, use FPU.
885 if (static_operands_type_.IsNumber()) { 885 if (static_operands_type_.IsNumber()) {
886 if (FLAG_debug_code) { 886 if (FLAG_debug_code) {
887 // Assert at runtime that inputs are only numbers. 887 // Assert at runtime that inputs are only numbers.
888 __ AbortIfNotNumber(edx); 888 __ AbortIfNotNumber(edx);
889 __ AbortIfNotNumber(eax); 889 __ AbortIfNotNumber(eax);
890 } 890 }
891 } else { 891 } else {
892 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); 892 FloatingPointHelper::CheckFloatOperands(masm, &not_floats, ebx);
893 } 893 }
894 FloatingPointHelper::LoadFloatOperands( 894 FloatingPointHelper::LoadFloatOperands(
895 masm, 895 masm,
896 ecx, 896 ecx,
897 FloatingPointHelper::ARGS_IN_REGISTERS); 897 FloatingPointHelper::ARGS_IN_REGISTERS);
898 switch (op_) { 898 switch (op_) {
899 case Token::ADD: __ faddp(1); break; 899 case Token::ADD: __ faddp(1); break;
900 case Token::SUB: __ fsubp(1); break; 900 case Token::SUB: __ fsubp(1); break;
901 case Token::MUL: __ fmulp(1); break; 901 case Token::MUL: __ fmulp(1); break;
902 case Token::DIV: __ fdivp(1); break; 902 case Token::DIV: __ fdivp(1); break;
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
994 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 994 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
995 } 995 }
996 GenerateReturn(masm); 996 GenerateReturn(masm);
997 } 997 }
998 break; 998 break;
999 } 999 }
1000 default: UNREACHABLE(); break; 1000 default: UNREACHABLE(); break;
1001 } 1001 }
1002 } 1002 }
1003 1003
1004 // Avoid hitting the string ADD code below when allocation fails in
1005 // the floating point code above.
1006 if (op_ != Token::ADD) {
1007 __ bind(&call_runtime);
1008 }
1009
1004 // If all else fails, use the runtime system to get the correct 1010 // If all else fails, use the runtime system to get the correct
1005 // result. If arguments was passed in registers now place them on the 1011 // result. If arguments was passed in registers now place them on the
1006 // stack in the correct order below the return address. 1012 // stack in the correct order below the return address.
1007 __ bind(&call_runtime);
1008 if (HasArgsInRegisters()) { 1013 if (HasArgsInRegisters()) {
1009 GenerateRegisterArgsPush(masm); 1014 GenerateRegisterArgsPush(masm);
1010 } 1015 }
1011 1016
1012 switch (op_) { 1017 switch (op_) {
1013 case Token::ADD: { 1018 case Token::ADD: {
1014 // Test for string arguments before calling runtime. 1019 // Test for string arguments before calling runtime.
1015 Label not_strings, not_string1, string1, string1_smi2;
1016 1020
1017 // If this stub has already generated FP-specific code then the arguments 1021 // If this stub has already generated FP-specific code then the arguments
1018 // are already in edx, eax 1022 // are already in edx, eax
1019 if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) { 1023 if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) {
1020 GenerateLoadArguments(masm); 1024 GenerateLoadArguments(masm);
1021 } 1025 }
1022 1026
1023 // Registers containing left and right operands respectively. 1027 // Registers containing left and right operands respectively.
1024 Register lhs, rhs; 1028 Register lhs, rhs;
1025 if (HasArgsReversed()) { 1029 if (HasArgsReversed()) {
1026 lhs = eax; 1030 lhs = eax;
1027 rhs = edx; 1031 rhs = edx;
1028 } else { 1032 } else {
1029 lhs = edx; 1033 lhs = edx;
1030 rhs = eax; 1034 rhs = eax;
1031 } 1035 }
1032 1036
1033 // Test if first argument is a string. 1037 // Test if left operand is a string.
1038 Label lhs_not_string;
1034 __ test(lhs, Immediate(kSmiTagMask)); 1039 __ test(lhs, Immediate(kSmiTagMask));
1035 __ j(zero, &not_string1); 1040 __ j(zero, &lhs_not_string);
1036 __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, ecx); 1041 __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, ecx);
1037 __ j(above_equal, &not_string1); 1042 __ j(above_equal, &lhs_not_string);
1038 1043
1039 // First argument is a string, test second. 1044 StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB);
1045 __ TailCallStub(&string_add_left_stub);
1046
1047 // Left operand is not a string, test right.
1048 __ bind(&lhs_not_string);
1040 __ test(rhs, Immediate(kSmiTagMask)); 1049 __ test(rhs, Immediate(kSmiTagMask));
1041 __ j(zero, &string1_smi2); 1050 __ j(zero, &call_runtime);
1042 __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, ecx); 1051 __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, ecx);
1043 __ j(above_equal, &string1); 1052 __ j(above_equal, &call_runtime);
1044 1053
1045 // First and second argument are strings. Jump to the string add stub. 1054 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
1046 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); 1055 __ TailCallStub(&string_add_right_stub);
1047 __ TailCallStub(&string_add_stub);
1048 1056
1049 __ bind(&string1_smi2);
1050 // First argument is a string, second is a smi. Try to lookup the number
1051 // string for the smi in the number string cache.
1052 NumberToStringStub::GenerateLookupNumberStringCache(
1053 masm, rhs, edi, ebx, ecx, true, &string1);
1054
1055 // Replace second argument on stack and tailcall string add stub to make
1056 // the result.
1057 __ mov(Operand(esp, 1 * kPointerSize), edi);
1058 __ TailCallStub(&string_add_stub);
1059
1060 // Only first argument is a string.
1061 __ bind(&string1);
1062 __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION);
1063
1064 // First argument was not a string, test second.
1065 __ bind(&not_string1);
1066 __ test(rhs, Immediate(kSmiTagMask));
1067 __ j(zero, &not_strings);
1068 __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, ecx);
1069 __ j(above_equal, &not_strings);
1070
1071 // Only second argument is a string.
1072 __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION);
1073
1074 __ bind(&not_strings);
1075 // Neither argument is a string. 1057 // Neither argument is a string.
1058 __ bind(&call_runtime);
1059 if (HasArgsInRegisters()) {
1060 GenerateRegisterArgsPush(masm);
1061 }
1076 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 1062 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
1077 break; 1063 break;
1078 } 1064 }
1079 case Token::SUB: 1065 case Token::SUB:
1080 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 1066 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
1081 break; 1067 break;
1082 case Token::MUL: 1068 case Token::MUL:
1083 __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 1069 __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
1084 break; 1070 break;
1085 case Token::DIV: 1071 case Token::DIV:
(...skipping 2672 matching lines...) Expand 10 before | Expand all | Expand 10 after
3758 3744
3759 3745
3760 void StringCharAtGenerator::GenerateSlow( 3746 void StringCharAtGenerator::GenerateSlow(
3761 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { 3747 MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
3762 char_code_at_generator_.GenerateSlow(masm, call_helper); 3748 char_code_at_generator_.GenerateSlow(masm, call_helper);
3763 char_from_code_generator_.GenerateSlow(masm, call_helper); 3749 char_from_code_generator_.GenerateSlow(masm, call_helper);
3764 } 3750 }
3765 3751
3766 3752
3767 void StringAddStub::Generate(MacroAssembler* masm) { 3753 void StringAddStub::Generate(MacroAssembler* masm) {
3768 Label string_add_runtime; 3754 Label string_add_runtime, call_builtin;
3755 Builtins::JavaScript builtin_id = Builtins::ADD;
3769 3756
3770 // Load the two arguments. 3757 // Load the two arguments.
3771 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. 3758 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument.
3772 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. 3759 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument.
3773 3760
3774 // Make sure that both arguments are strings if not known in advance. 3761 // Make sure that both arguments are strings if not known in advance.
3775 if (string_check_) { 3762 if (flags_ == NO_STRING_ADD_FLAGS) {
3776 __ test(eax, Immediate(kSmiTagMask)); 3763 __ test(eax, Immediate(kSmiTagMask));
3777 __ j(zero, &string_add_runtime); 3764 __ j(zero, &string_add_runtime);
3778 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx); 3765 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx);
3779 __ j(above_equal, &string_add_runtime); 3766 __ j(above_equal, &string_add_runtime);
3780 3767
3781 // First argument is a a string, test second. 3768 // First argument is a a string, test second.
3782 __ test(edx, Immediate(kSmiTagMask)); 3769 __ test(edx, Immediate(kSmiTagMask));
3783 __ j(zero, &string_add_runtime); 3770 __ j(zero, &string_add_runtime);
3784 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); 3771 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx);
3785 __ j(above_equal, &string_add_runtime); 3772 __ j(above_equal, &string_add_runtime);
3773 } else {
3774 // Here at least one of the arguments is definitely a string.
3775 // We convert the one that is not known to be a string.
3776 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) {
3777 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0);
3778 GenerateConvertArgument(masm, 2 * kPointerSize, eax, ebx, ecx, edi,
3779 &call_builtin);
3780 builtin_id = Builtins::STRING_ADD_RIGHT;
3781 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) {
3782 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0);
3783 GenerateConvertArgument(masm, 1 * kPointerSize, edx, ebx, ecx, edi,
3784 &call_builtin);
3785 builtin_id = Builtins::STRING_ADD_LEFT;
3786 }
3786 } 3787 }
3787 3788
3788 // Both arguments are strings. 3789 // Both arguments are strings.
3789 // eax: first string 3790 // eax: first string
3790 // edx: second string 3791 // edx: second string
3791 // Check if either of the strings are empty. In that case return the other. 3792 // Check if either of the strings are empty. In that case return the other.
3792 Label second_not_zero_length, both_not_zero_length; 3793 Label second_not_zero_length, both_not_zero_length;
3793 __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); 3794 __ mov(ecx, FieldOperand(edx, String::kLengthOffset));
3794 STATIC_ASSERT(kSmiTag == 0); 3795 STATIC_ASSERT(kSmiTag == 0);
3795 __ test(ecx, Operand(ecx)); 3796 __ test(ecx, Operand(ecx));
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
4009 // ecx: next character of result 4010 // ecx: next character of result
4010 // edx: first char of second argument 4011 // edx: first char of second argument
4011 // edi: length of second argument 4012 // edi: length of second argument
4012 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); 4013 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false);
4013 __ IncrementCounter(&Counters::string_add_native, 1); 4014 __ IncrementCounter(&Counters::string_add_native, 1);
4014 __ ret(2 * kPointerSize); 4015 __ ret(2 * kPointerSize);
4015 4016
4016 // Just jump to runtime to add the two strings. 4017 // Just jump to runtime to add the two strings.
4017 __ bind(&string_add_runtime); 4018 __ bind(&string_add_runtime);
4018 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); 4019 __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
4020
4021 if (call_builtin.is_linked()) {
4022 __ bind(&call_builtin);
4023 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
4024 }
4019 } 4025 }
4020 4026
4021 4027
4028 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
4029 int stack_offset,
4030 Register arg,
4031 Register scratch1,
4032 Register scratch2,
4033 Register scratch3,
4034 Label* slow) {
4035 // First check if the argument is already a string.
4036 Label not_string, done;
4037 __ test(arg, Immediate(kSmiTagMask));
4038 __ j(zero, &not_string);
4039 __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1);
4040 __ j(below, &done);
4041
4042 // Check the number to string cache.
4043 Label not_cached;
4044 __ bind(&not_string);
4045 // Puts the cached result into scratch1.
4046 NumberToStringStub::GenerateLookupNumberStringCache(masm,
4047 arg,
4048 scratch1,
4049 scratch2,
4050 scratch3,
4051 false,
4052 &not_cached);
4053 __ mov(arg, scratch1);
4054 __ mov(Operand(esp, stack_offset), arg);
4055 __ jmp(&done);
4056
4057 // Check if the argument is a safe string wrapper.
4058 __ bind(&not_cached);
4059 __ test(arg, Immediate(kSmiTagMask));
4060 __ j(zero, slow);
4061 __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1); // map -> scratch1.
4062 __ j(not_equal, slow);
4063 __ test_b(FieldOperand(scratch1, Map::kBitField2Offset),
4064 1 << Map::kStringWrapperSafeForDefaultValueOf);
4065 __ j(zero, slow);
4066 __ mov(arg, FieldOperand(arg, JSValue::kValueOffset));
4067 __ mov(Operand(esp, stack_offset), arg);
4068
4069 __ bind(&done);
4070 }
4071
4072
4022 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, 4073 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
4023 Register dest, 4074 Register dest,
4024 Register src, 4075 Register src,
4025 Register count, 4076 Register count,
4026 Register scratch, 4077 Register scratch,
4027 bool ascii) { 4078 bool ascii) {
4028 Label loop; 4079 Label loop;
4029 __ bind(&loop); 4080 __ bind(&loop);
4030 // This loop just copies one character at a time, as it is only used for very 4081 // This loop just copies one character at a time, as it is only used for very
4031 // short strings. 4082 // short strings.
(...skipping 520 matching lines...) Expand 10 before | Expand all | Expand 10 after
4552 // tagged as a small integer. 4603 // tagged as a small integer.
4553 __ bind(&runtime); 4604 __ bind(&runtime);
4554 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 4605 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
4555 } 4606 }
4556 4607
4557 #undef __ 4608 #undef __
4558 4609
4559 } } // namespace v8::internal 4610 } } // namespace v8::internal
4560 4611
4561 #endif // V8_TARGET_ARCH_IA32 4612 #endif // V8_TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « src/ia32/code-stubs-ia32.h ('k') | src/ia32/codegen-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698