]> granicus.if.org Git - git/commitdiff
commit.cocci: refactor code, avoid double rewrite
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Tue, 16 Apr 2019 09:33:18 +0000 (16:33 +0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 16 Apr 2019 09:56:51 +0000 (18:56 +0900)
"maybe" pointer in 'struct commit' is tricky because it can be lazily
initialized to take advantage of commit-graph if available. This makes
it not safe to access directly.

This leads to a rule in commit.cocci to rewrite 'x->maybe_tree' to
'get_commit_tree(x)'. But that rule alone could lead to incorrectly
rewrite assignments, e.g. from

    x->maybe_tree = yes

to

    get_commit_tree(x) = yes

Because of this we have a second rule to revert this effect. Szeder
found out that we could do better by performing the assignment rewrite
rule first, then the remaining is read-only access and handled by the
current first rule.

For this to work, we need to transform "x->maybe_tree = y" to something
that does NOT contain "x->maybe_tree" to avoid the original first
rule. This is where set_commit_tree() comes in.

Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
commit-graph.c
commit.c
contrib/coccinelle/commit.cocci
merge-recursive.c

index 47e9be0a3aad883c17221b11c972b8376a70a555..155a270457bb35dd94c3004455adecde182d4c40 100644 (file)
@@ -343,6 +343,11 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,
        item->generation = get_be32(commit_data + g->hash_len + 8) >> 2;
 }
 
+static inline void set_commit_tree(struct commit *c, struct tree *t)
+{
+       c->maybe_tree = t;
+}
+
 static int fill_commit_in_graph(struct repository *r,
                                struct commit *item,
                                struct commit_graph *g, uint32_t pos)
@@ -356,7 +361,7 @@ static int fill_commit_in_graph(struct repository *r,
        item->object.parsed = 1;
        item->graph_pos = pos;
 
-       item->maybe_tree = NULL;
+       set_commit_tree(item, NULL);
 
        date_high = get_be32(commit_data + g->hash_len + 8) & 0x3;
        date_low = get_be32(commit_data + g->hash_len + 12);
@@ -442,7 +447,7 @@ static struct tree *load_tree_for_commit(struct repository *r,
                                           GRAPH_DATA_WIDTH * (c->graph_pos);
 
        hashcpy(oid.hash, commit_data);
-       c->maybe_tree = lookup_tree(r, &oid);
+       set_commit_tree(c, lookup_tree(r, &oid));
 
        return c->maybe_tree;
 }
index a5333c7ac6c373a13f9298b36be5ff94a90a3e3f..043ba64f1755492e4aaafaf8da38b7edd8c8556a 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -340,6 +340,11 @@ void free_commit_buffer(struct parsed_object_pool *pool, struct commit *commit)
        }
 }
 
+static inline void set_commit_tree(struct commit *c, struct tree *t)
+{
+       c->maybe_tree = t;
+}
+
 struct tree *get_commit_tree(const struct commit *commit)
 {
        if (commit->maybe_tree || !commit->object.parsed)
@@ -358,7 +363,7 @@ struct object_id *get_commit_tree_oid(const struct commit *commit)
 
 void release_commit_memory(struct parsed_object_pool *pool, struct commit *c)
 {
-       c->maybe_tree = NULL;
+       set_commit_tree(c, NULL);
        c->index = 0;
        free_commit_buffer(pool, c);
        free_commit_list(c->parents);
@@ -406,7 +411,7 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
        if (get_oid_hex(bufptr + 5, &parent) < 0)
                return error("bad tree pointer in commit %s",
                             oid_to_hex(&item->object.oid));
-       item->maybe_tree = lookup_tree(r, &parent);
+       set_commit_tree(item, lookup_tree(r, &parent));
        bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
        pptr = &item->parents;
 
index c49aa558f0fe6b74b9d4d4a7779f0a9f32747388..663658a127e653e69bcf3d4576831272890c834f 100644 (file)
@@ -10,19 +10,25 @@ expression c;
 - c->maybe_tree->object.oid.hash
 + get_commit_tree_oid(c)->hash
 
-// These excluded functions must access c->maybe_tree direcly.
 @@
-identifier f !~ "^(get_commit_tree|get_commit_tree_in_graph_one|load_tree_for_commit)$";
+identifier f !~ "^set_commit_tree$";
 expression c;
+expression s;
 @@
   f(...) {<...
-- c->maybe_tree
-+ get_commit_tree(c)
+- c->maybe_tree = s
++ set_commit_tree(c, s)
   ...>}
 
+// These excluded functions must access c->maybe_tree direcly.
+// Note that if c->maybe_tree is written somewhere outside of these
+// functions, then the recommended transformation will be bogus with
+// get_commit_tree() on the LHS.
 @@
+identifier f !~ "^(get_commit_tree|get_commit_tree_in_graph_one|load_tree_for_commit|set_commit_tree)$";
 expression c;
-expression s;
 @@
-- get_commit_tree(c) = s
-+ c->maybe_tree = s
+  f(...) {<...
+- c->maybe_tree
++ get_commit_tree(c)
+  ...>}
index 6c40c61c4728d9224006768599d7bf2ded744bb1..ca4731a719cf1c6428ae6a03e631170d6a30ed37 100644 (file)
@@ -163,6 +163,11 @@ static struct tree *shift_tree_object(struct repository *repo,
        return lookup_tree(repo, &shifted);
 }
 
+static inline void set_commit_tree(struct commit *c, struct tree *t)
+{
+       c->maybe_tree = t;
+}
+
 static struct commit *make_virtual_commit(struct repository *repo,
                                          struct tree *tree,
                                          const char *comment)
@@ -170,7 +175,7 @@ static struct commit *make_virtual_commit(struct repository *repo,
        struct commit *commit = alloc_commit_node(repo);
 
        set_merge_remote_desc(commit, comment, (struct object *)commit);
-       commit->maybe_tree = tree;
+       set_commit_tree(commit, tree);
        commit->object.parsed = 1;
        return commit;
 }