| Index: src/code-stub-assembler.cc | 
| diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc | 
| index be7286e7c7365e8c064a80b6f5d98ddd3ed7ba00..170ad235e316f3f21141e296282c5252e47e402a 100644 | 
| --- a/src/code-stub-assembler.cc | 
| +++ b/src/code-stub-assembler.cc | 
| @@ -2073,47 +2073,66 @@ void CodeStubAssembler::CopyFixedArrayElements( | 
| Comment("] CopyFixedArrayElements"); | 
| } | 
|  | 
| -void CodeStubAssembler::CopyStringCharacters(compiler::Node* from_string, | 
| -                                             compiler::Node* to_string, | 
| -                                             compiler::Node* from_index, | 
| -                                             compiler::Node* to_index, | 
| -                                             compiler::Node* character_count, | 
| -                                             String::Encoding encoding, | 
| -                                             ParameterMode mode) { | 
| -  bool one_byte = encoding == String::ONE_BYTE_ENCODING; | 
| -  Comment(one_byte ? "CopyStringCharacters ONE_BYTE_ENCODING" | 
| -                   : "CopyStringCharacters TWO_BYTE_ENCODING"); | 
| - | 
| -  ElementsKind kind = one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS; | 
| -  int header_size = (one_byte ? SeqOneByteString::kHeaderSize | 
| -                              : SeqTwoByteString::kHeaderSize) - | 
| -                    kHeapObjectTag; | 
| -  Node* from_offset = ElementOffsetFromIndex(from_index, kind, mode); | 
| -  Node* to_offset = ElementOffsetFromIndex(to_index, kind, mode); | 
| -  Node* byte_count = ElementOffsetFromIndex(character_count, kind, mode); | 
| +void CodeStubAssembler::CopyStringCharacters( | 
| +    compiler::Node* from_string, compiler::Node* to_string, | 
| +    compiler::Node* from_index, compiler::Node* to_index, | 
| +    compiler::Node* character_count, String::Encoding from_encoding, | 
| +    String::Encoding to_encoding, ParameterMode mode) { | 
| +  bool from_one_byte = from_encoding == String::ONE_BYTE_ENCODING; | 
| +  bool to_one_byte = to_encoding == String::ONE_BYTE_ENCODING; | 
| +  DCHECK_IMPLIES(to_one_byte, from_one_byte); | 
| +  Comment("CopyStringCharacters %s -> %s", | 
| +          from_one_byte ? "ONE_BYTE_ENCODING" : "TWO_BYTE_ENCODING", | 
| +          to_one_byte ? "ONE_BYTE_ENCODING" : "TWO_BYTE_ENCODING"); | 
| + | 
| +  ElementsKind from_kind = from_one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS; | 
| +  ElementsKind to_kind = to_one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS; | 
| +  STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); | 
| +  int header_size = SeqOneByteString::kHeaderSize - kHeapObjectTag; | 
| +  Node* from_offset = | 
| +      ElementOffsetFromIndex(from_index, from_kind, mode, header_size); | 
| +  Node* to_offset = | 
| +      ElementOffsetFromIndex(to_index, to_kind, mode, header_size); | 
| +  Node* byte_count = ElementOffsetFromIndex(character_count, from_kind, mode); | 
| Node* limit_offset = IntPtrAddFoldConstants(from_offset, byte_count); | 
|  | 
| // Prepare the fast loop | 
| -  MachineType type = one_byte ? MachineType::Uint8() : MachineType::Uint16(); | 
| -  MachineRepresentation rep = | 
| -      one_byte ? MachineRepresentation::kWord8 : MachineRepresentation::kWord16; | 
| -  int increment = -(1 << ElementsKindToShiftSize(kind)); | 
| - | 
| -  Node* to_string_adjusted = IntPtrAddFoldConstants( | 
| -      to_string, IntPtrSubFoldConstants(to_offset, from_offset)); | 
| -  limit_offset = | 
| -      IntPtrAddFoldConstants(limit_offset, IntPtrConstant(header_size)); | 
| -  from_offset = | 
| -      IntPtrAddFoldConstants(from_offset, IntPtrConstant(header_size)); | 
| - | 
| -  BuildFastLoop(MachineType::PointerRepresentation(), limit_offset, from_offset, | 
| -                [from_string, to_string_adjusted, type, rep]( | 
| -                    CodeStubAssembler* assembler, Node* offset) { | 
| +  MachineType type = | 
| +      from_one_byte ? MachineType::Uint8() : MachineType::Uint16(); | 
| +  MachineRepresentation rep = to_one_byte ? MachineRepresentation::kWord8 | 
| +                                          : MachineRepresentation::kWord16; | 
| +  int from_increment = 1 << ElementsKindToShiftSize(from_kind); | 
| +  int to_increment = 1 << ElementsKindToShiftSize(to_kind); | 
| + | 
| +  Variable current_to_offset(this, MachineType::PointerRepresentation()); | 
| +  VariableList vars({¤t_to_offset}, zone()); | 
| +  current_to_offset.Bind(to_offset); | 
| +  int to_index_constant = 0, from_index_constant = 0; | 
| +  Smi* to_index_smi = nullptr; | 
| +  Smi* from_index_smi = nullptr; | 
| +  bool index_same = (from_encoding == to_encoding) && | 
| +                    (from_index == to_index || | 
| +                     (ToInt32Constant(from_index, from_index_constant) && | 
| +                      ToInt32Constant(to_index, to_index_constant) && | 
| +                      from_index_constant == to_index_constant) || | 
| +                     (ToSmiConstant(from_index, from_index_smi) && | 
| +                      ToSmiConstant(to_index, to_index_smi) && | 
| +                      to_index_smi == from_index_smi)); | 
| +  BuildFastLoop(vars, MachineType::PointerRepresentation(), from_offset, | 
| +                limit_offset, | 
| +                [from_string, to_string, ¤t_to_offset, to_increment, type, | 
| +                 rep, index_same](CodeStubAssembler* assembler, Node* offset) { | 
| Node* value = assembler->Load(type, from_string, offset); | 
| -                  assembler->StoreNoWriteBarrier(rep, to_string_adjusted, | 
| -                                                 offset, value); | 
| +                  assembler->StoreNoWriteBarrier( | 
| +                      rep, to_string, | 
| +                      index_same ? offset : current_to_offset.value(), value); | 
| +                  if (!index_same) { | 
| +                    current_to_offset.Bind(assembler->IntPtrAdd( | 
| +                        current_to_offset.value(), | 
| +                        assembler->IntPtrConstant(to_increment))); | 
| +                  } | 
| }, | 
| -                increment); | 
| +                from_increment, IndexAdvanceMode::kPost); | 
| } | 
|  | 
| Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array, | 
| @@ -2983,6 +3002,7 @@ Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context, | 
| a->AllocateSeqOneByteString(context, a->SmiToWord(character_count)); | 
| a->CopyStringCharacters(from, result, from_index, smi_zero, character_count, | 
| String::ONE_BYTE_ENCODING, | 
| +                            String::ONE_BYTE_ENCODING, | 
| CodeStubAssembler::SMI_PARAMETERS); | 
| var_result.Bind(result); | 
|  | 
| @@ -2996,6 +3016,7 @@ Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context, | 
| a->AllocateSeqTwoByteString(context, a->SmiToWord(character_count)); | 
| a->CopyStringCharacters(from, result, from_index, smi_zero, character_count, | 
| String::TWO_BYTE_ENCODING, | 
| +                            String::TWO_BYTE_ENCODING, | 
| CodeStubAssembler::SMI_PARAMETERS); | 
| var_result.Bind(result); | 
|  | 
| @@ -3297,9 +3318,11 @@ Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right, | 
| AllocateSeqOneByteString(context, new_length, SMI_PARAMETERS); | 
| CopyStringCharacters(left, new_string, SmiConstant(Smi::kZero), | 
| SmiConstant(Smi::kZero), left_length, | 
| -                       String::ONE_BYTE_ENCODING, SMI_PARAMETERS); | 
| +                       String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING, | 
| +                       SMI_PARAMETERS); | 
| CopyStringCharacters(right, new_string, SmiConstant(Smi::kZero), left_length, | 
| -                       right_length, String::ONE_BYTE_ENCODING, SMI_PARAMETERS); | 
| +                       right_length, String::ONE_BYTE_ENCODING, | 
| +                       String::ONE_BYTE_ENCODING, SMI_PARAMETERS); | 
| result.Bind(new_string); | 
| Goto(&done_native); | 
|  | 
| @@ -3309,10 +3332,11 @@ Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right, | 
| new_string = AllocateSeqTwoByteString(context, new_length, SMI_PARAMETERS); | 
| CopyStringCharacters(left, new_string, SmiConstant(Smi::kZero), | 
| SmiConstant(Smi::kZero), left_length, | 
| -                         String::TWO_BYTE_ENCODING, SMI_PARAMETERS); | 
| +                         String::TWO_BYTE_ENCODING, String::TWO_BYTE_ENCODING, | 
| +                         SMI_PARAMETERS); | 
| CopyStringCharacters(right, new_string, SmiConstant(Smi::kZero), | 
| left_length, right_length, String::TWO_BYTE_ENCODING, | 
| -                         SMI_PARAMETERS); | 
| +                         String::TWO_BYTE_ENCODING, SMI_PARAMETERS); | 
| result.Bind(new_string); | 
| Goto(&done_native); | 
| } | 
| @@ -6964,12 +6988,15 @@ Node* CodeStubAssembler::CreateWeakCellInFeedbackVector(Node* feedback_vector, | 
| } | 
|  | 
| void CodeStubAssembler::BuildFastLoop( | 
| +    const CodeStubAssembler::VariableList& vars, | 
| MachineRepresentation index_rep, Node* start_index, Node* end_index, | 
| std::function<void(CodeStubAssembler* assembler, Node* index)> body, | 
| int increment, IndexAdvanceMode mode) { | 
| Variable var(this, index_rep); | 
| +  VariableList vars_copy(vars, zone()); | 
| +  vars_copy.Add(&var, zone()); | 
| var.Bind(start_index); | 
| -  Label loop(this, &var); | 
| +  Label loop(this, vars_copy); | 
| Label after_loop(this); | 
| // Introduce an explicit second check of the termination condition before the | 
| // loop that helps turbofan generate better code. If there's only a single | 
|  |