Skip to content

Commit 60fcc2e

Browse files
dschospearce
authored andcommitted
clear_commit_marks(): avoid deep recursion
Before this patch, clear_commit_marks() recursed for each parent. This could be potentially very expensive in terms of stack space. Probably the only reason that this did not lead to problems is the fact that we typically call clear_commit_marks() after marking a relatively small set of commits. Use (sort of) a tail recursion instead: first recurse on the parents other than the first one, and then continue the loop with the first parent. Noticed by Shawn Pearce. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Lars Hjemli <hjemli@gmail.com> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
1 parent 7b40a45 commit 60fcc2e

File tree

1 file changed

+14
-9
lines changed

1 file changed

+14
-9
lines changed

commit.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -441,17 +441,22 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
441441

442442
void clear_commit_marks(struct commit *commit, unsigned int mark)
443443
{
444-
struct commit_list *parents;
444+
while (commit) {
445+
struct commit_list *parents;
445446

446-
commit->object.flags &= ~mark;
447-
parents = commit->parents;
448-
while (parents) {
449-
struct commit *parent = parents->item;
447+
if (!(mark & commit->object.flags))
448+
return;
450449

451-
/* Have we already cleared this? */
452-
if (mark & parent->object.flags)
453-
clear_commit_marks(parent, mark);
454-
parents = parents->next;
450+
commit->object.flags &= ~mark;
451+
452+
parents = commit->parents;
453+
if (!parents)
454+
return;
455+
456+
while ((parents = parents->next))
457+
clear_commit_marks(parents->item, mark);
458+
459+
commit = commit->parents->item;
455460
}
456461
}
457462

0 commit comments

Comments
 (0)