diff --git a/alloc.c b/alloc.c index eb22a45c9d..12afadfacd 100644 --- a/alloc.c +++ b/alloc.c @@ -18,25 +18,6 @@ #define BLOCKING 1024 -#define DEFINE_ALLOCATOR(name, type) \ -static unsigned int name##_allocs; \ -void *alloc_##name##_node(void) \ -{ \ - static int nr; \ - static type *block; \ - void *ret; \ - \ - if (!nr) { \ - nr = BLOCKING; \ - block = xmalloc(BLOCKING * sizeof(type)); \ - } \ - nr--; \ - name##_allocs++; \ - ret = block++; \ - memset(ret, 0, sizeof(type)); \ - return ret; \ -} - union any_object { struct object object; struct blob blob; @@ -45,17 +26,73 @@ union any_object { struct tag tag; }; -DEFINE_ALLOCATOR(blob, struct blob) -DEFINE_ALLOCATOR(tree, struct tree) -DEFINE_ALLOCATOR(raw_commit, struct commit) -DEFINE_ALLOCATOR(tag, struct tag) -DEFINE_ALLOCATOR(object, union any_object) +struct alloc_state { + int count; /* total number of nodes allocated */ + int nr; /* number of nodes left in current allocation */ + void *p; /* first free node in current allocation */ +}; + +static inline void *alloc_node(struct alloc_state *s, size_t node_size) +{ + void *ret; + + if (!s->nr) { + s->nr = BLOCKING; + s->p = xmalloc(BLOCKING * node_size); + } + s->nr--; + s->count++; + ret = s->p; + s->p = (char *)s->p + node_size; + memset(ret, 0, node_size); + return ret; +} + +static struct alloc_state blob_state; +void *alloc_blob_node(void) +{ + struct blob *b = alloc_node(&blob_state, sizeof(struct blob)); + b->object.type = OBJ_BLOB; + return b; +} + +static struct alloc_state tree_state; +void *alloc_tree_node(void) +{ + struct tree *t = alloc_node(&tree_state, sizeof(struct tree)); + t->object.type = OBJ_TREE; + return t; +} + +static struct alloc_state tag_state; +void *alloc_tag_node(void) +{ + struct tag *t = alloc_node(&tag_state, sizeof(struct tag)); + t->object.type = OBJ_TAG; + return t; +} + +static struct alloc_state object_state; +void *alloc_object_node(void) +{ + struct object *obj = alloc_node(&object_state, sizeof(union any_object)); + obj->type = OBJ_NONE; + return obj; +} + +static struct alloc_state commit_state; + +unsigned int alloc_commit_index(void) +{ + static unsigned int count; + return count++; +} void *alloc_commit_node(void) { - static int commit_count; - struct commit *c = alloc_raw_commit_node(); - c->index = commit_count++; + struct commit *c = alloc_node(&commit_state, sizeof(struct commit)); + c->object.type = OBJ_COMMIT; + c->index = alloc_commit_index(); return c; } @@ -66,13 +103,13 @@ static void report(const char *name, unsigned int count, size_t size) } #define REPORT(name, type) \ - report(#name, name##_allocs, name##_allocs * sizeof(type) >> 10) + report(#name, name##_state.count, name##_state.count * sizeof(type) >> 10) void alloc_report(void) { REPORT(blob, struct blob); REPORT(tree, struct tree); - REPORT(raw_commit, struct commit); + REPORT(commit, struct commit); REPORT(tag, struct tag); REPORT(object, union any_object); } diff --git a/blob.c b/blob.c index ae320bd8fa..1fcb8e44b0 100644 --- a/blob.c +++ b/blob.c @@ -7,15 +7,8 @@ struct blob *lookup_blob(const unsigned char *sha1) { struct object *obj = lookup_object(sha1); if (!obj) - return create_object(sha1, OBJ_BLOB, alloc_blob_node()); - if (!obj->type) - obj->type = OBJ_BLOB; - if (obj->type != OBJ_BLOB) { - error("Object %s is a %s, not a blob", - sha1_to_hex(sha1), typename(obj->type)); - return NULL; - } - return (struct blob *) obj; + return create_object(sha1, alloc_blob_node()); + return object_as_type(obj, OBJ_BLOB, 0); } int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size) diff --git a/builtin/blame.c b/builtin/blame.c index 32ce05f615..23212cbe87 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -2287,7 +2287,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, commit = alloc_commit_node(); commit->object.parsed = 1; commit->date = now; - commit->object.type = OBJ_COMMIT; parent_tail = &commit->parents; if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL)) diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index ce0e019e0c..1c4ad6223e 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -68,9 +68,7 @@ static int diff_tree_stdin(char *line) line[len-1] = 0; if (get_sha1_hex(line, sha1)) return -1; - obj = lookup_unknown_object(sha1); - if (!obj || !obj->parsed) - obj = parse_object(sha1); + obj = parse_object(sha1); if (!obj) return -1; if (obj->type == OBJ_COMMIT) diff --git a/cache.h b/cache.h index 8ae30d5a85..fcb511db70 100644 --- a/cache.h +++ b/cache.h @@ -1402,6 +1402,7 @@ extern void *alloc_commit_node(void); extern void *alloc_tag_node(void); extern void *alloc_object_node(void); extern void alloc_report(void); +extern unsigned int alloc_commit_index(void); /* pkt-line.c */ void packet_trace_identity(const char *prog); diff --git a/commit.c b/commit.c index f1c9d0e2b9..90a6d2974f 100644 --- a/commit.c +++ b/commit.c @@ -18,19 +18,6 @@ int save_commit_buffer = 1; const char *commit_type = "commit"; -static struct commit *check_commit(struct object *obj, - const unsigned char *sha1, - int quiet) -{ - if (obj->type != OBJ_COMMIT) { - if (!quiet) - error("Object %s is a %s, not a commit", - sha1_to_hex(sha1), typename(obj->type)); - return NULL; - } - return (struct commit *) obj; -} - struct commit *lookup_commit_reference_gently(const unsigned char *sha1, int quiet) { @@ -38,7 +25,7 @@ struct commit *lookup_commit_reference_gently(const unsigned char *sha1, if (!obj) return NULL; - return check_commit(obj, sha1, quiet); + return object_as_type(obj, OBJ_COMMIT, quiet); } struct commit *lookup_commit_reference(const unsigned char *sha1) @@ -61,13 +48,9 @@ struct commit *lookup_commit_or_die(const unsigned char *sha1, const char *ref_n struct commit *lookup_commit(const unsigned char *sha1) { struct object *obj = lookup_object(sha1); - if (!obj) { - struct commit *c = alloc_commit_node(); - return create_object(sha1, OBJ_COMMIT, c); - } - if (!obj->type) - obj->type = OBJ_COMMIT; - return check_commit(obj, sha1, 0); + if (!obj) + return create_object(sha1, alloc_commit_node()); + return object_as_type(obj, OBJ_COMMIT, 0); } struct commit *lookup_commit_reference_by_name(const char *name) diff --git a/object.c b/object.c index 91c7c867b9..a16b9f9e93 100644 --- a/object.c +++ b/object.c @@ -130,13 +130,12 @@ static void grow_object_hash(void) obj_hash_size = new_hash_size; } -void *create_object(const unsigned char *sha1, int type, void *o) +void *create_object(const unsigned char *sha1, void *o) { struct object *obj = o; obj->parsed = 0; obj->used = 0; - obj->type = type; obj->flags = 0; hashcpy(obj->sha1, sha1); @@ -148,11 +147,30 @@ void *create_object(const unsigned char *sha1, int type, void *o) return obj; } +void *object_as_type(struct object *obj, enum object_type type, int quiet) +{ + if (obj->type == type) + return obj; + else if (obj->type == OBJ_NONE) { + if (type == OBJ_COMMIT) + ((struct commit *)obj)->index = alloc_commit_index(); + obj->type = type; + return obj; + } + else { + if (!quiet) + error("object %s is a %s, not a %s", + sha1_to_hex(obj->sha1), + typename(obj->type), typename(type)); + return NULL; + } +} + struct object *lookup_unknown_object(const unsigned char *sha1) { struct object *obj = lookup_object(sha1); if (!obj) - obj = create_object(sha1, OBJ_NONE, alloc_object_node()); + obj = create_object(sha1, alloc_object_node()); return obj; } @@ -203,8 +221,6 @@ struct object *parse_object_buffer(const unsigned char *sha1, enum object_type t warning("object %s has unknown type id %d", sha1_to_hex(sha1), type); obj = NULL; } - if (obj && obj->type == OBJ_NONE) - obj->type = type; return obj; } diff --git a/object.h b/object.h index 6e12f2c7f4..5e8d8ee548 100644 --- a/object.h +++ b/object.h @@ -79,7 +79,9 @@ extern struct object *get_indexed_object(unsigned int); */ struct object *lookup_object(const unsigned char *sha1); -extern void *create_object(const unsigned char *sha1, int type, void *obj); +extern void *create_object(const unsigned char *sha1, void *obj); + +void *object_as_type(struct object *obj, enum object_type type, int quiet); /* * Returns the object, having parsed it to find out what it is. diff --git a/refs.c b/refs.c index 3792314f3b..84b9070b8d 100644 --- a/refs.c +++ b/refs.c @@ -1741,9 +1741,8 @@ static enum peel_status peel_object(const unsigned char *name, unsigned char *sh if (o->type == OBJ_NONE) { int type = sha1_object_info(name, NULL); - if (type < 0) + if (type < 0 || !object_as_type(o, type, 0)) return PEEL_INVALID; - o->type = type; } if (o->type != OBJ_TAG) diff --git a/tag.c b/tag.c index 7b07921b30..82d841bf2d 100644 --- a/tag.c +++ b/tag.c @@ -40,15 +40,8 @@ struct tag *lookup_tag(const unsigned char *sha1) { struct object *obj = lookup_object(sha1); if (!obj) - return create_object(sha1, OBJ_TAG, alloc_tag_node()); - if (!obj->type) - obj->type = OBJ_TAG; - if (obj->type != OBJ_TAG) { - error("Object %s is a %s, not a tag", - sha1_to_hex(sha1), typename(obj->type)); - return NULL; - } - return (struct tag *) obj; + return create_object(sha1, alloc_tag_node()); + return object_as_type(obj, OBJ_TAG, 0); } static unsigned long parse_tag_date(const char *buf, const char *tail) diff --git a/tree.c b/tree.c index c8c49d7b78..bb02c1caa4 100644 --- a/tree.c +++ b/tree.c @@ -183,15 +183,8 @@ struct tree *lookup_tree(const unsigned char *sha1) { struct object *obj = lookup_object(sha1); if (!obj) - return create_object(sha1, OBJ_TREE, alloc_tree_node()); - if (!obj->type) - obj->type = OBJ_TREE; - if (obj->type != OBJ_TREE) { - error("Object %s is a %s, not a tree", - sha1_to_hex(sha1), typename(obj->type)); - return NULL; - } - return (struct tree *) obj; + return create_object(sha1, alloc_tree_node()); + return object_as_type(obj, OBJ_TREE, 0); } int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)