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 6631 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6642 ASSERT(temp.is_valid()); | 6642 ASSERT(temp.is_valid()); |
6643 // Check if the object is a JS array or not. | 6643 // Check if the object is a JS array or not. |
6644 __ CmpObjectType(value.reg(), JS_ARRAY_TYPE, temp.reg()); | 6644 __ CmpObjectType(value.reg(), JS_ARRAY_TYPE, temp.reg()); |
6645 value.Unuse(); | 6645 value.Unuse(); |
6646 temp.Unuse(); | 6646 temp.Unuse(); |
6647 destination()->Split(equal); | 6647 destination()->Split(equal); |
6648 } | 6648 } |
6649 | 6649 |
6650 | 6650 |
6651 void CodeGenerator::GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args) { | 6651 void CodeGenerator::GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args) { |
| 6652 Label bailout, done, one_char_separator, long_separator, |
| 6653 non_trivial_array, not_size_one_array, loop, loop_condition, |
| 6654 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry; |
| 6655 |
6652 ASSERT(args->length() == 2); | 6656 ASSERT(args->length() == 2); |
| 6657 // We will leave the separator on the stack until the end of the function. |
6653 Load(args->at(1)); | 6658 Load(args->at(1)); |
| 6659 // Load this to eax (= array) |
6654 Load(args->at(0)); | 6660 Load(args->at(0)); |
6655 Result array_result = frame_->Pop(); | 6661 Result array_result = frame_->Pop(); |
6656 array_result.ToRegister(eax); | 6662 array_result.ToRegister(eax); |
6657 frame_->SpillAll(); | 6663 frame_->SpillAll(); |
6658 | 6664 |
6659 Label bailout; | |
6660 Label done; | |
6661 // All aliases of the same register have disjoint lifetimes. | 6665 // All aliases of the same register have disjoint lifetimes. |
6662 Register array = eax; | 6666 Register array = eax; |
6663 Register result_pos = no_reg; | 6667 Register elements = no_reg; // Will be eax. |
6664 | 6668 |
6665 Register index = edi; | 6669 Register index = edx; |
6666 | 6670 |
6667 Register current_string_length = ecx; // Will be ecx when live. | 6671 Register string_length = ecx; |
6668 | 6672 |
6669 Register current_string = edx; | 6673 Register string = esi; |
6670 | 6674 |
6671 Register scratch = ebx; | 6675 Register scratch = ebx; |
6672 | 6676 |
6673 Register scratch_2 = esi; | 6677 Register array_length = edi; |
6674 Register new_padding_chars = scratch_2; | 6678 Register result_pos = no_reg; // Will be edi. |
6675 | 6679 |
6676 Operand separator = Operand(esp, 4 * kPointerSize); // Already pushed. | 6680 // Separator operand is already pushed. |
6677 Operand elements = Operand(esp, 3 * kPointerSize); | 6681 Operand separator_operand = Operand(esp, 2 * kPointerSize); |
6678 Operand result = Operand(esp, 2 * kPointerSize); | 6682 Operand result_operand = Operand(esp, 1 * kPointerSize); |
6679 Operand padding_chars = Operand(esp, 1 * kPointerSize); | 6683 Operand array_length_operand = Operand(esp, 0); |
6680 Operand array_length = Operand(esp, 0); | 6684 __ sub(Operand(esp), Immediate(2 * kPointerSize)); |
6681 __ sub(Operand(esp), Immediate(4 * kPointerSize)); | 6685 __ cld(); |
6682 | 6686 // Check that the array is a JSArray |
6683 // Check that eax is a JSArray | |
6684 __ test(array, Immediate(kSmiTagMask)); | 6687 __ test(array, Immediate(kSmiTagMask)); |
6685 __ j(zero, &bailout); | 6688 __ j(zero, &bailout); |
6686 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); | 6689 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); |
6687 __ j(not_equal, &bailout); | 6690 __ j(not_equal, &bailout); |
6688 | 6691 |
6689 // Check that the array has fast elements. | 6692 // Check that the array has fast elements. |
6690 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), | 6693 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), |
6691 1 << Map::kHasFastElements); | 6694 1 << Map::kHasFastElements); |
6692 __ j(zero, &bailout); | 6695 __ j(zero, &bailout); |
6693 | 6696 |
6694 // If the array is empty, return the empty string. | 6697 // If the array has length zero, return the empty string. |
6695 __ mov(scratch, FieldOperand(array, JSArray::kLengthOffset)); | 6698 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset)); |
6696 __ sar(scratch, 1); | 6699 __ sar(array_length, 1); |
6697 Label non_trivial; | 6700 __ j(not_zero, &non_trivial_array); |
6698 __ j(not_zero, &non_trivial); | 6701 __ mov(result_operand, Factory::empty_string()); |
6699 __ mov(result, Factory::empty_string()); | 6702 __ jmp(&done); |
6700 __ jmp(&done); | 6703 |
6701 | 6704 // Save the array length. |
6702 __ bind(&non_trivial); | 6705 __ bind(&non_trivial_array); |
6703 __ mov(array_length, scratch); | 6706 __ mov(array_length_operand, array_length); |
6704 | 6707 |
6705 __ mov(scratch, FieldOperand(array, JSArray::kElementsOffset)); | 6708 // Save the FixedArray containing array's elements. |
6706 __ mov(elements, scratch); | |
6707 | |
6708 // End of array's live range. | 6709 // End of array's live range. |
6709 result_pos = array; | 6710 elements = array; |
| 6711 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset)); |
6710 array = no_reg; | 6712 array = no_reg; |
6711 | 6713 |
6712 | 6714 |
6713 // Check that the separator is a flat ascii string. | 6715 // Check that all array elements are sequential ASCII strings, and |
6714 __ mov(current_string, separator); | 6716 // accumulate the sum of their lengths, as a smi-encoded value. |
6715 __ test(current_string, Immediate(kSmiTagMask)); | 6717 __ Set(index, Immediate(0)); |
| 6718 __ Set(string_length, Immediate(0)); |
| 6719 // Loop condition: while (index < length). |
| 6720 // Live loop registers: index, array_length, string, |
| 6721 // scratch, string_length, elements. |
| 6722 __ jmp(&loop_condition); |
| 6723 __ bind(&loop); |
| 6724 __ cmp(index, Operand(array_length)); |
| 6725 __ j(greater_equal, &done); |
| 6726 |
| 6727 __ mov(string, FieldOperand(elements, index, |
| 6728 times_pointer_size, |
| 6729 FixedArray::kHeaderSize)); |
| 6730 __ test(string, Immediate(kSmiTagMask)); |
6716 __ j(zero, &bailout); | 6731 __ j(zero, &bailout); |
6717 __ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset)); | 6732 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); |
6718 __ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 6733 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
6719 __ and_(scratch, Immediate( | 6734 __ and_(scratch, Immediate( |
6720 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 6735 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
6721 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); | 6736 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); |
6722 __ j(not_equal, &bailout); | 6737 __ j(not_equal, &bailout); |
6723 // If the separator is the empty string, replace it with NULL. | 6738 __ add(string_length, |
6724 // The test for NULL is quicker than the empty string test, in a loop. | 6739 FieldOperand(string, SeqAsciiString::kLengthOffset)); |
6725 __ cmp(FieldOperand(current_string, SeqAsciiString::kLengthOffset), | 6740 __ j(overflow, &bailout); |
6726 Immediate(0)); | 6741 __ add(Operand(index), Immediate(1)); |
6727 Label separator_checked; | 6742 __ bind(&loop_condition); |
6728 __ j(not_zero, &separator_checked); | 6743 __ cmp(index, Operand(array_length)); |
6729 __ mov(separator, Immediate(0)); | 6744 __ j(less, &loop); |
6730 __ bind(&separator_checked); | 6745 |
6731 | 6746 // If array_length is 1, return elements[0], a string. |
6732 // Check that elements[0] is a flat ascii string, and copy it in new space. | 6747 __ cmp(array_length, 1); |
6733 __ mov(scratch, elements); | 6748 __ j(not_equal, ¬_size_one_array); |
6734 __ mov(current_string, FieldOperand(scratch, FixedArray::kHeaderSize)); | 6749 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize)); |
6735 __ test(current_string, Immediate(kSmiTagMask)); | 6750 __ mov(result_operand, scratch); |
| 6751 __ jmp(&done); |
| 6752 |
| 6753 __ bind(¬_size_one_array); |
| 6754 |
| 6755 // End of array_length live range. |
| 6756 result_pos = array_length; |
| 6757 array_length = no_reg; |
| 6758 |
| 6759 // Live registers: |
| 6760 // string_length: Sum of string lengths, as a smi. |
| 6761 // elements: FixedArray of strings. |
| 6762 |
| 6763 // Check that the separator is a flat ASCII string. |
| 6764 __ mov(string, separator_operand); |
| 6765 __ test(string, Immediate(kSmiTagMask)); |
6736 __ j(zero, &bailout); | 6766 __ j(zero, &bailout); |
6737 __ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset)); | 6767 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); |
6738 __ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 6768 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
6739 __ and_(scratch, Immediate( | 6769 __ and_(scratch, Immediate( |
6740 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 6770 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
6741 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); | 6771 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); |
6742 __ j(not_equal, &bailout); | 6772 __ j(not_equal, &bailout); |
6743 | 6773 |
6744 // Allocate space to copy it. Round up the size to the alignment granularity. | 6774 // Add (separator length times array_length) - separator length |
6745 __ mov(current_string_length, | 6775 // to string_length. |
6746 FieldOperand(current_string, String::kLengthOffset)); | 6776 __ mov(scratch, separator_operand); |
6747 __ shr(current_string_length, 1); | 6777 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset)); |
6748 | 6778 __ sub(string_length, Operand(scratch)); // May be negative, temporarily. |
| 6779 __ imul(scratch, array_length_operand); |
| 6780 __ j(overflow, &bailout); |
| 6781 __ add(string_length, Operand(scratch)); |
| 6782 __ j(overflow, &bailout); |
| 6783 |
| 6784 __ shr(string_length, 1); |
6749 // Live registers and stack values: | 6785 // Live registers and stack values: |
6750 // current_string_length: length of elements[0]. | 6786 // string_length |
6751 | 6787 // elements |
6752 // New string result in new space = elements[0] | 6788 __ AllocateAsciiString(result_pos, string_length, scratch, |
6753 __ AllocateAsciiString(result_pos, current_string_length, scratch_2, | 6789 index, string, &bailout); |
6754 index, no_reg, &bailout); | 6790 __ mov(result_operand, result_pos); |
6755 __ mov(result, result_pos); | 6791 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize)); |
6756 | 6792 |
6757 // Adjust current_string_length to include padding bytes at end of string. | 6793 |
6758 // Keep track of the number of padding bytes. | 6794 __ mov(string, separator_operand); |
6759 __ mov(new_padding_chars, current_string_length); | 6795 __ cmp(FieldOperand(string, SeqAsciiString::kLengthOffset), |
6760 __ add(Operand(current_string_length), Immediate(kObjectAlignmentMask)); | 6796 Immediate(Smi::FromInt(1))); |
6761 __ and_(Operand(current_string_length), Immediate(~kObjectAlignmentMask)); | 6797 __ j(equal, &one_char_separator); |
6762 __ sub(new_padding_chars, Operand(current_string_length)); | 6798 __ j(greater, &long_separator); |
6763 __ neg(new_padding_chars); | 6799 |
6764 __ mov(padding_chars, new_padding_chars); | 6800 |
6765 | 6801 // Empty separator case |
6766 Label copy_loop_1_done; | 6802 __ mov(index, Immediate(0)); |
6767 Label copy_loop_1; | 6803 __ jmp(&loop_1_condition); |
6768 __ test(current_string_length, Operand(current_string_length)); | 6804 // Loop condition: while (index < length). |
6769 __ j(zero, ©_loop_1_done); | 6805 __ bind(&loop_1); |
6770 __ bind(©_loop_1); | 6806 // Each iteration of the loop concatenates one string to the result. |
6771 __ sub(Operand(current_string_length), Immediate(kPointerSize)); | 6807 // Live values in registers: |
6772 __ mov(scratch, FieldOperand(current_string, current_string_length, | 6808 // index: which element of the elements array we are adding to the result. |
6773 times_1, SeqAsciiString::kHeaderSize)); | 6809 // result_pos: the position to which we are currently copying characters. |
6774 __ mov(FieldOperand(result_pos, current_string_length, | 6810 // elements: the FixedArray of strings we are joining. |
6775 times_1, SeqAsciiString::kHeaderSize), | 6811 |
6776 scratch); | 6812 // Get string = array[index]. |
6777 __ j(not_zero, ©_loop_1); | 6813 __ mov(string, FieldOperand(elements, index, |
6778 __ bind(©_loop_1_done); | 6814 times_pointer_size, |
6779 | 6815 FixedArray::kHeaderSize)); |
6780 __ mov(index, Immediate(1)); | 6816 __ mov(string_length, |
6781 // Loop condition: while (index < length). | 6817 FieldOperand(string, String::kLengthOffset)); |
6782 Label loop; | 6818 __ shr(string_length, 1); |
6783 __ bind(&loop); | 6819 __ lea(string, |
6784 __ cmp(index, array_length); | 6820 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
6785 __ j(greater_equal, &done); | 6821 __ CopyBytes(string, result_pos, string_length, scratch); |
6786 | 6822 __ add(Operand(index), Immediate(1)); |
6787 // If the separator is the empty string, signalled by NULL, skip it. | 6823 __ bind(&loop_1_condition); |
6788 Label separator_done; | 6824 __ cmp(index, array_length_operand); |
6789 __ mov(current_string, separator); | 6825 __ j(less, &loop_1); // End while (index < length). |
6790 __ test(current_string, Operand(current_string)); | 6826 __ jmp(&done); |
6791 __ j(zero, &separator_done); | 6827 |
6792 | 6828 |
6793 // Append separator to result. It is known to be a flat ascii string. | 6829 |
6794 __ AppendStringToTopOfNewSpace(current_string, current_string_length, | 6830 // One-character separator case |
6795 result_pos, scratch, scratch_2, result, | 6831 __ bind(&one_char_separator); |
6796 padding_chars, &bailout); | 6832 // Replace separator with its ascii character value. |
6797 __ bind(&separator_done); | 6833 __ mov_b(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize)); |
6798 | 6834 __ mov_b(separator_operand, scratch); |
6799 // Add next element of array to the end of the result. | 6835 |
6800 // Get current_string = array[index]. | 6836 __ Set(index, Immediate(0)); |
6801 __ mov(scratch, elements); | 6837 // Jump into the loop after the code that copies the separator, so the first |
6802 __ mov(current_string, FieldOperand(scratch, index, | 6838 // element is not preceded by a separator |
6803 times_pointer_size, | 6839 __ jmp(&loop_2_entry); |
6804 FixedArray::kHeaderSize)); | 6840 // Loop condition: while (index < length). |
6805 // If current != flat ascii string drop result, return undefined. | 6841 __ bind(&loop_2); |
6806 __ test(current_string, Immediate(kSmiTagMask)); | 6842 // Each iteration of the loop concatenates one string to the result. |
6807 __ j(zero, &bailout); | 6843 // Live values in registers: |
6808 __ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset)); | 6844 // index: which element of the elements array we are adding to the result. |
6809 __ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 6845 // result_pos: the position to which we are currently copying characters. |
6810 __ and_(scratch, Immediate( | 6846 |
6811 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 6847 // Copy the separator character to the result. |
6812 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); | 6848 __ mov_b(scratch, separator_operand); |
6813 __ j(not_equal, &bailout); | 6849 __ mov_b(Operand(result_pos, 0), scratch); |
6814 | 6850 __ inc(result_pos); |
6815 // Append current to the result. | 6851 |
6816 __ AppendStringToTopOfNewSpace(current_string, current_string_length, | 6852 __ bind(&loop_2_entry); |
6817 result_pos, scratch, scratch_2, result, | 6853 // Get string = array[index]. |
6818 padding_chars, &bailout); | 6854 __ mov(string, FieldOperand(elements, index, |
6819 __ add(Operand(index), Immediate(1)); | 6855 times_pointer_size, |
6820 __ jmp(&loop); // End while (index < length). | 6856 FixedArray::kHeaderSize)); |
| 6857 __ mov(string_length, |
| 6858 FieldOperand(string, String::kLengthOffset)); |
| 6859 __ shr(string_length, 1); |
| 6860 __ lea(string, |
| 6861 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
| 6862 __ CopyBytes(string, result_pos, string_length, scratch); |
| 6863 __ add(Operand(index), Immediate(1)); |
| 6864 |
| 6865 __ cmp(index, array_length_operand); |
| 6866 __ j(less, &loop_2); // End while (index < length). |
| 6867 __ jmp(&done); |
| 6868 |
| 6869 |
| 6870 // Long separator case (separator is more than one character). |
| 6871 __ bind(&long_separator); |
| 6872 |
| 6873 __ Set(index, Immediate(0)); |
| 6874 // Jump into the loop after the code that copies the separator, so the first |
| 6875 // element is not preceded by a separator |
| 6876 __ jmp(&loop_3_entry); |
| 6877 // Loop condition: while (index < length). |
| 6878 __ bind(&loop_3); |
| 6879 // Each iteration of the loop concatenates one string to the result. |
| 6880 // Live values in registers: |
| 6881 // index: which element of the elements array we are adding to the result. |
| 6882 // result_pos: the position to which we are currently copying characters. |
| 6883 |
| 6884 // Copy the separator to the result. |
| 6885 __ mov(string, separator_operand); |
| 6886 __ mov(string_length, |
| 6887 FieldOperand(string, String::kLengthOffset)); |
| 6888 __ shr(string_length, 1); |
| 6889 __ lea(string, |
| 6890 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
| 6891 __ CopyBytes(string, result_pos, string_length, scratch); |
| 6892 |
| 6893 __ bind(&loop_3_entry); |
| 6894 // Get string = array[index]. |
| 6895 __ mov(string, FieldOperand(elements, index, |
| 6896 times_pointer_size, |
| 6897 FixedArray::kHeaderSize)); |
| 6898 __ mov(string_length, |
| 6899 FieldOperand(string, String::kLengthOffset)); |
| 6900 __ shr(string_length, 1); |
| 6901 __ lea(string, |
| 6902 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
| 6903 __ CopyBytes(string, result_pos, string_length, scratch); |
| 6904 __ add(Operand(index), Immediate(1)); |
| 6905 |
| 6906 __ cmp(index, array_length_operand); |
| 6907 __ j(less, &loop_3); // End while (index < length). |
| 6908 __ jmp(&done); |
| 6909 |
6821 | 6910 |
6822 __ bind(&bailout); | 6911 __ bind(&bailout); |
6823 __ mov(result, Factory::undefined_value()); | 6912 __ mov(result_operand, Factory::undefined_value()); |
6824 __ bind(&done); | 6913 __ bind(&done); |
6825 __ mov(eax, result); | 6914 __ mov(eax, result_operand); |
6826 // Drop temp values from the stack, and restore context register. | 6915 // Drop temp values from the stack, and restore context register. |
6827 __ add(Operand(esp), Immediate(4 * kPointerSize)); | 6916 __ add(Operand(esp), Immediate(2 * kPointerSize)); |
6828 | 6917 |
6829 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 6918 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
6830 frame_->Drop(1); | 6919 frame_->Drop(1); |
6831 frame_->Push(&array_result); | 6920 frame_->Push(&array_result); |
6832 } | 6921 } |
6833 | 6922 |
6834 | 6923 |
6835 void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) { | 6924 void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) { |
6836 ASSERT(args->length() == 1); | 6925 ASSERT(args->length() == 1); |
6837 Load(args->at(0)); | 6926 Load(args->at(0)); |
(...skipping 3389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10227 memcpy(chunk->GetStartAddress(), desc.buffer, desc.instr_size); | 10316 memcpy(chunk->GetStartAddress(), desc.buffer, desc.instr_size); |
10228 CPU::FlushICache(chunk->GetStartAddress(), desc.instr_size); | 10317 CPU::FlushICache(chunk->GetStartAddress(), desc.instr_size); |
10229 return FUNCTION_CAST<MemCopyFunction>(chunk->GetStartAddress()); | 10318 return FUNCTION_CAST<MemCopyFunction>(chunk->GetStartAddress()); |
10230 } | 10319 } |
10231 | 10320 |
10232 #undef __ | 10321 #undef __ |
10233 | 10322 |
10234 } } // namespace v8::internal | 10323 } } // namespace v8::internal |
10235 | 10324 |
10236 #endif // V8_TARGET_ARCH_IA32 | 10325 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |