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)); |
} |