| Index: runtime/vm/regexp_assembler.cc
 | 
| diff --git a/runtime/vm/regexp_assembler.cc b/runtime/vm/regexp_assembler.cc
 | 
| index fa666ae3e55f77a89a0fefa3d1117b628693ded0..ac8f360ec1cff8403890386caef2839d2266155d 100644
 | 
| --- a/runtime/vm/regexp_assembler.cc
 | 
| +++ b/runtime/vm/regexp_assembler.cc
 | 
| @@ -158,6 +158,7 @@ void IRRegExpMacroAssembler::InitializeLocals() {
 | 
|    match_end_index_ = Local(Symbols::match_end_index());
 | 
|    char_in_capture_ = Local(Symbols::char_in_capture());
 | 
|    char_in_match_ = Local(Symbols::char_in_match());
 | 
| +  index_temp_ = Local(Symbols::index_temp());
 | 
|    result_ = Local(Symbols::result());
 | 
|  
 | 
|    string_param_ = Parameter(Symbols::string_param(), 0);
 | 
| @@ -944,8 +945,8 @@ void IRRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(
 | 
|      BlockLabel loop;
 | 
|      BindBlock(&loop);
 | 
|  
 | 
| -    StoreLocal(char_in_capture_, CharacterAt(LoadLocal(capture_start_index_)));
 | 
| -    StoreLocal(char_in_match_, CharacterAt(LoadLocal(match_start_index_)));
 | 
| +    StoreLocal(char_in_capture_, CharacterAt(capture_start_index_));
 | 
| +    StoreLocal(char_in_match_, CharacterAt(match_start_index_));
 | 
|  
 | 
|      BranchOrBacktrack(Comparison(kEQ,
 | 
|                                   LoadLocal(char_in_capture_),
 | 
| @@ -1105,8 +1106,8 @@ void IRRegExpMacroAssembler::CheckNotBackReference(
 | 
|    BlockLabel loop;
 | 
|    BindBlock(&loop);
 | 
|  
 | 
| -  StoreLocal(char_in_capture_, CharacterAt(LoadLocal(capture_start_index_)));
 | 
| -  StoreLocal(char_in_match_, CharacterAt(LoadLocal(match_start_index_)));
 | 
| +  StoreLocal(char_in_capture_, CharacterAt(capture_start_index_));
 | 
| +  StoreLocal(char_in_match_, CharacterAt(match_start_index_));
 | 
|  
 | 
|    BranchOrBacktrack(Comparison(kNE,
 | 
|                                 LoadLocal(char_in_capture_),
 | 
| @@ -1765,9 +1766,6 @@ void IRRegExpMacroAssembler::LoadCurrentCharacterUnchecked(
 | 
|      ASSERT(characters == 1 || characters == 2);
 | 
|    }
 | 
|  
 | 
| -  // Bind the pattern as the load receiver.
 | 
| -  Value* pattern = BindLoadLocal(*string_param_);
 | 
| -
 | 
|    // Calculate the addressed string index as:
 | 
|    //    cp_offset + current_position_ + string_param_length_
 | 
|    // TODO(zerny): Avoid generating 'add' instance-calls here.
 | 
| @@ -1779,30 +1777,53 @@ void IRRegExpMacroAssembler::LoadCurrentCharacterUnchecked(
 | 
|        PushArgument(Bind(Add(off_arg, pos_arg)));
 | 
|    PushArgumentInstr* len_arg =
 | 
|        PushArgument(BindLoadLocal(*string_param_length_));
 | 
| -  Value* index = Bind(Add(off_pos_arg, len_arg));
 | 
| +  // Index is stored in a temporary local so that we can later load it safely.
 | 
| +  StoreLocal(index_temp_, Bind(Add(off_pos_arg, len_arg)));
 | 
|  
 | 
|    // Load and store the code units.
 | 
| -  Value* code_unit_value = LoadCodeUnitsAt(pattern, index, characters);
 | 
| +  Value* code_unit_value = LoadCodeUnitsAt(index_temp_, characters);
 | 
|    StoreLocal(current_character_, code_unit_value);
 | 
|    PRINT(PushLocal(current_character_));
 | 
|  }
 | 
|  
 | 
|  
 | 
| -Value* IRRegExpMacroAssembler::CharacterAt(Definition* index) {
 | 
| -  Value* pattern_val = BindLoadLocal(*string_param_);
 | 
| -  Value* index_val = Bind(index);
 | 
| -  return LoadCodeUnitsAt(pattern_val, index_val, 1);
 | 
| +Value* IRRegExpMacroAssembler::CharacterAt(LocalVariable* index) {
 | 
| +  return LoadCodeUnitsAt(index, 1);
 | 
|  }
 | 
|  
 | 
|  
 | 
| -// Note: We can't replace pattern with a load-local of string_param_
 | 
| -// because we need to maintain the stack discipline in unoptimized code.
 | 
| -Value* IRRegExpMacroAssembler::LoadCodeUnitsAt(Value* pattern,
 | 
| -                                               Value* index,
 | 
| +Value* IRRegExpMacroAssembler::LoadCodeUnitsAt(LocalVariable* index,
 | 
|                                                 intptr_t characters) {
 | 
| +  // Bind the pattern as the load receiver.
 | 
| +  Value* pattern_val = BindLoadLocal(*string_param_);
 | 
| +  if (RawObject::IsExternalStringClassId(specialization_cid_)) {
 | 
| +    // The data of an external string is stored through two indirections.
 | 
| +    intptr_t external_offset;
 | 
| +    intptr_t data_offset;
 | 
| +    if (specialization_cid_ == kExternalOneByteStringCid) {
 | 
| +      external_offset = ExternalOneByteString::external_data_offset();
 | 
| +      data_offset = RawExternalOneByteString::ExternalData::data_offset();
 | 
| +    } else if (specialization_cid_ == kExternalTwoByteStringCid) {
 | 
| +      external_offset = ExternalTwoByteString::external_data_offset();
 | 
| +      data_offset = RawExternalTwoByteString::ExternalData::data_offset();
 | 
| +    } else {
 | 
| +      UNREACHABLE();
 | 
| +    }
 | 
| +    // This pushes untagged values on the stack which are immediately consumed:
 | 
| +    // the first value is consumed to obtain the second value which is consumed
 | 
| +    // by LoadCodeUnitsAtInstr below.
 | 
| +    Value* external_val =
 | 
| +        Bind(new(I) LoadUntaggedInstr(pattern_val, external_offset));
 | 
| +    pattern_val =
 | 
| +        Bind(new(I) LoadUntaggedInstr(external_val, data_offset));
 | 
| +  }
 | 
| +
 | 
| +  // Here pattern_val might be untagged so this must not trigger a GC.
 | 
| +  Value* index_val = BindLoadLocal(*index);
 | 
| +
 | 
|    return Bind(new(I) LoadCodeUnitsInstr(
 | 
| -      pattern,
 | 
| -      index,
 | 
| +      pattern_val,
 | 
| +      index_val,
 | 
|        characters,
 | 
|        specialization_cid_,
 | 
|        Scanner::kNoSourcePos));
 | 
| 
 |