Chromium Code Reviews| Index: src/arm/full-codegen-arm.cc |
| =================================================================== |
| --- src/arm/full-codegen-arm.cc (revision 6989) |
| +++ src/arm/full-codegen-arm.cc (working copy) |
| @@ -3200,9 +3200,236 @@ |
| void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { |
| + Label bailout, done, one_char_separator, long_separator, |
| + non_trivial_array, not_size_one_array, loop, |
| + empty_separator_loop, one_char_separator_loop, |
| + one_char_separator_loop_entry, long_separator_loop; |
| + |
| + ASSERT(args->length() == 2); |
| + // We will leave the separator on the stack until the end of the function. |
|
William Hesse
2011/03/01 13:54:11
This comment seems inconsistent with the "pop sepa
Søren Thygesen Gjesse
2011/03/01 14:08:31
Done.
|
| + VisitForStackValue(args->at(1)); |
| + // Load this to r0 (= array) |
| + VisitForAccumulatorValue(args->at(0)); |
| + |
| + // All aliases of the same register have disjoint lifetimes. |
| + Register array = r0; |
| + Register elements = no_reg; // Will be r0. |
| + Register result = no_reg; // Will be r0. |
| + Register separator = r1; |
| + Register array_length = r2; |
| + Register result_pos = no_reg; // Will be r2 |
| + Register string_length = r3; |
| + Register string = r4; |
| + Register element = r5; |
| + Register elements_end = r6; |
| + Register scratch1 = r7; |
| + Register scratch2 = r9; |
| + |
| + // Separator operand is on the stack. |
| + __ pop(separator); |
| + |
| + // Check that the array is a JSArray. |
| + __ JumpIfSmi(array, &bailout); |
| + __ CompareObjectType(array, scratch1, scratch2, JS_ARRAY_TYPE); |
| + __ b(ne, &bailout); |
| + |
| + // Check that the array has fast elements. |
| + __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitField2Offset)); |
| + __ tst(scratch2, Operand(1 << Map::kHasFastElements)); |
| + __ b(eq, &bailout); |
| + |
| + // If the array has length zero, return the empty string. |
| + __ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset)); |
| + __ SmiUntag(array_length, SetCC); |
| + __ b(ne, &non_trivial_array); |
| + __ LoadRoot(r0, Heap::kEmptyStringRootIndex); |
| + __ b(&done); |
| + |
| + __ bind(&non_trivial_array); |
| + |
| + // Get the FixedArray containing array's elements. |
| + elements = array; |
| + __ ldr(elements, FieldMemOperand(array, JSArray::kElementsOffset)); |
| + array = no_reg; // End of array's live range. |
| + |
| + // Check that all array elements are sequential ASCII strings, and |
| + // accumulate the sum of their lengths, as a smi-encoded value. |
| + __ mov(string_length, Operand(0)); |
| + __ add(element, |
| + elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| + __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2)); |
| + // Loop condition: while (element < elements_end). |
| + // Live values in registers: |
| + // elements: Fixed array of strings. |
| + // array_length: Length of the fixed array of strings (not smi) |
| + // separator: Separator string |
| + // string_length: Accumulated sum of string lengths (smi). |
| + // element: Current array element. |
| + // elements_end: Array end. |
| + if (FLAG_debug_code) { |
| + __ cmp(array_length, Operand(0)); |
| + __ Assert(gt, "No empty arrays here in EmitFastAsciiArrayJoin"); |
| + } |
| + __ bind(&loop); |
| + __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
| + __ JumpIfSmi(string, &bailout); |
| + __ ldr(scratch1, FieldMemOperand(string, HeapObject::kMapOffset)); |
| + __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); |
| + __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout); |
| + __ ldr(scratch1, FieldMemOperand(string, SeqAsciiString::kLengthOffset)); |
| + __ add(string_length, string_length, Operand(scratch1)); |
| + __ b(vs, &bailout); |
| + __ cmp(element, elements_end); |
| + __ b(lt, &loop); |
| + |
| + // If array_length is 1, return elements[0], a string. |
| + __ cmp(array_length, Operand(1)); |
| + __ b(ne, ¬_size_one_array); |
| + __ ldr(r0, FieldMemOperand(elements, FixedArray::kHeaderSize)); |
| + __ b(&done); |
| + |
| + __ bind(¬_size_one_array); |
| + |
| + // Live values in registers: |
| + // separator: Separator string |
| + // array_length: Length of the array. |
| + // string_length: Sum of string lengths (smi). |
| + // elements: FixedArray of strings. |
| + |
| + // Check that the separator is a flat ASCII string. |
| + __ JumpIfSmi(separator, &bailout); |
| + __ ldr(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset)); |
| + __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); |
| + __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout); |
| + |
| + // Add (separator length times array_length) - separator length to the |
| + // string_length to get the length of the result string. array_length is not |
| + // smi but the other values are, so the result is a smi |
| + __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset)); |
| + __ sub(string_length, string_length, Operand(scratch1)); |
| + __ smull(scratch2, ip, array_length, scratch1); |
| + // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are |
| + // zero. |
| + __ cmp(ip, Operand(0)); |
| + __ b(ne, &bailout); |
| + __ tst(scratch2, Operand(0x80000000)); |
| + __ b(ne, &bailout); |
| + __ add(string_length, string_length, Operand(scratch2)); |
| + __ b(vs, &bailout); |
| + __ SmiUntag(string_length); |
| + |
| + // Get first element in the array to free up the elements register to be used |
| + // for the result. |
| + __ add(element, |
| + elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| + result = elements; // End of live range for elements. |
| + elements = no_reg; |
| + // Live values in registers: |
|
William Hesse
2011/03/01 13:54:11
array_length must be live here, because you use it
Søren Thygesen Gjesse
2011/03/01 14:08:31
Done.
|
| + // element: First array element |
| + // separator: Separator string |
| + // string_length: Length of result string (not smi) |
| + __ AllocateAsciiString(result, |
| + string_length, |
| + scratch1, |
| + scratch2, |
| + elements_end, |
| + &bailout); |
| + // Prepare for looping. Set up elements_end to end of the array. Set |
| + // result_pos to the position of the result where to write the first |
| + // character. |
| + __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2)); |
| + result_pos = array_length; // End of live range for array_length. |
| + array_length = no_reg; |
| + __ add(result_pos, |
| + result, |
| + Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| + |
| + // Check the length of the separator. |
| + __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset)); |
| + __ cmp(scratch1, Operand(Smi::FromInt(1))); |
| + __ b(eq, &one_char_separator); |
| + __ b(gt, &long_separator); |
| + |
| + // Empty separator case |
| + __ bind(&empty_separator_loop); |
| + // Live values in registers: |
| + // result_pos: the position to which we are currently copying characters. |
| + // element: Current array element. |
| + // elements_end: Array end. |
| + |
| + // Copy next array element to the result. |
| + __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
| + __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); |
| + __ SmiUntag(string_length); |
| + __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| + __ CopyBytes(string, result_pos, string_length, scratch1); |
| + __ cmp(element, elements_end); |
| + __ b(lt, &empty_separator_loop); // End while (element < elements_end). |
| + ASSERT(result.is(r0)); |
| + __ b(&done); |
| + |
| + // One-character separator case |
| + __ bind(&one_char_separator); |
| + // Replace separator with its ascii character value. |
| + __ ldrb(separator, FieldMemOperand(separator, SeqAsciiString::kHeaderSize)); |
| + // Jump into the loop after the code that copies the separator, so the first |
| + // element is not preceded by a separator |
| + __ jmp(&one_char_separator_loop_entry); |
| + |
| + __ bind(&one_char_separator_loop); |
| + // Live values in registers: |
| + // result_pos: the position to which we are currently copying characters. |
| + // element: Current array element. |
| + // elements_end: Array end. |
| + // separator: Single separator ascii char (in lower byte). |
| + |
| + // Copy the separator character to the result. |
| + __ strb(separator, MemOperand(result_pos, 1, PostIndex)); |
| + |
| + // Copy next array element to the result. |
| + __ bind(&one_char_separator_loop_entry); |
| + __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
| + __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); |
| + __ SmiUntag(string_length); |
| + __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| + __ CopyBytes(string, result_pos, string_length, scratch1); |
| + __ cmp(element, elements_end); |
| + __ b(lt, &one_char_separator_loop); // End while (element < elements_end). |
| + ASSERT(result.is(r0)); |
| + __ b(&done); |
| + |
| + // Long separator case (separator is more than one character). Entry is at the |
| + // labe long_separator below. |
|
William Hesse
2011/03/01 13:54:11
label
Søren Thygesen Gjesse
2011/03/01 14:08:31
Done.
|
| + __ bind(&long_separator_loop); |
| + // Live values in registers: |
| + // result_pos: the position to which we are currently copying characters. |
| + // element: Current array element. |
| + // elements_end: Array end. |
| + // separator: Separator string. |
| + |
| + // Copy the separator to the result. |
| + __ ldr(string_length, FieldMemOperand(separator, String::kLengthOffset)); |
| + __ SmiUntag(string_length); |
| + __ add(string, |
| + separator, |
| + Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| + __ CopyBytes(string, result_pos, string_length, scratch1); |
| + |
| + __ bind(&long_separator); |
| + __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
| + __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); |
| + __ SmiUntag(string_length); |
| + __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| + __ CopyBytes(string, result_pos, string_length, scratch1); |
| + __ cmp(element, elements_end); |
| + __ b(lt, &long_separator_loop); // End while (element < elements_end). |
| + ASSERT(result.is(r0)); |
| + __ b(&done); |
| + |
| + __ bind(&bailout); |
| __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
| + __ bind(&done); |
| context()->Plug(r0); |
| - return; |
| } |