OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 4033 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4044 done.Bind(); | 4044 done.Bind(); |
4045 } | 4045 } |
4046 | 4046 |
4047 | 4047 |
4048 void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) { | 4048 void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) { |
4049 ASSERT_EQ(2, args->length()); | 4049 ASSERT_EQ(2, args->length()); |
4050 | 4050 |
4051 Load(args->at(0)); | 4051 Load(args->at(0)); |
4052 Load(args->at(1)); | 4052 Load(args->at(1)); |
4053 | 4053 |
4054 Result answer = frame_->CallRuntime(Runtime::kStringAdd, 2); | 4054 StringAddStub stub(NO_STRING_ADD_FLAGS); |
| 4055 Result answer = frame_->CallStub(&stub, 2); |
4055 frame_->Push(&answer); | 4056 frame_->Push(&answer); |
4056 } | 4057 } |
4057 | 4058 |
4058 | 4059 |
4059 void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) { | 4060 void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) { |
4060 ASSERT(args->length() == 1); | 4061 ASSERT(args->length() == 1); |
4061 JumpTarget leave, null, function, non_function_constructor; | 4062 JumpTarget leave, null, function, non_function_constructor; |
4062 Load(args->at(0)); // Load the object. | 4063 Load(args->at(0)); // Load the object. |
4063 Result obj = frame_->Pop(); | 4064 Result obj = frame_->Pop(); |
4064 obj.ToRegister(); | 4065 obj.ToRegister(); |
(...skipping 3724 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7789 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rdx); | 7790 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rdx); |
7790 __ j(above_equal, ¬_string1); | 7791 __ j(above_equal, ¬_string1); |
7791 | 7792 |
7792 // First argument is a a string, test second. | 7793 // First argument is a a string, test second. |
7793 is_smi = masm->CheckSmi(rax); | 7794 is_smi = masm->CheckSmi(rax); |
7794 __ j(is_smi, &string1); | 7795 __ j(is_smi, &string1); |
7795 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax); | 7796 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax); |
7796 __ j(above_equal, &string1); | 7797 __ j(above_equal, &string1); |
7797 | 7798 |
7798 // First and second argument are strings. | 7799 // First and second argument are strings. |
7799 Runtime::Function* f = Runtime::FunctionForId(Runtime::kStringAdd); | 7800 StringAddStub stub(NO_STRING_CHECK_IN_STUB); |
7800 __ TailCallRuntime(ExternalReference(f), 2, f->result_size); | 7801 __ TailCallStub(&stub); |
7801 | 7802 |
7802 // Only first argument is a string. | 7803 // Only first argument is a string. |
7803 __ bind(&string1); | 7804 __ bind(&string1); |
7804 __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION); | 7805 __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION); |
7805 | 7806 |
7806 // First argument was not a string, test second. | 7807 // First argument was not a string, test second. |
7807 __ bind(¬_string1); | 7808 __ bind(¬_string1); |
7808 is_smi = masm->CheckSmi(rax); | 7809 is_smi = masm->CheckSmi(rax); |
7809 __ j(is_smi, ¬_strings); | 7810 __ j(is_smi, ¬_strings); |
7810 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax); | 7811 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7873 } | 7874 } |
7874 } | 7875 } |
7875 | 7876 |
7876 | 7877 |
7877 int CompareStub::MinorKey() { | 7878 int CompareStub::MinorKey() { |
7878 // Encode the two parameters in a unique 16 bit value. | 7879 // Encode the two parameters in a unique 16 bit value. |
7879 ASSERT(static_cast<unsigned>(cc_) < (1 << 15)); | 7880 ASSERT(static_cast<unsigned>(cc_) < (1 << 15)); |
7880 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); | 7881 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); |
7881 } | 7882 } |
7882 | 7883 |
| 7884 |
| 7885 void StringAddStub::Generate(MacroAssembler* masm) { |
| 7886 Label string_add_runtime; |
| 7887 |
| 7888 // Load the two arguments. |
| 7889 __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument. |
| 7890 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument. |
| 7891 |
| 7892 // Make sure that both arguments are strings if not known in advance. |
| 7893 if (string_check_) { |
| 7894 Condition is_smi; |
| 7895 is_smi = masm->CheckSmi(rax); |
| 7896 __ j(is_smi, &string_add_runtime); |
| 7897 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); |
| 7898 __ j(above_equal, &string_add_runtime); |
| 7899 |
| 7900 // First argument is a a string, test second. |
| 7901 is_smi = masm->CheckSmi(rdx); |
| 7902 __ j(is_smi, &string_add_runtime); |
| 7903 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); |
| 7904 __ j(above_equal, &string_add_runtime); |
| 7905 } |
| 7906 |
| 7907 // Both arguments are strings. |
| 7908 // rax: first string |
| 7909 // rdx: second string |
| 7910 // Check if either of the strings are empty. In that case return the other. |
| 7911 Label second_not_zero_length, both_not_zero_length; |
| 7912 __ movl(rcx, FieldOperand(rdx, String::kLengthOffset)); |
| 7913 __ testl(rcx, rcx); |
| 7914 __ j(not_zero, &second_not_zero_length); |
| 7915 // Second string is empty, result is first string which is already in rax. |
| 7916 __ IncrementCounter(&Counters::string_add_native, 1); |
| 7917 __ ret(2 * kPointerSize); |
| 7918 __ bind(&second_not_zero_length); |
| 7919 __ movl(rbx, FieldOperand(rax, String::kLengthOffset)); |
| 7920 __ testl(rbx, rbx); |
| 7921 __ j(not_zero, &both_not_zero_length); |
| 7922 // First string is empty, result is second string which is in rdx. |
| 7923 __ movq(rax, rdx); |
| 7924 __ IncrementCounter(&Counters::string_add_native, 1); |
| 7925 __ ret(2 * kPointerSize); |
| 7926 |
| 7927 // Both strings are non-empty. |
| 7928 // rax: first string |
| 7929 // rbx: length of first string |
| 7930 // ecx: length of second string |
| 7931 // edx: second string |
| 7932 // r8: instance type of first string if string check was performed above |
| 7933 // r9: instance type of first string if string check was performed above |
| 7934 Label string_add_flat_result; |
| 7935 __ bind(&both_not_zero_length); |
| 7936 // Look at the length of the result of adding the two strings. |
| 7937 __ addl(rbx, rcx); |
| 7938 // Use the runtime system when adding two one character strings, as it |
| 7939 // contains optimizations for this specific case using the symbol table. |
| 7940 __ cmpl(rbx, Immediate(2)); |
| 7941 __ j(equal, &string_add_runtime); |
| 7942 // If arguments where known to be strings, maps are not loaded to r8 and r9 |
| 7943 // by the code above. |
| 7944 if (!string_check_) { |
| 7945 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); |
| 7946 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); |
| 7947 } |
| 7948 // Get the instance types of the two strings as they will be needed soon. |
| 7949 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); |
| 7950 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); |
| 7951 // Check if resulting string will be flat. |
| 7952 __ cmpl(rbx, Immediate(String::kMinNonFlatLength)); |
| 7953 __ j(below, &string_add_flat_result); |
| 7954 // Handle exceptionally long strings in the runtime system. |
| 7955 ASSERT((String::kMaxLength & 0x80000000) == 0); |
| 7956 __ cmpl(rbx, Immediate(String::kMaxLength)); |
| 7957 __ j(above, &string_add_runtime); |
| 7958 |
| 7959 // If result is not supposed to be flat, allocate a cons string object. If |
| 7960 // both strings are ascii the result is an ascii cons string. |
| 7961 // rax: first string |
| 7962 // ebx: length of resulting flat string |
| 7963 // rdx: second string |
| 7964 // r8: instance type of first string |
| 7965 // r9: instance type of second string |
| 7966 Label non_ascii, allocated; |
| 7967 __ movl(rcx, r8); |
| 7968 __ and_(rcx, r9); |
| 7969 ASSERT(kStringEncodingMask == kAsciiStringTag); |
| 7970 __ testl(rcx, Immediate(kAsciiStringTag)); |
| 7971 __ j(zero, &non_ascii); |
| 7972 // Allocate an acsii cons string. |
| 7973 __ AllocateAsciiConsString(rcx, rdi, no_reg, &string_add_runtime); |
| 7974 __ bind(&allocated); |
| 7975 // Fill the fields of the cons string. |
| 7976 __ movl(FieldOperand(rcx, ConsString::kLengthOffset), rbx); |
| 7977 __ movl(FieldOperand(rcx, ConsString::kHashFieldOffset), |
| 7978 Immediate(String::kEmptyHashField)); |
| 7979 __ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax); |
| 7980 __ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx); |
| 7981 __ movq(rax, rcx); |
| 7982 __ IncrementCounter(&Counters::string_add_native, 1); |
| 7983 __ ret(2 * kPointerSize); |
| 7984 __ bind(&non_ascii); |
| 7985 // Allocate a two byte cons string. |
| 7986 __ AllocateConsString(rcx, rdi, no_reg, &string_add_runtime); |
| 7987 __ jmp(&allocated); |
| 7988 |
| 7989 // Handle creating a flat result. First check that both strings are not |
| 7990 // external strings. |
| 7991 // rax: first string |
| 7992 // ebx: length of resulting flat string |
| 7993 // rdx: second string |
| 7994 // r8: instance type of first string |
| 7995 // r9: instance type of first string |
| 7996 __ bind(&string_add_flat_result); |
| 7997 __ movl(rcx, r8); |
| 7998 __ and_(rcx, Immediate(kStringRepresentationMask)); |
| 7999 __ cmpl(rcx, Immediate(kExternalStringTag)); |
| 8000 __ j(equal, &string_add_runtime); |
| 8001 __ movl(rcx, r9); |
| 8002 __ and_(rcx, Immediate(kStringRepresentationMask)); |
| 8003 __ cmpl(rcx, Immediate(kExternalStringTag)); |
| 8004 __ j(equal, &string_add_runtime); |
| 8005 // Now check if both strings are ascii strings. |
| 8006 // rax: first string |
| 8007 // ebx: length of resulting flat string |
| 8008 // rdx: second string |
| 8009 // r8: instance type of first string |
| 8010 // r9: instance type of second string |
| 8011 Label non_ascii_string_add_flat_result; |
| 8012 ASSERT(kStringEncodingMask == kAsciiStringTag); |
| 8013 __ testl(r8, Immediate(kAsciiStringTag)); |
| 8014 __ j(zero, &non_ascii_string_add_flat_result); |
| 8015 __ testl(r9, Immediate(kAsciiStringTag)); |
| 8016 __ j(zero, &string_add_runtime); |
| 8017 // Both strings are ascii strings. As they are short they are both flat. |
| 8018 __ AllocateAsciiString(rcx, rbx, rdi, r14, r15, &string_add_runtime); |
| 8019 // rcx: result string |
| 8020 __ movq(rbx, rcx); |
| 8021 // Locate first character of result. |
| 8022 __ addq(rcx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 8023 // Locate first character of first argument |
| 8024 __ movl(rdi, FieldOperand(rax, String::kLengthOffset)); |
| 8025 __ addq(rax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 8026 // rax: first char of first argument |
| 8027 // rbx: result string |
| 8028 // rcx: first character of result |
| 8029 // rdx: second string |
| 8030 // rdi: length of first argument |
| 8031 GenerateCopyCharacters(masm, rcx, rax, rdi, true); |
| 8032 // Locate first character of second argument. |
| 8033 __ movl(rdi, FieldOperand(rdx, String::kLengthOffset)); |
| 8034 __ addq(rdx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 8035 // rbx: result string |
| 8036 // rcx: next character of result |
| 8037 // rdx: first char of second argument |
| 8038 // rdi: length of second argument |
| 8039 GenerateCopyCharacters(masm, rcx, rdx, rdi, true); |
| 8040 __ movq(rax, rbx); |
| 8041 __ IncrementCounter(&Counters::string_add_native, 1); |
| 8042 __ ret(2 * kPointerSize); |
| 8043 |
| 8044 // Handle creating a flat two byte result. |
| 8045 // rax: first string - known to be two byte |
| 8046 // rbx: length of resulting flat string |
| 8047 // rdx: second string |
| 8048 // r8: instance type of first string |
| 8049 // r9: instance type of first string |
| 8050 __ bind(&non_ascii_string_add_flat_result); |
| 8051 __ and_(r9, Immediate(kAsciiStringTag)); |
| 8052 __ j(not_zero, &string_add_runtime); |
| 8053 // Both strings are two byte strings. As they are short they are both |
| 8054 // flat. |
| 8055 __ AllocateTwoByteString(rcx, rbx, rdi, r14, r15, &string_add_runtime); |
| 8056 // rcx: result string |
| 8057 __ movq(rbx, rcx); |
| 8058 // Locate first character of result. |
| 8059 __ addq(rcx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 8060 // Locate first character of first argument. |
| 8061 __ movl(rdi, FieldOperand(rax, String::kLengthOffset)); |
| 8062 __ addq(rax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 8063 // rax: first char of first argument |
| 8064 // rbx: result string |
| 8065 // rcx: first character of result |
| 8066 // rdx: second argument |
| 8067 // rdi: length of first argument |
| 8068 GenerateCopyCharacters(masm, rcx, rax, rdi, false); |
| 8069 // Locate first character of second argument. |
| 8070 __ movl(rdi, FieldOperand(rdx, String::kLengthOffset)); |
| 8071 __ addq(rdx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 8072 // rbx: result string |
| 8073 // rcx: next character of result |
| 8074 // rdx: first char of second argument |
| 8075 // rdi: length of second argument |
| 8076 GenerateCopyCharacters(masm, rcx, rdx, rdi, false); |
| 8077 __ movq(rax, rbx); |
| 8078 __ IncrementCounter(&Counters::string_add_native, 1); |
| 8079 __ ret(2 * kPointerSize); |
| 8080 |
| 8081 // Just jump to runtime to add the two strings. |
| 8082 __ bind(&string_add_runtime); |
| 8083 __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1); |
| 8084 } |
| 8085 |
| 8086 |
| 8087 void StringAddStub::GenerateCopyCharacters(MacroAssembler* masm, |
| 8088 Register dest, |
| 8089 Register src, |
| 8090 Register count, |
| 8091 bool ascii) { |
| 8092 Label loop; |
| 8093 __ bind(&loop); |
| 8094 // This loop just copies one character at a time, as it is only used for very |
| 8095 // short strings. |
| 8096 if (ascii) { |
| 8097 __ movb(kScratchRegister, Operand(src, 0)); |
| 8098 __ movb(Operand(dest, 0), kScratchRegister); |
| 8099 __ addq(src, Immediate(1)); |
| 8100 __ addq(dest, Immediate(1)); |
| 8101 } else { |
| 8102 __ movzxwl(kScratchRegister, Operand(src, 0)); |
| 8103 __ movw(Operand(dest, 0), kScratchRegister); |
| 8104 __ addq(src, Immediate(2)); |
| 8105 __ addq(dest, Immediate(2)); |
| 8106 } |
| 8107 __ subl(count, Immediate(1)); |
| 8108 __ j(not_zero, &loop); |
| 8109 } |
| 8110 |
| 8111 |
7883 #undef __ | 8112 #undef __ |
7884 | 8113 |
7885 #define __ masm. | 8114 #define __ masm. |
7886 | 8115 |
7887 #ifdef _WIN64 | 8116 #ifdef _WIN64 |
7888 typedef double (*ModuloFunction)(double, double); | 8117 typedef double (*ModuloFunction)(double, double); |
7889 // Define custom fmod implementation. | 8118 // Define custom fmod implementation. |
7890 ModuloFunction CreateModuloFunction() { | 8119 ModuloFunction CreateModuloFunction() { |
7891 size_t actual_size; | 8120 size_t actual_size; |
7892 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, | 8121 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7969 masm.GetCode(&desc); | 8198 masm.GetCode(&desc); |
7970 // Call the function from C++. | 8199 // Call the function from C++. |
7971 return FUNCTION_CAST<ModuloFunction>(buffer); | 8200 return FUNCTION_CAST<ModuloFunction>(buffer); |
7972 } | 8201 } |
7973 | 8202 |
7974 #endif | 8203 #endif |
7975 | 8204 |
7976 #undef __ | 8205 #undef __ |
7977 | 8206 |
7978 } } // namespace v8::internal | 8207 } } // namespace v8::internal |
OLD | NEW |