Merge pull request #3469 from cfallin/machbuffer-quadratic-labels

Avoid quadratic behavior in pathological label-alias case in MachBuffer.
This commit is contained in:
Chris Fallin
2021-10-21 13:37:40 -07:00
committed by GitHub

View File

@@ -250,8 +250,12 @@ pub struct MachBufferFinalized {
pub unwind_info: SmallVec<[(CodeOffset, UnwindInst); 8]>, pub unwind_info: SmallVec<[(CodeOffset, UnwindInst); 8]>,
} }
static UNKNOWN_LABEL_OFFSET: CodeOffset = 0xffff_ffff; const UNKNOWN_LABEL_OFFSET: CodeOffset = 0xffff_ffff;
static UNKNOWN_LABEL: MachLabel = MachLabel(0xffff_ffff); const UNKNOWN_LABEL: MachLabel = MachLabel(0xffff_ffff);
/// Threshold on max length of `labels_at_this_branch` list to avoid
/// unbounded quadratic behavior (see comment below at use-site).
const LABEL_LIST_THRESHOLD: usize = 100;
/// A label refers to some offset in a `MachBuffer`. It may not be resolved at /// A label refers to some offset in a `MachBuffer`. It may not be resolved at
/// the point at which it is used by emitted code; the buffer records "fixups" /// the point at which it is used by emitted code; the buffer records "fixups"
@@ -791,6 +795,24 @@ impl<I: VCodeInst> MachBuffer<I> {
break; break;
} }
// If the "labels at this branch" list on this branch is
// longer than a threshold, don't do any simplification,
// and let the branch remain to separate those labels from
// the current tail. This avoids quadratic behavior (see
// #3468): otherwise, if a long string of "goto next;
// next:" patterns are emitted, all of the labels will
// coalesce into a long list of aliases for the current
// buffer tail. We must track all aliases of the current
// tail for correctness, but we are also allowed to skip
// optimization (removal) of any branch, so we take the
// escape hatch here and let it stand. In effect this
// "spreads" the many thousands of labels in the
// pathological case among an actual (harmless but
// suboptimal) instruction once per N labels.
if b.labels_at_this_branch.len() > LABEL_LIST_THRESHOLD {
break;
}
// Invariant: we are looking at a branch that ends at the tail of // Invariant: we are looking at a branch that ends at the tail of
// the buffer. // the buffer.