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