Chromium Code Reviews| Index: src/a64/assembler-a64.cc |
| diff --git a/src/a64/assembler-a64.cc b/src/a64/assembler-a64.cc |
| index 06acffbaacbd83ec98375775f8d0f69010911f2a..0548dca0c661ad27eaa38a223f3c98c5f8a38266 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(); |
| @@ -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 start_of_chain = false; |
| + |
| + while (link != branch && !start_of_chain) { |
| + next_link = link->ImmPCOffsetTarget(); |
| + start_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. |
|
ulan
2014/02/18 10:17:40
I think these comments do not agree with the start
Alexandre Rames
2014/02/18 11:59:20
Renaming `start_of_chain` to `end_of_chain` here a
|
| + 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); |
| + |
| + start_of_chain = false; |
| + link = next_link; |
| + while (!start_of_chain) { |
| + next_link = link->ImmPCOffsetTarget(); |
| + start_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)); |
| } |