| OLD | NEW |
| 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 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 | 196 |
| 197 // Return and remove the on-stack parameters. | 197 // Return and remove the on-stack parameters. |
| 198 __ ret(3 * kPointerSize); | 198 __ ret(3 * kPointerSize); |
| 199 | 199 |
| 200 __ bind(&slow_case); | 200 __ bind(&slow_case); |
| 201 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); | 201 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); |
| 202 } | 202 } |
| 203 | 203 |
| 204 | 204 |
| 205 void ToBooleanStub::Generate(MacroAssembler* masm) { | 205 void ToBooleanStub::Generate(MacroAssembler* masm) { |
| 206 Label false_result, true_result, not_string; | 206 NearLabel false_result, true_result, not_string; |
| 207 __ movq(rax, Operand(rsp, 1 * kPointerSize)); | 207 __ movq(rax, Operand(rsp, 1 * kPointerSize)); |
| 208 | 208 |
| 209 // 'null' => false. | 209 // 'null' => false. |
| 210 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 210 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
| 211 __ j(equal, &false_result); | 211 __ j(equal, &false_result); |
| 212 | 212 |
| 213 // Get the map and type of the heap object. | 213 // Get the map and type of the heap object. |
| 214 // We don't use CmpObjectType because we manipulate the type field. | 214 // We don't use CmpObjectType because we manipulate the type field. |
| 215 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); | 215 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 216 __ movzxbq(rcx, FieldOperand(rdx, Map::kInstanceTypeOffset)); | 216 __ movzxbq(rcx, FieldOperand(rdx, Map::kInstanceTypeOffset)); |
| (...skipping 765 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 982 } | 982 } |
| 983 | 983 |
| 984 | 984 |
| 985 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { | 985 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
| 986 // Input on stack: | 986 // Input on stack: |
| 987 // rsp[8]: argument (should be number). | 987 // rsp[8]: argument (should be number). |
| 988 // rsp[0]: return address. | 988 // rsp[0]: return address. |
| 989 Label runtime_call; | 989 Label runtime_call; |
| 990 Label runtime_call_clear_stack; | 990 Label runtime_call_clear_stack; |
| 991 Label input_not_smi; | 991 Label input_not_smi; |
| 992 Label loaded; | 992 NearLabel loaded; |
| 993 // Test that rax is a number. | 993 // Test that rax is a number. |
| 994 __ movq(rax, Operand(rsp, kPointerSize)); | 994 __ movq(rax, Operand(rsp, kPointerSize)); |
| 995 __ JumpIfNotSmi(rax, &input_not_smi); | 995 __ JumpIfNotSmi(rax, &input_not_smi); |
| 996 // Input is a smi. Untag and load it onto the FPU stack. | 996 // Input is a smi. Untag and load it onto the FPU stack. |
| 997 // Then load the bits of the double into rbx. | 997 // Then load the bits of the double into rbx. |
| 998 __ SmiToInteger32(rax, rax); | 998 __ SmiToInteger32(rax, rax); |
| 999 __ subq(rsp, Immediate(kPointerSize)); | 999 __ subq(rsp, Immediate(kPointerSize)); |
| 1000 __ cvtlsi2sd(xmm1, rax); | 1000 __ cvtlsi2sd(xmm1, rax); |
| 1001 __ movsd(Operand(rsp, 0), xmm1); | 1001 __ movsd(Operand(rsp, 0), xmm1); |
| 1002 __ movq(rbx, xmm1); | 1002 __ movq(rbx, xmm1); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1062 CHECK_EQ(16, static_cast<int>(elem2_start - elem_start)); | 1062 CHECK_EQ(16, static_cast<int>(elem2_start - elem_start)); |
| 1063 CHECK_EQ(0, static_cast<int>(elem_in0 - elem_start)); | 1063 CHECK_EQ(0, static_cast<int>(elem_in0 - elem_start)); |
| 1064 CHECK_EQ(kIntSize, static_cast<int>(elem_in1 - elem_start)); | 1064 CHECK_EQ(kIntSize, static_cast<int>(elem_in1 - elem_start)); |
| 1065 CHECK_EQ(2 * kIntSize, static_cast<int>(elem_out - elem_start)); | 1065 CHECK_EQ(2 * kIntSize, static_cast<int>(elem_out - elem_start)); |
| 1066 } | 1066 } |
| 1067 #endif | 1067 #endif |
| 1068 // Find the address of the rcx'th entry in the cache, i.e., &rax[rcx*16]. | 1068 // Find the address of the rcx'th entry in the cache, i.e., &rax[rcx*16]. |
| 1069 __ addl(rcx, rcx); | 1069 __ addl(rcx, rcx); |
| 1070 __ lea(rcx, Operand(rax, rcx, times_8, 0)); | 1070 __ lea(rcx, Operand(rax, rcx, times_8, 0)); |
| 1071 // Check if cache matches: Double value is stored in uint32_t[2] array. | 1071 // Check if cache matches: Double value is stored in uint32_t[2] array. |
| 1072 Label cache_miss; | 1072 NearLabel cache_miss; |
| 1073 __ cmpq(rbx, Operand(rcx, 0)); | 1073 __ cmpq(rbx, Operand(rcx, 0)); |
| 1074 __ j(not_equal, &cache_miss); | 1074 __ j(not_equal, &cache_miss); |
| 1075 // Cache hit! | 1075 // Cache hit! |
| 1076 __ movq(rax, Operand(rcx, 2 * kIntSize)); | 1076 __ movq(rax, Operand(rcx, 2 * kIntSize)); |
| 1077 __ fstp(0); // Clear FPU stack. | 1077 __ fstp(0); // Clear FPU stack. |
| 1078 __ ret(kPointerSize); | 1078 __ ret(kPointerSize); |
| 1079 | 1079 |
| 1080 __ bind(&cache_miss); | 1080 __ bind(&cache_miss); |
| 1081 // Update cache with new value. | 1081 // Update cache with new value. |
| 1082 Label nan_result; | 1082 Label nan_result; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1153 __ fnstsw_ax(); | 1153 __ fnstsw_ax(); |
| 1154 // Clear if Illegal Operand or Zero Division exceptions are set. | 1154 // Clear if Illegal Operand or Zero Division exceptions are set. |
| 1155 __ testl(rax, Immediate(5)); // #IO and #ZD flags of FPU status word. | 1155 __ testl(rax, Immediate(5)); // #IO and #ZD flags of FPU status word. |
| 1156 __ j(zero, &no_exceptions); | 1156 __ j(zero, &no_exceptions); |
| 1157 __ fnclex(); | 1157 __ fnclex(); |
| 1158 __ bind(&no_exceptions); | 1158 __ bind(&no_exceptions); |
| 1159 } | 1159 } |
| 1160 | 1160 |
| 1161 // Compute st(0) % st(1) | 1161 // Compute st(0) % st(1) |
| 1162 { | 1162 { |
| 1163 Label partial_remainder_loop; | 1163 NearLabel partial_remainder_loop; |
| 1164 __ bind(&partial_remainder_loop); | 1164 __ bind(&partial_remainder_loop); |
| 1165 __ fprem1(); | 1165 __ fprem1(); |
| 1166 __ fwait(); | 1166 __ fwait(); |
| 1167 __ fnstsw_ax(); | 1167 __ fnstsw_ax(); |
| 1168 __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word. | 1168 __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word. |
| 1169 // If C2 is set, computation only has partial result. Loop to | 1169 // If C2 is set, computation only has partial result. Loop to |
| 1170 // continue computation. | 1170 // continue computation. |
| 1171 __ j(not_zero, &partial_remainder_loop); | 1171 __ j(not_zero, &partial_remainder_loop); |
| 1172 } | 1172 } |
| 1173 // FPU Stack: input, 2*pi, input % 2*pi | 1173 // FPU Stack: input, 2*pi, input % 2*pi |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1195 void IntegerConvert(MacroAssembler* masm, | 1195 void IntegerConvert(MacroAssembler* masm, |
| 1196 Register result, | 1196 Register result, |
| 1197 Register source) { | 1197 Register source) { |
| 1198 // Result may be rcx. If result and source are the same register, source will | 1198 // Result may be rcx. If result and source are the same register, source will |
| 1199 // be overwritten. | 1199 // be overwritten. |
| 1200 ASSERT(!result.is(rdi) && !result.is(rbx)); | 1200 ASSERT(!result.is(rdi) && !result.is(rbx)); |
| 1201 // TODO(lrn): When type info reaches here, if value is a 32-bit integer, use | 1201 // TODO(lrn): When type info reaches here, if value is a 32-bit integer, use |
| 1202 // cvttsd2si (32-bit version) directly. | 1202 // cvttsd2si (32-bit version) directly. |
| 1203 Register double_exponent = rbx; | 1203 Register double_exponent = rbx; |
| 1204 Register double_value = rdi; | 1204 Register double_value = rdi; |
| 1205 Label done, exponent_63_plus; | 1205 NearLabel done, exponent_63_plus; |
| 1206 // Get double and extract exponent. | 1206 // Get double and extract exponent. |
| 1207 __ movq(double_value, FieldOperand(source, HeapNumber::kValueOffset)); | 1207 __ movq(double_value, FieldOperand(source, HeapNumber::kValueOffset)); |
| 1208 // Clear result preemptively, in case we need to return zero. | 1208 // Clear result preemptively, in case we need to return zero. |
| 1209 __ xorl(result, result); | 1209 __ xorl(result, result); |
| 1210 __ movq(xmm0, double_value); // Save copy in xmm0 in case we need it there. | 1210 __ movq(xmm0, double_value); // Save copy in xmm0 in case we need it there. |
| 1211 // Double to remove sign bit, shift exponent down to least significant bits. | 1211 // Double to remove sign bit, shift exponent down to least significant bits. |
| 1212 // and subtract bias to get the unshifted, unbiased exponent. | 1212 // and subtract bias to get the unshifted, unbiased exponent. |
| 1213 __ lea(double_exponent, Operand(double_value, double_value, times_1, 0)); | 1213 __ lea(double_exponent, Operand(double_value, double_value, times_1, 0)); |
| 1214 __ shr(double_exponent, Immediate(64 - HeapNumber::kExponentBits)); | 1214 __ shr(double_exponent, Immediate(64 - HeapNumber::kExponentBits)); |
| 1215 __ subl(double_exponent, Immediate(HeapNumber::kExponentBias)); | 1215 __ subl(double_exponent, Immediate(HeapNumber::kExponentBias)); |
| (...skipping 535 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1751 // Check that the last match info has space for the capture registers and the | 1751 // Check that the last match info has space for the capture registers and the |
| 1752 // additional information. Ensure no overflow in add. | 1752 // additional information. Ensure no overflow in add. |
| 1753 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); | 1753 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); |
| 1754 __ SmiToInteger32(rax, FieldOperand(rbx, FixedArray::kLengthOffset)); | 1754 __ SmiToInteger32(rax, FieldOperand(rbx, FixedArray::kLengthOffset)); |
| 1755 __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead)); | 1755 __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead)); |
| 1756 __ cmpl(rdx, rax); | 1756 __ cmpl(rdx, rax); |
| 1757 __ j(greater, &runtime); | 1757 __ j(greater, &runtime); |
| 1758 | 1758 |
| 1759 // rcx: RegExp data (FixedArray) | 1759 // rcx: RegExp data (FixedArray) |
| 1760 // Check the representation and encoding of the subject string. | 1760 // Check the representation and encoding of the subject string. |
| 1761 Label seq_ascii_string, seq_two_byte_string, check_code; | 1761 NearLabel seq_ascii_string, seq_two_byte_string, check_code; |
| 1762 __ movq(rax, Operand(rsp, kSubjectOffset)); | 1762 __ movq(rax, Operand(rsp, kSubjectOffset)); |
| 1763 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 1763 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 1764 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 1764 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 1765 // First check for flat two byte string. | 1765 // First check for flat two byte string. |
| 1766 __ andb(rbx, Immediate( | 1766 __ andb(rbx, Immediate( |
| 1767 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask)); | 1767 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask)); |
| 1768 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); | 1768 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); |
| 1769 __ j(zero, &seq_two_byte_string); | 1769 __ j(zero, &seq_two_byte_string); |
| 1770 // Any other flat string must be a flat ascii string. | 1770 // Any other flat string must be a flat ascii string. |
| 1771 __ testb(rbx, Immediate(kIsNotStringMask | kStringRepresentationMask)); | 1771 __ testb(rbx, Immediate(kIsNotStringMask | kStringRepresentationMask)); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1876 #endif | 1876 #endif |
| 1877 | 1877 |
| 1878 // Keep track on aliasing between argX defined above and the registers used. | 1878 // Keep track on aliasing between argX defined above and the registers used. |
| 1879 // rax: subject string | 1879 // rax: subject string |
| 1880 // rbx: previous index | 1880 // rbx: previous index |
| 1881 // rdi: encoding of subject string (1 if ascii 0 if two_byte); | 1881 // rdi: encoding of subject string (1 if ascii 0 if two_byte); |
| 1882 // r11: code | 1882 // r11: code |
| 1883 | 1883 |
| 1884 // Argument 4: End of string data | 1884 // Argument 4: End of string data |
| 1885 // Argument 3: Start of string data | 1885 // Argument 3: Start of string data |
| 1886 Label setup_two_byte, setup_rest; | 1886 NearLabel setup_two_byte, setup_rest; |
| 1887 __ testb(rdi, rdi); | 1887 __ testb(rdi, rdi); |
| 1888 __ j(zero, &setup_two_byte); | 1888 __ j(zero, &setup_two_byte); |
| 1889 __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset)); | 1889 __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset)); |
| 1890 __ lea(arg4, FieldOperand(rax, rdi, times_1, SeqAsciiString::kHeaderSize)); | 1890 __ lea(arg4, FieldOperand(rax, rdi, times_1, SeqAsciiString::kHeaderSize)); |
| 1891 __ lea(arg3, FieldOperand(rax, rbx, times_1, SeqAsciiString::kHeaderSize)); | 1891 __ lea(arg3, FieldOperand(rax, rbx, times_1, SeqAsciiString::kHeaderSize)); |
| 1892 __ jmp(&setup_rest); | 1892 __ jmp(&setup_rest); |
| 1893 __ bind(&setup_two_byte); | 1893 __ bind(&setup_two_byte); |
| 1894 __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset)); | 1894 __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset)); |
| 1895 __ lea(arg4, FieldOperand(rax, rdi, times_2, SeqTwoByteString::kHeaderSize)); | 1895 __ lea(arg4, FieldOperand(rax, rdi, times_2, SeqTwoByteString::kHeaderSize)); |
| 1896 __ lea(arg3, FieldOperand(rax, rbx, times_2, SeqTwoByteString::kHeaderSize)); | 1896 __ lea(arg3, FieldOperand(rax, rbx, times_2, SeqTwoByteString::kHeaderSize)); |
| 1897 | 1897 |
| 1898 __ bind(&setup_rest); | 1898 __ bind(&setup_rest); |
| 1899 // Argument 2: Previous index. | 1899 // Argument 2: Previous index. |
| 1900 __ movq(arg2, rbx); | 1900 __ movq(arg2, rbx); |
| 1901 | 1901 |
| 1902 // Argument 1: Subject string. | 1902 // Argument 1: Subject string. |
| 1903 __ movq(arg1, rax); | 1903 __ movq(arg1, rax); |
| 1904 | 1904 |
| 1905 // Locate the code entry and call it. | 1905 // Locate the code entry and call it. |
| 1906 __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); | 1906 __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); |
| 1907 __ CallCFunction(r11, kRegExpExecuteArguments); | 1907 __ CallCFunction(r11, kRegExpExecuteArguments); |
| 1908 | 1908 |
| 1909 // rsi is caller save, as it is used to pass parameter. | 1909 // rsi is caller save, as it is used to pass parameter. |
| 1910 __ pop(rsi); | 1910 __ pop(rsi); |
| 1911 | 1911 |
| 1912 // Check the result. | 1912 // Check the result. |
| 1913 Label success; | 1913 NearLabel success; |
| 1914 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::SUCCESS)); | 1914 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::SUCCESS)); |
| 1915 __ j(equal, &success); | 1915 __ j(equal, &success); |
| 1916 Label failure; | 1916 NearLabel failure; |
| 1917 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE)); | 1917 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE)); |
| 1918 __ j(equal, &failure); | 1918 __ j(equal, &failure); |
| 1919 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION)); | 1919 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION)); |
| 1920 // If not exception it can only be retry. Handle that in the runtime system. | 1920 // If not exception it can only be retry. Handle that in the runtime system. |
| 1921 __ j(not_equal, &runtime); | 1921 __ j(not_equal, &runtime); |
| 1922 // Result must now be exception. If there is no pending exception already a | 1922 // Result must now be exception. If there is no pending exception already a |
| 1923 // stack overflow (on the backtrack stack) was detected in RegExp code but | 1923 // stack overflow (on the backtrack stack) was detected in RegExp code but |
| 1924 // haven't created the exception yet. Handle that in the runtime system. | 1924 // haven't created the exception yet. Handle that in the runtime system. |
| 1925 // TODO(592): Rerunning the RegExp to get the stack overflow exception. | 1925 // TODO(592): Rerunning the RegExp to get the stack overflow exception. |
| 1926 ExternalReference pending_exception_address(Top::k_pending_exception_address); | 1926 ExternalReference pending_exception_address(Top::k_pending_exception_address); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1961 __ movq(FieldOperand(rbx, RegExpImpl::kLastInputOffset), rax); | 1961 __ movq(FieldOperand(rbx, RegExpImpl::kLastInputOffset), rax); |
| 1962 __ movq(rcx, rbx); | 1962 __ movq(rcx, rbx); |
| 1963 __ RecordWrite(rcx, RegExpImpl::kLastInputOffset, rax, rdi); | 1963 __ RecordWrite(rcx, RegExpImpl::kLastInputOffset, rax, rdi); |
| 1964 | 1964 |
| 1965 // Get the static offsets vector filled by the native regexp code. | 1965 // Get the static offsets vector filled by the native regexp code. |
| 1966 __ movq(rcx, ExternalReference::address_of_static_offsets_vector()); | 1966 __ movq(rcx, ExternalReference::address_of_static_offsets_vector()); |
| 1967 | 1967 |
| 1968 // rbx: last_match_info backing store (FixedArray) | 1968 // rbx: last_match_info backing store (FixedArray) |
| 1969 // rcx: offsets vector | 1969 // rcx: offsets vector |
| 1970 // rdx: number of capture registers | 1970 // rdx: number of capture registers |
| 1971 Label next_capture, done; | 1971 NearLabel next_capture, done; |
| 1972 // Capture register counter starts from number of capture registers and | 1972 // Capture register counter starts from number of capture registers and |
| 1973 // counts down until wraping after zero. | 1973 // counts down until wraping after zero. |
| 1974 __ bind(&next_capture); | 1974 __ bind(&next_capture); |
| 1975 __ subq(rdx, Immediate(1)); | 1975 __ subq(rdx, Immediate(1)); |
| 1976 __ j(negative, &done); | 1976 __ j(negative, &done); |
| 1977 // Read the value from the static offsets vector buffer and make it a smi. | 1977 // Read the value from the static offsets vector buffer and make it a smi. |
| 1978 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); | 1978 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); |
| 1979 __ Integer32ToSmi(rdi, rdi, &runtime); | 1979 __ Integer32ToSmi(rdi, rdi, &runtime); |
| 1980 // Store the smi value in the last match info. | 1980 // Store the smi value in the last match info. |
| 1981 __ movq(FieldOperand(rbx, | 1981 __ movq(FieldOperand(rbx, |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2115 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); | 2115 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); |
| 2116 | 2116 |
| 2117 Label check_unequal_objects, done; | 2117 Label check_unequal_objects, done; |
| 2118 // The compare stub returns a positive, negative, or zero 64-bit integer | 2118 // The compare stub returns a positive, negative, or zero 64-bit integer |
| 2119 // value in rax, corresponding to result of comparing the two inputs. | 2119 // value in rax, corresponding to result of comparing the two inputs. |
| 2120 // NOTICE! This code is only reached after a smi-fast-case check, so | 2120 // NOTICE! This code is only reached after a smi-fast-case check, so |
| 2121 // it is certain that at least one operand isn't a smi. | 2121 // it is certain that at least one operand isn't a smi. |
| 2122 | 2122 |
| 2123 // Two identical objects are equal unless they are both NaN or undefined. | 2123 // Two identical objects are equal unless they are both NaN or undefined. |
| 2124 { | 2124 { |
| 2125 Label not_identical; | 2125 NearLabel not_identical; |
| 2126 __ cmpq(rax, rdx); | 2126 __ cmpq(rax, rdx); |
| 2127 __ j(not_equal, ¬_identical); | 2127 __ j(not_equal, ¬_identical); |
| 2128 | 2128 |
| 2129 if (cc_ != equal) { | 2129 if (cc_ != equal) { |
| 2130 // Check for undefined. undefined OP undefined is false even though | 2130 // Check for undefined. undefined OP undefined is false even though |
| 2131 // undefined == undefined. | 2131 // undefined == undefined. |
| 2132 Label check_for_nan; | 2132 NearLabel check_for_nan; |
| 2133 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); | 2133 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); |
| 2134 __ j(not_equal, &check_for_nan); | 2134 __ j(not_equal, &check_for_nan); |
| 2135 __ Set(rax, NegativeComparisonResult(cc_)); | 2135 __ Set(rax, NegativeComparisonResult(cc_)); |
| 2136 __ ret(0); | 2136 __ ret(0); |
| 2137 __ bind(&check_for_nan); | 2137 __ bind(&check_for_nan); |
| 2138 } | 2138 } |
| 2139 | 2139 |
| 2140 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), | 2140 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), |
| 2141 // so we do the second best thing - test it ourselves. | 2141 // so we do the second best thing - test it ourselves. |
| 2142 // Note: if cc_ != equal, never_nan_nan_ is not used. | 2142 // Note: if cc_ != equal, never_nan_nan_ is not used. |
| 2143 // We cannot set rax to EQUAL until just before return because | 2143 // We cannot set rax to EQUAL until just before return because |
| 2144 // rax must be unchanged on jump to not_identical. | 2144 // rax must be unchanged on jump to not_identical. |
| 2145 | 2145 |
| 2146 if (never_nan_nan_ && (cc_ == equal)) { | 2146 if (never_nan_nan_ && (cc_ == equal)) { |
| 2147 __ Set(rax, EQUAL); | 2147 __ Set(rax, EQUAL); |
| 2148 __ ret(0); | 2148 __ ret(0); |
| 2149 } else { | 2149 } else { |
| 2150 Label heap_number; | 2150 NearLabel heap_number; |
| 2151 // If it's not a heap number, then return equal for (in)equality operator. | 2151 // If it's not a heap number, then return equal for (in)equality operator. |
| 2152 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), | 2152 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), |
| 2153 Factory::heap_number_map()); | 2153 Factory::heap_number_map()); |
| 2154 __ j(equal, &heap_number); | 2154 __ j(equal, &heap_number); |
| 2155 if (cc_ != equal) { | 2155 if (cc_ != equal) { |
| 2156 // Call runtime on identical JSObjects. Otherwise return equal. | 2156 // Call runtime on identical JSObjects. Otherwise return equal. |
| 2157 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); | 2157 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); |
| 2158 __ j(above_equal, ¬_identical); | 2158 __ j(above_equal, ¬_identical); |
| 2159 } | 2159 } |
| 2160 __ Set(rax, EQUAL); | 2160 __ Set(rax, EQUAL); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2204 | 2204 |
| 2205 __ bind(¬_smis); | 2205 __ bind(¬_smis); |
| 2206 } | 2206 } |
| 2207 | 2207 |
| 2208 // If either operand is a JSObject or an oddball value, then they are not | 2208 // If either operand is a JSObject or an oddball value, then they are not |
| 2209 // equal since their pointers are different | 2209 // equal since their pointers are different |
| 2210 // There is no test for undetectability in strict equality. | 2210 // There is no test for undetectability in strict equality. |
| 2211 | 2211 |
| 2212 // If the first object is a JS object, we have done pointer comparison. | 2212 // If the first object is a JS object, we have done pointer comparison. |
| 2213 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 2213 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
| 2214 Label first_non_object; | 2214 NearLabel first_non_object; |
| 2215 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); | 2215 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); |
| 2216 __ j(below, &first_non_object); | 2216 __ j(below, &first_non_object); |
| 2217 // Return non-zero (eax (not rax) is not zero) | 2217 // Return non-zero (eax (not rax) is not zero) |
| 2218 Label return_not_equal; | 2218 Label return_not_equal; |
| 2219 STATIC_ASSERT(kHeapObjectTag != 0); | 2219 STATIC_ASSERT(kHeapObjectTag != 0); |
| 2220 __ bind(&return_not_equal); | 2220 __ bind(&return_not_equal); |
| 2221 __ ret(0); | 2221 __ ret(0); |
| 2222 | 2222 |
| 2223 __ bind(&first_non_object); | 2223 __ bind(&first_non_object); |
| 2224 // Check for oddballs: true, false, null, undefined. | 2224 // Check for oddballs: true, false, null, undefined. |
| 2225 __ CmpInstanceType(rcx, ODDBALL_TYPE); | 2225 __ CmpInstanceType(rcx, ODDBALL_TYPE); |
| 2226 __ j(equal, &return_not_equal); | 2226 __ j(equal, &return_not_equal); |
| 2227 | 2227 |
| 2228 __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx); | 2228 __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx); |
| 2229 __ j(above_equal, &return_not_equal); | 2229 __ j(above_equal, &return_not_equal); |
| 2230 | 2230 |
| 2231 // Check for oddballs: true, false, null, undefined. | 2231 // Check for oddballs: true, false, null, undefined. |
| 2232 __ CmpInstanceType(rcx, ODDBALL_TYPE); | 2232 __ CmpInstanceType(rcx, ODDBALL_TYPE); |
| 2233 __ j(equal, &return_not_equal); | 2233 __ j(equal, &return_not_equal); |
| 2234 | 2234 |
| 2235 // Fall through to the general case. | 2235 // Fall through to the general case. |
| 2236 } | 2236 } |
| 2237 __ bind(&slow); | 2237 __ bind(&slow); |
| 2238 } | 2238 } |
| 2239 | 2239 |
| 2240 // Generate the number comparison code. | 2240 // Generate the number comparison code. |
| 2241 if (include_number_compare_) { | 2241 if (include_number_compare_) { |
| 2242 Label non_number_comparison; | 2242 Label non_number_comparison; |
| 2243 Label unordered; | 2243 NearLabel unordered; |
| 2244 FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison); | 2244 FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison); |
| 2245 __ xorl(rax, rax); | 2245 __ xorl(rax, rax); |
| 2246 __ xorl(rcx, rcx); | 2246 __ xorl(rcx, rcx); |
| 2247 __ ucomisd(xmm0, xmm1); | 2247 __ ucomisd(xmm0, xmm1); |
| 2248 | 2248 |
| 2249 // Don't base result on EFLAGS when a NaN is involved. | 2249 // Don't base result on EFLAGS when a NaN is involved. |
| 2250 __ j(parity_even, &unordered); | 2250 __ j(parity_even, &unordered); |
| 2251 // Return a result of -1, 0, or 1, based on EFLAGS. | 2251 // Return a result of -1, 0, or 1, based on EFLAGS. |
| 2252 __ setcc(above, rax); | 2252 __ setcc(above, rax); |
| 2253 __ setcc(below, rcx); | 2253 __ setcc(below, rcx); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2297 | 2297 |
| 2298 #ifdef DEBUG | 2298 #ifdef DEBUG |
| 2299 __ Abort("Unexpected fall-through from string comparison"); | 2299 __ Abort("Unexpected fall-through from string comparison"); |
| 2300 #endif | 2300 #endif |
| 2301 | 2301 |
| 2302 __ bind(&check_unequal_objects); | 2302 __ bind(&check_unequal_objects); |
| 2303 if (cc_ == equal && !strict_) { | 2303 if (cc_ == equal && !strict_) { |
| 2304 // Not strict equality. Objects are unequal if | 2304 // Not strict equality. Objects are unequal if |
| 2305 // they are both JSObjects and not undetectable, | 2305 // they are both JSObjects and not undetectable, |
| 2306 // and their pointers are different. | 2306 // and their pointers are different. |
| 2307 Label not_both_objects, return_unequal; | 2307 NearLabel not_both_objects, return_unequal; |
| 2308 // At most one is a smi, so we can test for smi by adding the two. | 2308 // At most one is a smi, so we can test for smi by adding the two. |
| 2309 // A smi plus a heap object has the low bit set, a heap object plus | 2309 // A smi plus a heap object has the low bit set, a heap object plus |
| 2310 // a heap object has the low bit clear. | 2310 // a heap object has the low bit clear. |
| 2311 STATIC_ASSERT(kSmiTag == 0); | 2311 STATIC_ASSERT(kSmiTag == 0); |
| 2312 STATIC_ASSERT(kSmiTagMask == 1); | 2312 STATIC_ASSERT(kSmiTagMask == 1); |
| 2313 __ lea(rcx, Operand(rax, rdx, times_1, 0)); | 2313 __ lea(rcx, Operand(rax, rdx, times_1, 0)); |
| 2314 __ testb(rcx, Immediate(kSmiTagMask)); | 2314 __ testb(rcx, Immediate(kSmiTagMask)); |
| 2315 __ j(not_zero, ¬_both_objects); | 2315 __ j(not_zero, ¬_both_objects); |
| 2316 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); | 2316 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); |
| 2317 __ j(below, ¬_both_objects); | 2317 __ j(below, ¬_both_objects); |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2455 __ movq(rsp, Operand(kScratchRegister, 0)); | 2455 __ movq(rsp, Operand(kScratchRegister, 0)); |
| 2456 // get next in chain | 2456 // get next in chain |
| 2457 __ pop(rcx); | 2457 __ pop(rcx); |
| 2458 __ movq(Operand(kScratchRegister, 0), rcx); | 2458 __ movq(Operand(kScratchRegister, 0), rcx); |
| 2459 __ pop(rbp); // pop frame pointer | 2459 __ pop(rbp); // pop frame pointer |
| 2460 __ pop(rdx); // remove state | 2460 __ pop(rdx); // remove state |
| 2461 | 2461 |
| 2462 // Before returning we restore the context from the frame pointer if not NULL. | 2462 // Before returning we restore the context from the frame pointer if not NULL. |
| 2463 // The frame pointer is NULL in the exception handler of a JS entry frame. | 2463 // The frame pointer is NULL in the exception handler of a JS entry frame. |
| 2464 __ xor_(rsi, rsi); // tentatively set context pointer to NULL | 2464 __ xor_(rsi, rsi); // tentatively set context pointer to NULL |
| 2465 Label skip; | 2465 NearLabel skip; |
| 2466 __ cmpq(rbp, Immediate(0)); | 2466 __ cmpq(rbp, Immediate(0)); |
| 2467 __ j(equal, &skip); | 2467 __ j(equal, &skip); |
| 2468 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2468 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2469 __ bind(&skip); | 2469 __ bind(&skip); |
| 2470 __ ret(0); | 2470 __ ret(0); |
| 2471 } | 2471 } |
| 2472 | 2472 |
| 2473 | 2473 |
| 2474 void ApiGetterEntryStub::Generate(MacroAssembler* masm) { | 2474 void ApiGetterEntryStub::Generate(MacroAssembler* masm) { |
| 2475 Label empty_result; | 2475 Label empty_result; |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2615 __ testl(rcx, Immediate(kFailureTagMask)); | 2615 __ testl(rcx, Immediate(kFailureTagMask)); |
| 2616 __ j(zero, &failure_returned); | 2616 __ j(zero, &failure_returned); |
| 2617 | 2617 |
| 2618 // Exit the JavaScript to C++ exit frame. | 2618 // Exit the JavaScript to C++ exit frame. |
| 2619 __ LeaveExitFrame(result_size_); | 2619 __ LeaveExitFrame(result_size_); |
| 2620 __ ret(0); | 2620 __ ret(0); |
| 2621 | 2621 |
| 2622 // Handling of failure. | 2622 // Handling of failure. |
| 2623 __ bind(&failure_returned); | 2623 __ bind(&failure_returned); |
| 2624 | 2624 |
| 2625 Label retry; | 2625 NearLabel retry; |
| 2626 // If the returned exception is RETRY_AFTER_GC continue at retry label | 2626 // If the returned exception is RETRY_AFTER_GC continue at retry label |
| 2627 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); | 2627 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); |
| 2628 __ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); | 2628 __ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); |
| 2629 __ j(zero, &retry); | 2629 __ j(zero, &retry); |
| 2630 | 2630 |
| 2631 // Special handling of out of memory exceptions. | 2631 // Special handling of out of memory exceptions. |
| 2632 __ movq(kScratchRegister, Failure::OutOfMemoryException(), RelocInfo::NONE); | 2632 __ movq(kScratchRegister, Failure::OutOfMemoryException(), RelocInfo::NONE); |
| 2633 __ cmpq(rax, kScratchRegister); | 2633 __ cmpq(rax, kScratchRegister); |
| 2634 __ j(equal, throw_out_of_memory_exception); | 2634 __ j(equal, throw_out_of_memory_exception); |
| 2635 | 2635 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2655 | 2655 |
| 2656 | 2656 |
| 2657 void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, | 2657 void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, |
| 2658 UncatchableExceptionType type) { | 2658 UncatchableExceptionType type) { |
| 2659 // Fetch top stack handler. | 2659 // Fetch top stack handler. |
| 2660 ExternalReference handler_address(Top::k_handler_address); | 2660 ExternalReference handler_address(Top::k_handler_address); |
| 2661 __ movq(kScratchRegister, handler_address); | 2661 __ movq(kScratchRegister, handler_address); |
| 2662 __ movq(rsp, Operand(kScratchRegister, 0)); | 2662 __ movq(rsp, Operand(kScratchRegister, 0)); |
| 2663 | 2663 |
| 2664 // Unwind the handlers until the ENTRY handler is found. | 2664 // Unwind the handlers until the ENTRY handler is found. |
| 2665 Label loop, done; | 2665 NearLabel loop, done; |
| 2666 __ bind(&loop); | 2666 __ bind(&loop); |
| 2667 // Load the type of the current stack handler. | 2667 // Load the type of the current stack handler. |
| 2668 const int kStateOffset = StackHandlerConstants::kStateOffset; | 2668 const int kStateOffset = StackHandlerConstants::kStateOffset; |
| 2669 __ cmpq(Operand(rsp, kStateOffset), Immediate(StackHandler::ENTRY)); | 2669 __ cmpq(Operand(rsp, kStateOffset), Immediate(StackHandler::ENTRY)); |
| 2670 __ j(equal, &done); | 2670 __ j(equal, &done); |
| 2671 // Fetch the next handler in the list. | 2671 // Fetch the next handler in the list. |
| 2672 const int kNextOffset = StackHandlerConstants::kNextOffset; | 2672 const int kNextOffset = StackHandlerConstants::kNextOffset; |
| 2673 __ movq(rsp, Operand(rsp, kNextOffset)); | 2673 __ movq(rsp, Operand(rsp, kNextOffset)); |
| 2674 __ jmp(&loop); | 2674 __ jmp(&loop); |
| 2675 __ bind(&done); | 2675 __ bind(&done); |
| (...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2925 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax); | 2925 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax); |
| 2926 __ j(below, &slow); | 2926 __ j(below, &slow); |
| 2927 __ CmpInstanceType(rax, LAST_JS_OBJECT_TYPE); | 2927 __ CmpInstanceType(rax, LAST_JS_OBJECT_TYPE); |
| 2928 __ j(above, &slow); | 2928 __ j(above, &slow); |
| 2929 | 2929 |
| 2930 // Get the prototype of the function. | 2930 // Get the prototype of the function. |
| 2931 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); | 2931 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); |
| 2932 // rdx is function, rax is map. | 2932 // rdx is function, rax is map. |
| 2933 | 2933 |
| 2934 // Look up the function and the map in the instanceof cache. | 2934 // Look up the function and the map in the instanceof cache. |
| 2935 Label miss; | 2935 NearLabel miss; |
| 2936 __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); | 2936 __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); |
| 2937 __ j(not_equal, &miss); | 2937 __ j(not_equal, &miss); |
| 2938 __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex); | 2938 __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex); |
| 2939 __ j(not_equal, &miss); | 2939 __ j(not_equal, &miss); |
| 2940 __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); | 2940 __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); |
| 2941 __ ret(2 * kPointerSize); | 2941 __ ret(2 * kPointerSize); |
| 2942 | 2942 |
| 2943 __ bind(&miss); | 2943 __ bind(&miss); |
| 2944 __ TryGetFunctionPrototype(rdx, rbx, &slow); | 2944 __ TryGetFunctionPrototype(rdx, rbx, &slow); |
| 2945 | 2945 |
| 2946 // Check that the function prototype is a JS object. | 2946 // Check that the function prototype is a JS object. |
| 2947 __ JumpIfSmi(rbx, &slow); | 2947 __ JumpIfSmi(rbx, &slow); |
| 2948 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister); | 2948 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister); |
| 2949 __ j(below, &slow); | 2949 __ j(below, &slow); |
| 2950 __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE); | 2950 __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE); |
| 2951 __ j(above, &slow); | 2951 __ j(above, &slow); |
| 2952 | 2952 |
| 2953 // Register mapping: | 2953 // Register mapping: |
| 2954 // rax is object map. | 2954 // rax is object map. |
| 2955 // rdx is function. | 2955 // rdx is function. |
| 2956 // rbx is function prototype. | 2956 // rbx is function prototype. |
| 2957 __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); | 2957 __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); |
| 2958 __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex); | 2958 __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex); |
| 2959 | 2959 |
| 2960 __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset)); | 2960 __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset)); |
| 2961 | 2961 |
| 2962 // Loop through the prototype chain looking for the function prototype. | 2962 // Loop through the prototype chain looking for the function prototype. |
| 2963 Label loop, is_instance, is_not_instance; | 2963 NearLabel loop, is_instance, is_not_instance; |
| 2964 __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex); | 2964 __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex); |
| 2965 __ bind(&loop); | 2965 __ bind(&loop); |
| 2966 __ cmpq(rcx, rbx); | 2966 __ cmpq(rcx, rbx); |
| 2967 __ j(equal, &is_instance); | 2967 __ j(equal, &is_instance); |
| 2968 __ cmpq(rcx, kScratchRegister); | 2968 __ cmpq(rcx, kScratchRegister); |
| 2969 // The code at is_not_instance assumes that kScratchRegister contains a | 2969 // The code at is_not_instance assumes that kScratchRegister contains a |
| 2970 // non-zero GCable value (the null object in this case). | 2970 // non-zero GCable value (the null object in this case). |
| 2971 __ j(equal, &is_not_instance); | 2971 __ j(equal, &is_not_instance); |
| 2972 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); | 2972 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); |
| 2973 __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset)); | 2973 __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset)); |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3258 is_smi = masm->CheckSmi(rdx); | 3258 is_smi = masm->CheckSmi(rdx); |
| 3259 __ j(is_smi, &string_add_runtime); | 3259 __ j(is_smi, &string_add_runtime); |
| 3260 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); | 3260 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); |
| 3261 __ j(above_equal, &string_add_runtime); | 3261 __ j(above_equal, &string_add_runtime); |
| 3262 } | 3262 } |
| 3263 | 3263 |
| 3264 // Both arguments are strings. | 3264 // Both arguments are strings. |
| 3265 // rax: first string | 3265 // rax: first string |
| 3266 // rdx: second string | 3266 // rdx: second string |
| 3267 // Check if either of the strings are empty. In that case return the other. | 3267 // Check if either of the strings are empty. In that case return the other. |
| 3268 Label second_not_zero_length, both_not_zero_length; | 3268 NearLabel second_not_zero_length, both_not_zero_length; |
| 3269 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); | 3269 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); |
| 3270 __ SmiTest(rcx); | 3270 __ SmiTest(rcx); |
| 3271 __ j(not_zero, &second_not_zero_length); | 3271 __ j(not_zero, &second_not_zero_length); |
| 3272 // Second string is empty, result is first string which is already in rax. | 3272 // Second string is empty, result is first string which is already in rax. |
| 3273 __ IncrementCounter(&Counters::string_add_native, 1); | 3273 __ IncrementCounter(&Counters::string_add_native, 1); |
| 3274 __ ret(2 * kPointerSize); | 3274 __ ret(2 * kPointerSize); |
| 3275 __ bind(&second_not_zero_length); | 3275 __ bind(&second_not_zero_length); |
| 3276 __ movq(rbx, FieldOperand(rax, String::kLengthOffset)); | 3276 __ movq(rbx, FieldOperand(rax, String::kLengthOffset)); |
| 3277 __ SmiTest(rbx); | 3277 __ SmiTest(rbx); |
| 3278 __ j(not_zero, &both_not_zero_length); | 3278 __ j(not_zero, &both_not_zero_length); |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3514 bool ascii) { | 3514 bool ascii) { |
| 3515 // Copy characters using rep movs of doublewords. Align destination on 4 byte | 3515 // Copy characters using rep movs of doublewords. Align destination on 4 byte |
| 3516 // boundary before starting rep movs. Copy remaining characters after running | 3516 // boundary before starting rep movs. Copy remaining characters after running |
| 3517 // rep movs. | 3517 // rep movs. |
| 3518 // Count is positive int32, dest and src are character pointers. | 3518 // Count is positive int32, dest and src are character pointers. |
| 3519 ASSERT(dest.is(rdi)); // rep movs destination | 3519 ASSERT(dest.is(rdi)); // rep movs destination |
| 3520 ASSERT(src.is(rsi)); // rep movs source | 3520 ASSERT(src.is(rsi)); // rep movs source |
| 3521 ASSERT(count.is(rcx)); // rep movs count | 3521 ASSERT(count.is(rcx)); // rep movs count |
| 3522 | 3522 |
| 3523 // Nothing to do for zero characters. | 3523 // Nothing to do for zero characters. |
| 3524 Label done; | 3524 NearLabel done; |
| 3525 __ testl(count, count); | 3525 __ testl(count, count); |
| 3526 __ j(zero, &done); | 3526 __ j(zero, &done); |
| 3527 | 3527 |
| 3528 // Make count the number of bytes to copy. | 3528 // Make count the number of bytes to copy. |
| 3529 if (!ascii) { | 3529 if (!ascii) { |
| 3530 STATIC_ASSERT(2 == sizeof(uc16)); | 3530 STATIC_ASSERT(2 == sizeof(uc16)); |
| 3531 __ addl(count, count); | 3531 __ addl(count, count); |
| 3532 } | 3532 } |
| 3533 | 3533 |
| 3534 // Don't enter the rep movs if there are less than 4 bytes to copy. | 3534 // Don't enter the rep movs if there are less than 4 bytes to copy. |
| 3535 Label last_bytes; | 3535 NearLabel last_bytes; |
| 3536 __ testl(count, Immediate(~7)); | 3536 __ testl(count, Immediate(~7)); |
| 3537 __ j(zero, &last_bytes); | 3537 __ j(zero, &last_bytes); |
| 3538 | 3538 |
| 3539 // Copy from edi to esi using rep movs instruction. | 3539 // Copy from edi to esi using rep movs instruction. |
| 3540 __ movl(kScratchRegister, count); | 3540 __ movl(kScratchRegister, count); |
| 3541 __ shr(count, Immediate(3)); // Number of doublewords to copy. | 3541 __ shr(count, Immediate(3)); // Number of doublewords to copy. |
| 3542 __ repmovsq(); | 3542 __ repmovsq(); |
| 3543 | 3543 |
| 3544 // Find number of bytes left. | 3544 // Find number of bytes left. |
| 3545 __ movl(count, kScratchRegister); | 3545 __ movl(count, kScratchRegister); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 3569 Register scratch1, | 3569 Register scratch1, |
| 3570 Register scratch2, | 3570 Register scratch2, |
| 3571 Register scratch3, | 3571 Register scratch3, |
| 3572 Register scratch4, | 3572 Register scratch4, |
| 3573 Label* not_found) { | 3573 Label* not_found) { |
| 3574 // Register scratch3 is the general scratch register in this function. | 3574 // Register scratch3 is the general scratch register in this function. |
| 3575 Register scratch = scratch3; | 3575 Register scratch = scratch3; |
| 3576 | 3576 |
| 3577 // Make sure that both characters are not digits as such strings has a | 3577 // Make sure that both characters are not digits as such strings has a |
| 3578 // different hash algorithm. Don't try to look for these in the symbol table. | 3578 // different hash algorithm. Don't try to look for these in the symbol table. |
| 3579 Label not_array_index; | 3579 NearLabel not_array_index; |
| 3580 __ leal(scratch, Operand(c1, -'0')); | 3580 __ leal(scratch, Operand(c1, -'0')); |
| 3581 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); | 3581 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); |
| 3582 __ j(above, ¬_array_index); | 3582 __ j(above, ¬_array_index); |
| 3583 __ leal(scratch, Operand(c2, -'0')); | 3583 __ leal(scratch, Operand(c2, -'0')); |
| 3584 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); | 3584 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); |
| 3585 __ j(below_equal, not_found); | 3585 __ j(below_equal, not_found); |
| 3586 | 3586 |
| 3587 __ bind(¬_array_index); | 3587 __ bind(¬_array_index); |
| 3588 // Calculate the two character string hash. | 3588 // Calculate the two character string hash. |
| 3589 Register hash = scratch1; | 3589 Register hash = scratch1; |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3893 | 3893 |
| 3894 // Find minimum length and length difference. | 3894 // Find minimum length and length difference. |
| 3895 __ movq(scratch1, FieldOperand(left, String::kLengthOffset)); | 3895 __ movq(scratch1, FieldOperand(left, String::kLengthOffset)); |
| 3896 __ movq(scratch4, scratch1); | 3896 __ movq(scratch4, scratch1); |
| 3897 __ SmiSub(scratch4, | 3897 __ SmiSub(scratch4, |
| 3898 scratch4, | 3898 scratch4, |
| 3899 FieldOperand(right, String::kLengthOffset), | 3899 FieldOperand(right, String::kLengthOffset), |
| 3900 NULL); | 3900 NULL); |
| 3901 // Register scratch4 now holds left.length - right.length. | 3901 // Register scratch4 now holds left.length - right.length. |
| 3902 const Register length_difference = scratch4; | 3902 const Register length_difference = scratch4; |
| 3903 Label left_shorter; | 3903 NearLabel left_shorter; |
| 3904 __ j(less, &left_shorter); | 3904 __ j(less, &left_shorter); |
| 3905 // The right string isn't longer that the left one. | 3905 // The right string isn't longer that the left one. |
| 3906 // Get the right string's length by subtracting the (non-negative) difference | 3906 // Get the right string's length by subtracting the (non-negative) difference |
| 3907 // from the left string's length. | 3907 // from the left string's length. |
| 3908 __ SmiSub(scratch1, scratch1, length_difference, NULL); | 3908 __ SmiSub(scratch1, scratch1, length_difference, NULL); |
| 3909 __ bind(&left_shorter); | 3909 __ bind(&left_shorter); |
| 3910 // Register scratch1 now holds Min(left.length, right.length). | 3910 // Register scratch1 now holds Min(left.length, right.length). |
| 3911 const Register min_length = scratch1; | 3911 const Register min_length = scratch1; |
| 3912 | 3912 |
| 3913 Label compare_lengths; | 3913 NearLabel compare_lengths; |
| 3914 // If min-length is zero, go directly to comparing lengths. | 3914 // If min-length is zero, go directly to comparing lengths. |
| 3915 __ SmiTest(min_length); | 3915 __ SmiTest(min_length); |
| 3916 __ j(zero, &compare_lengths); | 3916 __ j(zero, &compare_lengths); |
| 3917 | 3917 |
| 3918 __ SmiToInteger32(min_length, min_length); | 3918 __ SmiToInteger32(min_length, min_length); |
| 3919 | 3919 |
| 3920 // Registers scratch2 and scratch3 are free. | 3920 // Registers scratch2 and scratch3 are free. |
| 3921 Label result_not_equal; | 3921 NearLabel result_not_equal; |
| 3922 Label loop; | 3922 Label loop; |
| 3923 { | 3923 { |
| 3924 // Check characters 0 .. min_length - 1 in a loop. | 3924 // Check characters 0 .. min_length - 1 in a loop. |
| 3925 // Use scratch3 as loop index, min_length as limit and scratch2 | 3925 // Use scratch3 as loop index, min_length as limit and scratch2 |
| 3926 // for computation. | 3926 // for computation. |
| 3927 const Register index = scratch3; | 3927 const Register index = scratch3; |
| 3928 __ movl(index, Immediate(0)); // Index into strings. | 3928 __ movl(index, Immediate(0)); // Index into strings. |
| 3929 __ bind(&loop); | 3929 __ bind(&loop); |
| 3930 // Compare characters. | 3930 // Compare characters. |
| 3931 // TODO(lrn): Could we load more than one character at a time? | 3931 // TODO(lrn): Could we load more than one character at a time? |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3947 // Completed loop without finding different characters. | 3947 // Completed loop without finding different characters. |
| 3948 // Compare lengths (precomputed). | 3948 // Compare lengths (precomputed). |
| 3949 __ bind(&compare_lengths); | 3949 __ bind(&compare_lengths); |
| 3950 __ SmiTest(length_difference); | 3950 __ SmiTest(length_difference); |
| 3951 __ j(not_zero, &result_not_equal); | 3951 __ j(not_zero, &result_not_equal); |
| 3952 | 3952 |
| 3953 // Result is EQUAL. | 3953 // Result is EQUAL. |
| 3954 __ Move(rax, Smi::FromInt(EQUAL)); | 3954 __ Move(rax, Smi::FromInt(EQUAL)); |
| 3955 __ ret(0); | 3955 __ ret(0); |
| 3956 | 3956 |
| 3957 Label result_greater; | 3957 NearLabel result_greater; |
| 3958 __ bind(&result_not_equal); | 3958 __ bind(&result_not_equal); |
| 3959 // Unequal comparison of left to right, either character or length. | 3959 // Unequal comparison of left to right, either character or length. |
| 3960 __ j(greater, &result_greater); | 3960 __ j(greater, &result_greater); |
| 3961 | 3961 |
| 3962 // Result is LESS. | 3962 // Result is LESS. |
| 3963 __ Move(rax, Smi::FromInt(LESS)); | 3963 __ Move(rax, Smi::FromInt(LESS)); |
| 3964 __ ret(0); | 3964 __ ret(0); |
| 3965 | 3965 |
| 3966 // Result is GREATER. | 3966 // Result is GREATER. |
| 3967 __ bind(&result_greater); | 3967 __ bind(&result_greater); |
| 3968 __ Move(rax, Smi::FromInt(GREATER)); | 3968 __ Move(rax, Smi::FromInt(GREATER)); |
| 3969 __ ret(0); | 3969 __ ret(0); |
| 3970 } | 3970 } |
| 3971 | 3971 |
| 3972 | 3972 |
| 3973 void StringCompareStub::Generate(MacroAssembler* masm) { | 3973 void StringCompareStub::Generate(MacroAssembler* masm) { |
| 3974 Label runtime; | 3974 Label runtime; |
| 3975 | 3975 |
| 3976 // Stack frame on entry. | 3976 // Stack frame on entry. |
| 3977 // rsp[0]: return address | 3977 // rsp[0]: return address |
| 3978 // rsp[8]: right string | 3978 // rsp[8]: right string |
| 3979 // rsp[16]: left string | 3979 // rsp[16]: left string |
| 3980 | 3980 |
| 3981 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // left | 3981 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // left |
| 3982 __ movq(rax, Operand(rsp, 1 * kPointerSize)); // right | 3982 __ movq(rax, Operand(rsp, 1 * kPointerSize)); // right |
| 3983 | 3983 |
| 3984 // Check for identity. | 3984 // Check for identity. |
| 3985 Label not_same; | 3985 NearLabel not_same; |
| 3986 __ cmpq(rdx, rax); | 3986 __ cmpq(rdx, rax); |
| 3987 __ j(not_equal, ¬_same); | 3987 __ j(not_equal, ¬_same); |
| 3988 __ Move(rax, Smi::FromInt(EQUAL)); | 3988 __ Move(rax, Smi::FromInt(EQUAL)); |
| 3989 __ IncrementCounter(&Counters::string_compare_native, 1); | 3989 __ IncrementCounter(&Counters::string_compare_native, 1); |
| 3990 __ ret(2 * kPointerSize); | 3990 __ ret(2 * kPointerSize); |
| 3991 | 3991 |
| 3992 __ bind(¬_same); | 3992 __ bind(¬_same); |
| 3993 | 3993 |
| 3994 // Check that both are sequential ASCII strings. | 3994 // Check that both are sequential ASCII strings. |
| 3995 __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime); | 3995 __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 4006 // tagged as a small integer. | 4006 // tagged as a small integer. |
| 4007 __ bind(&runtime); | 4007 __ bind(&runtime); |
| 4008 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 4008 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
| 4009 } | 4009 } |
| 4010 | 4010 |
| 4011 #undef __ | 4011 #undef __ |
| 4012 | 4012 |
| 4013 } } // namespace v8::internal | 4013 } } // namespace v8::internal |
| 4014 | 4014 |
| 4015 #endif // V8_TARGET_ARCH_X64 | 4015 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |