fix(coverity): performance inefficiencies (PASS_BY_VALUE)

The perf cost is negligible, but it's easy to address so might as well.

    CID 653826:         Performance inefficiencies  (PASS_BY_VALUE)
    /src/nvim/input_cmdatom.c: 385             in atom_push_raw()
    384     /// Takes ownership of the atom's allocated members. Caller sets `atom.changed`.
    >>>     CID 653826:         Performance inefficiencies  (PASS_BY_VALUE)
    >>>     Passing parameter atom of type "CmdAtom" (size 176 bytes) by value, which exceeds the low threshold of 128 bytes.
    385     void atom_push_raw(bool cascade, CmdAtom atom)

    CID 653825:         Performance inefficiencies  (PASS_BY_VALUE)
    /src/nvim/input_cmdatom.c: 438             in atom_stage_set()
    436     /// Stages an atom built before its command executes (do_pending_operator() prep-exempt, Visual
    437     /// ops), in the command's frame; pushed at frame end, once `changed` is known.
    >>>     CID 653825:         Performance inefficiencies  (PASS_BY_VALUE)
    >>>     Passing parameter atom of type "CmdAtom" (size 176 bytes) by value, which exceeds the low threshold of 128 bytes.
    438     static void atom_stage_set(CmdAtom atom)

    CID 653824:         Performance inefficiencies  (PASS_BY_VALUE)
    /src/nvim/input_cmdatom.c: 427             in atom_push()
    425     /// Pushes an atom (emit + maybe cascade), or drops it if replay/Visual/internal-op already
    426     /// in-progress.
    >>>     CID 653824:         Performance inefficiencies  (PASS_BY_VALUE)
    >>>     Passing parameter atom of type "CmdAtom" (size 176 bytes) by value, which exceeds the low threshold of 128 bytes.
    427     static void atom_push(bool cascade, CmdAtom atom)
This commit is contained in:
Justin M. Keyes
2026-08-22 14:59:25 +02:00
parent 47cd769ed5
commit b53077d5f0

View File

@@ -389,34 +389,34 @@ static void atom_emit(const CmdAtom *atom)
}
/// Emits a CmdAtom event, or collects it as a subatom of an open scope. If `cascade` is true,
/// queues a copy for mcursor cascade. Takes ownership of the atom's allocated members.
/// queues a copy for mcursor cascade. Takes ownership: `*atom` is invalid after.
///
/// Both scopes (composite, Visual session) can be open. Routed by scope kind, not depth:
/// a collecting Visual session takes the atom, its atom then lands in the composite (",v"+"d").
/// Depth would invert "v@q", where the "@q" composite opened LAST yet collects nothing.
void atom_push_raw(bool cascade, CmdAtom atom)
void atom_push_raw(bool cascade, CmdAtom *atom)
{
assert(atom.keys != NULL);
if (atom.origin.buf.br_buf != NULL) {
assert(atom->keys != NULL);
if (atom->origin.buf.br_buf != NULL) {
// Calculated here, from the atom's own baseline.
atom.changed = atom_origin_changed(atom.origin);
atom.moved = atom_origin_moved(atom.origin);
atom.undoseq = atom_origin_undoseq(atom.origin);
atom->changed = atom_origin_changed(atom->origin);
atom->moved = atom_origin_moved(atom->origin);
atom->undoseq = atom_origin_undoseq(atom->origin);
}
if (atom_visual_pending()) {
if (vatom.state & kVatomTyped) {
// Not for kVatomFed: redo-prep must not mark the enclosing span as captured.
atom_captures++;
}
kv_push(vatom.atoms, atom);
kv_push(vatom.atoms, *atom);
return;
}
atom_captures++;
if (atom.type == kAVisual && kv_size(atom.atoms) > 0) {
if (atom->type == kAVisual && kv_size(atom->atoms) > 0) {
// The completing operator is the only subatom that could have edited.
CmdAtom *last = &kv_A(atom.atoms, kv_size(atom.atoms) - 1);
CmdAtom *last = &kv_A(atom->atoms, kv_size(atom->atoms) - 1);
if (last->type == kAOperator) {
last->changed = atom.changed;
last->changed = atom->changed;
}
}
// `composite.frame`: the command that was executing when a peek opened the composite is not part
@@ -424,8 +424,8 @@ void atom_push_raw(bool cascade, CmdAtom atom)
const bool collect = composite.lhs != NULL
&& (cur_frame == NULL || cur_frame->id != composite.frame);
if (cascade) {
CmdAtom copy = atom;
copy.keys = xstrdup(atom.keys);
CmdAtom copy = *atom;
copy.keys = xstrdup(atom->keys);
copy.text = NULL; // replay (mc_execute()) reads only type/keys/remap: not the text,
copy.lhs = NULL; // nor the label,
copy.atoms = (CmdAtomVec)KV_INITIAL_VALUE; // nor the decomposition
@@ -435,22 +435,22 @@ void atom_push_raw(bool cascade, CmdAtom atom)
}
}
if (collect) {
kv_push(composite.atoms, atom);
kv_push(composite.atoms, *atom);
} else {
if (atom.type != kAInsertSpan) {
if (atom->type != kAInsertSpan) {
// Spans are cascade-internal; only emit the whole session (kAInsert).
atom_emit(&atom);
atom_emit(atom);
}
atom_free(&atom);
atom_free(atom);
}
}
/// Pushes an atom (emit + maybe cascade), or drops it if replay/Visual/internal-op already
/// in-progress.
static void atom_push(bool cascade, CmdAtom atom)
static void atom_push(bool cascade, CmdAtom *atom)
{
if (atom_blocked()) {
atom_free(&atom);
atom_free(atom);
return;
}
atom_push_raw(cascade, atom);
@@ -458,18 +458,18 @@ static void atom_push(bool cascade, CmdAtom atom)
/// Stages an atom built before its command executes (do_pending_operator() prep-exempt, Visual
/// ops), in the command's frame; pushed at frame end, once `changed` is known.
static void atom_stage_set(CmdAtom atom)
static void atom_stage_set(CmdAtom *atom)
{
assert(cur_frame != NULL);
assert(!atom_staged()); // One stage per frame: a second would discard a captured command.
atom_free(&cur_frame->staged);
if (atom_blocked()) {
// Now, not at flush: drop the atom of an internal operator (atom_suppress()).
atom_free(&atom);
atom_free(atom);
return;
}
assert(atom.keys != NULL);
cur_frame->staged = atom;
assert(atom->keys != NULL);
cur_frame->staged = *atom;
}
/// True if an atom is staged for the current command (frame).
@@ -486,7 +486,7 @@ static void atom_stage_flush(CmdFrame *frame)
}
// Staged commands are edits, thus cascade. Except with no keys (poisoned Visual selection).
bool cascade = *frame->staged.keys != NUL;
atom_push(cascade, frame->staged);
atom_push(cascade, &frame->staged);
frame->staged = (CmdAtom){ 0 };
}
@@ -951,8 +951,8 @@ static bool atom_visual_end_suffix(char *suffix, const CmdSpec *spec, bool redoa
xfree(suffix);
atom_visual_reset(); // End the session before staging.
if (emit) {
atom_stage_set((CmdAtom){ .type = kAVisual, .spec = *spec, .keys = xstrdup(""),
.lhs = label, .origin = origin });
atom_stage_set(&(CmdAtom){ .type = kAVisual, .spec = *spec, .keys = xstrdup(""),
.lhs = label, .origin = origin });
}
return prepped;
}
@@ -991,7 +991,7 @@ static bool atom_visual_end_suffix(char *suffix, const CmdSpec *spec, bool redoa
atom.atoms = vatom.atoms;
vatom.atoms = (CmdAtomVec)KV_INITIAL_VALUE;
atom_visual_reset();
atom_stage_set(atom);
atom_stage_set(&atom);
return prep;
}
@@ -1036,7 +1036,7 @@ void atom_capture_op(oparg_T *oap, cmdarg_T *cap, bool redo_yank)
spec.cmdarg = operand ? cap->nchar : NUL;
CmdAtom op_atom = atom_from_spec(kAOperator, spec);
op_atom.origin = cur_frame->origin;
atom_stage_set(op_atom);
atom_stage_set(&op_atom);
}
} else if (!Visual.active || oap->motion_force) {
// Prepped: atom_cmd_end() derives the atom from redobuff.
@@ -1183,7 +1183,7 @@ static void atom_ins_push(const InsSession *session, bool cascade)
}
atom.text = get_last_insert_save();
atom.origin = session->origin;
atom_push_raw(cascade, atom);
atom_push_raw(cascade, &atom);
}
/// Samples the pre-command state at normal_execute() entry; atom_cmd_end() diffs against it to
@@ -1334,7 +1334,7 @@ static void atom_capture_cmd(cmdarg_T *ca, CmdFrame *old)
bool effect = changed || reg_max_ts(true) > old->reg_ts;
if (atom.keys != NULL && *atom.keys != NUL) {
atom.origin = old->origin;
atom_push(effect, atom);
atom_push(effect, &atom);
} else {
atom_free(&atom);
}
@@ -1343,14 +1343,14 @@ static void atom_capture_cmd(cmdarg_T *ca, CmdFrame *old)
// Payload typed in the cmdline ("/pat<CR>"). Emit-only. Not if pattern was not found.
CmdAtom atom = atom_from_cmdline(kAMotion, ca, ca->searchbuf);
atom.origin = old->origin;
atom_push(false, atom);
atom_push(false, &atom);
} else if (!vis && curcmd.cmdline != NULL && (ca->cmdchar == ':' || ca->cmdchar == K_COMMAND)) {
// Same for ":cnext<CR>" or "<Cmd>cnext<CR>". Never a Visual subatom.
CmdAtom atom = atom_from_cmdline(kAExcmd, ca, curcmd.cmdline);
// Payload read during the cmdline execution (`ds)` getchar() => ")").
atom_payload_append(&atom, old);
atom.origin = old->origin;
atom_push(false, atom);
atom_push(false, &atom);
} else if (replayable && (!vis || (keycls & kKeyPayload) == 0)) {
// Non-redoable command (u, zz, q=): never cascaded as an edit.
CmdSpec spec = atom_cmd_spec(ca);
@@ -1360,7 +1360,7 @@ static void atom_capture_cmd(cmdarg_T *ca, CmdFrame *old)
}
CmdAtom atom = atom_from_spec(motion ? kAMotion : jump_cmd ? kAJump : kANormal, spec);
atom.origin = old->origin;
atom_push(follow, atom);
atom_push(follow, &atom);
} else if ((scroll_cmd || mouse_cmd) && !atom_composite_active()) {
// Emit-only (viewport-dependent).
CmdSpec spec = atom_cmd_spec(ca);
@@ -1370,7 +1370,7 @@ static void atom_capture_cmd(cmdarg_T *ca, CmdFrame *old)
}
CmdAtom atom = atom_from_spec(scroll_cmd ? kAScroll : kAMouse, spec);
atom.origin = old->origin;
atom_push(false, atom);
atom_push(false, &atom);
}
if (vis && kv_size(vatom.atoms) == collected && !unchanged) {
// Not replayable: moved the selection by non-collectible keys.