| Index: src/a64/assembler-a64.cc | 
| diff --git a/src/a64/assembler-a64.cc b/src/a64/assembler-a64.cc | 
| index 06acffbaacbd83ec98375775f8d0f69010911f2a..c19148f1f8f78943345d88f9993090e95328fb44 100644 | 
| --- a/src/a64/assembler-a64.cc | 
| +++ b/src/a64/assembler-a64.cc | 
| @@ -289,6 +289,7 @@ bool Operand::NeedsRelocation() const { | 
| Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size) | 
| : AssemblerBase(isolate, buffer, buffer_size), | 
| recorded_ast_id_(TypeFeedbackId::None()), | 
| +      unresolved_branches_(), | 
| positions_recorder_(this) { | 
| const_pool_blocked_nesting_ = 0; | 
| Reset(); | 
| @@ -347,13 +348,13 @@ void Assembler::CheckLabelLinkChain(Label const * label) { | 
| #ifdef DEBUG | 
| if (label->is_linked()) { | 
| int linkoffset = label->pos(); | 
| -    bool start_of_chain = false; | 
| -    while (!start_of_chain) { | 
| +    bool end_of_chain = false; | 
| +    while (!end_of_chain) { | 
| Instruction * link = InstructionAt(linkoffset); | 
| int linkpcoffset = link->ImmPCOffset(); | 
| int prevlinkoffset = linkoffset + linkpcoffset; | 
|  | 
| -      start_of_chain = (linkoffset == prevlinkoffset); | 
| +      end_of_chain = (linkoffset == prevlinkoffset); | 
| linkoffset = linkoffset + linkpcoffset; | 
| } | 
| } | 
| @@ -361,6 +362,86 @@ void Assembler::CheckLabelLinkChain(Label const * label) { | 
| } | 
|  | 
|  | 
| +void Assembler::RemoveBranchFromLabelLinkChain(Instruction* branch, | 
| +                                               Label* label, | 
| +                                               Instruction* label_veneer) { | 
| +  ASSERT(label->is_linked()); | 
| + | 
| +  CheckLabelLinkChain(label); | 
| + | 
| +  Instruction* link = InstructionAt(label->pos()); | 
| +  Instruction* prev_link = link; | 
| +  Instruction* next_link; | 
| +  bool end_of_chain = false; | 
| + | 
| +  while (link != branch && !end_of_chain) { | 
| +    next_link = link->ImmPCOffsetTarget(); | 
| +    end_of_chain = (link == next_link); | 
| +    prev_link = link; | 
| +    link = next_link; | 
| +  } | 
| + | 
| +  ASSERT(branch == link); | 
| +  next_link = branch->ImmPCOffsetTarget(); | 
| + | 
| +  if (branch == prev_link) { | 
| +    // The branch is the first instruction in the chain. | 
| +    if (branch == next_link) { | 
| +      // It is also the last instruction in the chain, so it is the only branch | 
| +      // currently referring to this label. | 
| +      label->Unuse(); | 
| +    } else { | 
| +      label->link_to(reinterpret_cast<byte*>(next_link) - buffer_); | 
| +    } | 
| + | 
| +  } else if (branch == next_link) { | 
| +    // The branch is the last (but not also the first) instruction in the chain. | 
| +    prev_link->SetImmPCOffsetTarget(prev_link); | 
| + | 
| +  } else { | 
| +    // The branch is in the middle of the chain. | 
| +    if (prev_link->IsTargetInImmPCOffsetRange(next_link)) { | 
| +      prev_link->SetImmPCOffsetTarget(next_link); | 
| +    } else if (label_veneer != NULL) { | 
| +      // Use the veneer for all previous links in the chain. | 
| +      prev_link->SetImmPCOffsetTarget(prev_link); | 
| + | 
| +      end_of_chain = false; | 
| +      link = next_link; | 
| +      while (!end_of_chain) { | 
| +        next_link = link->ImmPCOffsetTarget(); | 
| +        end_of_chain = (link == next_link); | 
| +        link->SetImmPCOffsetTarget(label_veneer); | 
| +        link = next_link; | 
| +      } | 
| +    } else { | 
| +      // The assert below will fire. | 
| +      // Some other work could be attempted to fix up the chain, but it would be | 
| +      // rather complicated. If we crash here, we may want to consider using an | 
| +      // other mechanism than a chain of branches. | 
| +      // | 
| +      // Note that this situation currently should not happen, as we always call | 
| +      // this function with a veneer to the target label. | 
| +      // However this could happen with a MacroAssembler in the following state: | 
| +      //    [previous code] | 
| +      //    B(label); | 
| +      //    [20KB code] | 
| +      //    Tbz(label);   // First tbz. Pointing to unconditional branch. | 
| +      //    [20KB code] | 
| +      //    Tbz(label);   // Second tbz. Pointing to the first tbz. | 
| +      //    [more code] | 
| +      // and this function is called to remove the first tbz from the label link | 
| +      // chain. Since tbz has a range of +-32KB, the second tbz cannot point to | 
| +      // the unconditional branch. | 
| +      CHECK(prev_link->IsTargetInImmPCOffsetRange(next_link)); | 
| +      UNREACHABLE(); | 
| +    } | 
| +  } | 
| + | 
| +  CheckLabelLinkChain(label); | 
| +} | 
| + | 
| + | 
| void Assembler::bind(Label* label) { | 
| // Bind label to the address at pc_. All instructions (most likely branches) | 
| // that are linked to this label will be updated to point to the newly-bound | 
| @@ -410,6 +491,8 @@ void Assembler::bind(Label* label) { | 
|  | 
| ASSERT(label->is_bound()); | 
| ASSERT(!label->is_linked()); | 
| + | 
| +  DeleteUnresolvedBranchInfoForLabel(label); | 
| } | 
|  | 
|  | 
| @@ -456,6 +539,20 @@ int Assembler::LinkAndGetByteOffsetTo(Label* label) { | 
| } | 
|  | 
|  | 
| +void Assembler::DeleteUnresolvedBranchInfoForLabel(Label* label) { | 
| +  // Branches to this label will be resolved when the label is bound below. | 
| +  std::multimap<int, FarBranchInfo>::iterator it_tmp, it; | 
| +  it = unresolved_branches_.begin(); | 
| +  while (it != unresolved_branches_.end()) { | 
| +    it_tmp = it++; | 
| +    if (it_tmp->second.label_ == label) { | 
| +      CHECK(it_tmp->first >= pc_offset()); | 
| +      unresolved_branches_.erase(it_tmp); | 
| +    } | 
| +  } | 
| +} | 
| + | 
| + | 
| void Assembler::StartBlockConstPool() { | 
| if (const_pool_blocked_nesting_++ == 0) { | 
| // Prevent constant pool checks happening by setting the next check to | 
| @@ -526,8 +623,7 @@ void Assembler::ConstantPoolGuard() { | 
| instr->preceding()->Rt() == xzr.code()); | 
| #endif | 
|  | 
| -  // Crash by branching to 0. lr now points near the fault. | 
| -  // TODO(all): update the simulator to trap this pattern. | 
| +  // We must generate only one instruction. | 
| Emit(BLR | Rn(xzr)); | 
| } | 
|  | 
|  |