@@ -3414,6 +3414,243 @@ void FullCodeGenerator::EmitGetSuperConstructor(CallRuntime* expr) {
34143414}
34153415
34163416
3417+ void FullCodeGenerator::EmitFastOneByteArrayJoin (CallRuntime* expr) {
3418+ Label bailout, done, one_char_separator, long_separator, non_trivial_array,
3419+ not_size_one_array, loop, empty_separator_loop, one_char_separator_loop,
3420+ one_char_separator_loop_entry, long_separator_loop;
3421+ ZoneList<Expression*>* args = expr->arguments ();
3422+ DCHECK (args->length () == 2 );
3423+ VisitForStackValue (args->at (1 ));
3424+ VisitForAccumulatorValue (args->at (0 ));
3425+
3426+ // All aliases of the same register have disjoint lifetimes.
3427+ Register array = r0;
3428+ Register elements = no_reg; // Will be r0.
3429+ Register result = no_reg; // Will be r0.
3430+ Register separator = r1;
3431+ Register array_length = r2;
3432+ Register result_pos = no_reg; // Will be r2
3433+ Register string_length = r3;
3434+ Register string = r4;
3435+ Register element = r5;
3436+ Register elements_end = r6;
3437+ Register scratch = r9;
3438+
3439+ // Separator operand is on the stack.
3440+ __ pop (separator);
3441+
3442+ // Check that the array is a JSArray.
3443+ __ JumpIfSmi (array, &bailout);
3444+ __ CompareObjectType (array, scratch, array_length, JS_ARRAY_TYPE );
3445+ __ b (ne, &bailout);
3446+
3447+ // Check that the array has fast elements.
3448+ __ CheckFastElements (scratch, array_length, &bailout);
3449+
3450+ // If the array has length zero, return the empty string.
3451+ __ ldr (array_length, FieldMemOperand (array, JSArray::kLengthOffset ));
3452+ __ SmiUntag (array_length, SetCC);
3453+ __ b (ne, &non_trivial_array);
3454+ __ LoadRoot (r0, Heap::kempty_stringRootIndex);
3455+ __ b (&done);
3456+
3457+ __ bind (&non_trivial_array);
3458+
3459+ // Get the FixedArray containing array's elements.
3460+ elements = array;
3461+ __ ldr (elements, FieldMemOperand (array, JSArray::kElementsOffset ));
3462+ array = no_reg; // End of array's live range.
3463+
3464+ // Check that all array elements are sequential one-byte strings, and
3465+ // accumulate the sum of their lengths, as a smi-encoded value.
3466+ __ mov (string_length, Operand::Zero ());
3467+ __ add (element,
3468+ elements, Operand (FixedArray::kHeaderSize - kHeapObjectTag ));
3469+ __ add (elements_end, element, Operand (array_length, LSL , kPointerSizeLog2 ));
3470+ // Loop condition: while (element < elements_end).
3471+ // Live values in registers:
3472+ // elements: Fixed array of strings.
3473+ // array_length: Length of the fixed array of strings (not smi)
3474+ // separator: Separator string
3475+ // string_length: Accumulated sum of string lengths (smi).
3476+ // element: Current array element.
3477+ // elements_end: Array end.
3478+ if (generate_debug_code_) {
3479+ __ cmp (array_length, Operand::Zero ());
3480+ __ Assert (gt, kNoEmptyArraysHereInEmitFastOneByteArrayJoin );
3481+ }
3482+ __ bind (&loop);
3483+ __ ldr (string, MemOperand (element, kPointerSize , PostIndex));
3484+ __ JumpIfSmi (string, &bailout);
3485+ __ ldr (scratch, FieldMemOperand (string, HeapObject::kMapOffset ));
3486+ __ ldrb (scratch, FieldMemOperand (scratch, Map::kInstanceTypeOffset ));
3487+ __ JumpIfInstanceTypeIsNotSequentialOneByte (scratch, scratch, &bailout);
3488+ __ ldr (scratch, FieldMemOperand (string, SeqOneByteString::kLengthOffset ));
3489+ __ add (string_length, string_length, Operand (scratch), SetCC);
3490+ __ b (vs, &bailout);
3491+ __ cmp (element, elements_end);
3492+ __ b (lt, &loop);
3493+
3494+ // If array_length is 1, return elements[0], a string.
3495+ __ cmp (array_length, Operand (1 ));
3496+ __ b (ne, ¬_size_one_array);
3497+ __ ldr (r0, FieldMemOperand (elements, FixedArray::kHeaderSize ));
3498+ __ b (&done);
3499+
3500+ __ bind (¬_size_one_array);
3501+
3502+ // Live values in registers:
3503+ // separator: Separator string
3504+ // array_length: Length of the array.
3505+ // string_length: Sum of string lengths (smi).
3506+ // elements: FixedArray of strings.
3507+
3508+ // Check that the separator is a flat one-byte string.
3509+ __ JumpIfSmi (separator, &bailout);
3510+ __ ldr (scratch, FieldMemOperand (separator, HeapObject::kMapOffset ));
3511+ __ ldrb (scratch, FieldMemOperand (scratch, Map::kInstanceTypeOffset ));
3512+ __ JumpIfInstanceTypeIsNotSequentialOneByte (scratch, scratch, &bailout);
3513+
3514+ // Add (separator length times array_length) - separator length to the
3515+ // string_length to get the length of the result string. array_length is not
3516+ // smi but the other values are, so the result is a smi
3517+ __ ldr (scratch, FieldMemOperand (separator, SeqOneByteString::kLengthOffset ));
3518+ __ sub (string_length, string_length, Operand (scratch));
3519+ __ smull (scratch, ip, array_length, scratch);
3520+ // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are
3521+ // zero.
3522+ __ cmp (ip, Operand::Zero ());
3523+ __ b (ne, &bailout);
3524+ __ tst (scratch, Operand (0x80000000 ));
3525+ __ b (ne, &bailout);
3526+ __ add (string_length, string_length, Operand (scratch), SetCC);
3527+ __ b (vs, &bailout);
3528+ __ SmiUntag (string_length);
3529+
3530+ // Bailout for large object allocations.
3531+ __ cmp (string_length, Operand (Page::kMaxRegularHeapObjectSize ));
3532+ __ b (gt, &bailout);
3533+
3534+ // Get first element in the array to free up the elements register to be used
3535+ // for the result.
3536+ __ add (element,
3537+ elements, Operand (FixedArray::kHeaderSize - kHeapObjectTag ));
3538+ result = elements; // End of live range for elements.
3539+ elements = no_reg;
3540+ // Live values in registers:
3541+ // element: First array element
3542+ // separator: Separator string
3543+ // string_length: Length of result string (not smi)
3544+ // array_length: Length of the array.
3545+ __ AllocateOneByteString (result, string_length, scratch,
3546+ string, // used as scratch
3547+ elements_end, // used as scratch
3548+ &bailout);
3549+ // Prepare for looping. Set up elements_end to end of the array. Set
3550+ // result_pos to the position of the result where to write the first
3551+ // character.
3552+ __ add (elements_end, element, Operand (array_length, LSL , kPointerSizeLog2 ));
3553+ result_pos = array_length; // End of live range for array_length.
3554+ array_length = no_reg;
3555+ __ add (result_pos,
3556+ result,
3557+ Operand (SeqOneByteString::kHeaderSize - kHeapObjectTag ));
3558+
3559+ // Check the length of the separator.
3560+ __ ldr (scratch, FieldMemOperand (separator, SeqOneByteString::kLengthOffset ));
3561+ __ cmp (scratch, Operand (Smi::FromInt (1 )));
3562+ __ b (eq, &one_char_separator);
3563+ __ b (gt, &long_separator);
3564+
3565+ // Empty separator case
3566+ __ bind (&empty_separator_loop);
3567+ // Live values in registers:
3568+ // result_pos: the position to which we are currently copying characters.
3569+ // element: Current array element.
3570+ // elements_end: Array end.
3571+
3572+ // Copy next array element to the result.
3573+ __ ldr (string, MemOperand (element, kPointerSize , PostIndex));
3574+ __ ldr (string_length, FieldMemOperand (string, String::kLengthOffset ));
3575+ __ SmiUntag (string_length);
3576+ __ add (string,
3577+ string,
3578+ Operand (SeqOneByteString::kHeaderSize - kHeapObjectTag ));
3579+ __ CopyBytes (string, result_pos, string_length, scratch);
3580+ __ cmp (element, elements_end);
3581+ __ b (lt, &empty_separator_loop); // End while (element < elements_end).
3582+ DCHECK (result.is (r0));
3583+ __ b (&done);
3584+
3585+ // One-character separator case
3586+ __ bind (&one_char_separator);
3587+ // Replace separator with its one-byte character value.
3588+ __ ldrb (separator, FieldMemOperand (separator, SeqOneByteString::kHeaderSize ));
3589+ // Jump into the loop after the code that copies the separator, so the first
3590+ // element is not preceded by a separator
3591+ __ jmp (&one_char_separator_loop_entry);
3592+
3593+ __ bind (&one_char_separator_loop);
3594+ // Live values in registers:
3595+ // result_pos: the position to which we are currently copying characters.
3596+ // element: Current array element.
3597+ // elements_end: Array end.
3598+ // separator: Single separator one-byte char (in lower byte).
3599+
3600+ // Copy the separator character to the result.
3601+ __ strb (separator, MemOperand (result_pos, 1 , PostIndex));
3602+
3603+ // Copy next array element to the result.
3604+ __ bind (&one_char_separator_loop_entry);
3605+ __ ldr (string, MemOperand (element, kPointerSize , PostIndex));
3606+ __ ldr (string_length, FieldMemOperand (string, String::kLengthOffset ));
3607+ __ SmiUntag (string_length);
3608+ __ add (string,
3609+ string,
3610+ Operand (SeqOneByteString::kHeaderSize - kHeapObjectTag ));
3611+ __ CopyBytes (string, result_pos, string_length, scratch);
3612+ __ cmp (element, elements_end);
3613+ __ b (lt, &one_char_separator_loop); // End while (element < elements_end).
3614+ DCHECK (result.is (r0));
3615+ __ b (&done);
3616+
3617+ // Long separator case (separator is more than one character). Entry is at the
3618+ // label long_separator below.
3619+ __ bind (&long_separator_loop);
3620+ // Live values in registers:
3621+ // result_pos: the position to which we are currently copying characters.
3622+ // element: Current array element.
3623+ // elements_end: Array end.
3624+ // separator: Separator string.
3625+
3626+ // Copy the separator to the result.
3627+ __ ldr (string_length, FieldMemOperand (separator, String::kLengthOffset ));
3628+ __ SmiUntag (string_length);
3629+ __ add (string,
3630+ separator,
3631+ Operand (SeqOneByteString::kHeaderSize - kHeapObjectTag ));
3632+ __ CopyBytes (string, result_pos, string_length, scratch);
3633+
3634+ __ bind (&long_separator);
3635+ __ ldr (string, MemOperand (element, kPointerSize , PostIndex));
3636+ __ ldr (string_length, FieldMemOperand (string, String::kLengthOffset ));
3637+ __ SmiUntag (string_length);
3638+ __ add (string,
3639+ string,
3640+ Operand (SeqOneByteString::kHeaderSize - kHeapObjectTag ));
3641+ __ CopyBytes (string, result_pos, string_length, scratch);
3642+ __ cmp (element, elements_end);
3643+ __ b (lt, &long_separator_loop); // End while (element < elements_end).
3644+ DCHECK (result.is (r0));
3645+ __ b (&done);
3646+
3647+ __ bind (&bailout);
3648+ __ LoadRoot (r0, Heap::kUndefinedValueRootIndex );
3649+ __ bind (&done);
3650+ context ()->Plug (r0);
3651+ }
3652+
3653+
34173654void FullCodeGenerator::EmitDebugIsActive (CallRuntime* expr) {
34183655 DCHECK (expr->arguments ()->length () == 0 );
34193656 ExternalReference debug_is_active =
0 commit comments