diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2021-01-14 19:43:30 -0800 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2021-01-14 19:43:30 -0800 |
| commit | 2c43d65c7db47f2b682b8924669b8e6aef22ec0a (patch) | |
| tree | 54eef343d568fa5272b9114fab2d40c197076ae8 | |
| parent | 3cd61e3abc79a80d38afa9c633c59585aeb0311a (diff) | |
Made all the heap garbage collection code optional, which saves some
time and memory.
| -rw-r--r-- | bp.c | 4 | ||||
| -rw-r--r-- | types.h | 5 | ||||
| -rw-r--r-- | vm.c | 48 | ||||
| -rw-r--r-- | vm.h | 4 |
4 files changed, 47 insertions, 14 deletions
@@ -120,7 +120,9 @@ static int process_file(def_t *defs, const char *filename, vm_op_t *pattern, uns } recycle_if_unused(&m); +#ifdef DEBUG_HEAP check(recycle_all_matches() == 0, "Memory leak: there should no longer be any matches in use at this point."); +#endif destroy_file(&f); return success; @@ -300,7 +302,7 @@ int main(int argc, char *argv[]) } if (flags & BP_JSON) printf("]\n"); -#ifdef FREE_ON_EXIT +#ifdef DEBUG_HEAP // This code frees up all residual heap-allocated memory. Since the program // is about to exit, this step is unnecessary. However, it is useful for // tracking down memory leaks. @@ -94,7 +94,10 @@ typedef struct match_s { struct match_s *child, *nextsibling; vm_op_t *op; // Intrusive linked list nodes for garbage collection: - struct match_s **atme, *next; + struct match_s *next; +#ifdef DEBUG_HEAP + struct match_s **atme; +#endif int refcount; } match_t; @@ -12,9 +12,11 @@ #include "utils.h" #include "vm.h" -// Linked list operations: -#define LL_PREPEND(head, node) do { (node)->atme = &(head); (node)->next = head; if (head) (head)->atme = &(node)->next; head = node; } while(0) -#define LL_REMOVE(node) do { *(node)->atme = (node)->next; if ((node)->next) (node)->next->atme = (node)->atme; } while(0) +#ifdef DEBUG_HEAP +// Doubly-linked list operations: +#define DLL_PREPEND(head, node) do { (node)->atme = &(head); (node)->next = head; if (head) (head)->atme = &(node)->next; head = node; } while(0) +#define DLL_REMOVE(node) do { *(node)->atme = (node)->next; if ((node)->next) (node)->next->atme = (node)->atme; } while(0) +#endif // Refcounting ownership-setting macros: #define ADD_OWNER(owner, m) do { owner = m; ++(m)->refcount; } while(0) @@ -26,7 +28,10 @@ // the `unused_matches` linked list so it can be reused without the need for // additional calls to malloc/free. Thus, it is an invariant that every match // object is in one of these two lists: -static match_t *in_use_matches = NULL, *unused_matches = NULL; +static match_t *unused_matches = NULL; +#ifdef DEBUG_HEAP +static match_t *in_use_matches = NULL; +#endif __attribute__((nonnull, pure)) static inline const char *next_char(file_t *f, const char *str); @@ -552,15 +557,27 @@ match_t *get_capture(match_t *m, const char **id) match_t *new_match(void) { match_t *m; + +#ifdef DEBUG_HEAP if (unused_matches) { m = unused_matches; - LL_REMOVE(m); + DLL_REMOVE(m); memset(m, 0, sizeof(match_t)); } else { m = new(match_t); } // Keep track of the object: - LL_PREPEND(in_use_matches, m); + DLL_PREPEND(in_use_matches, m); +#else + if (unused_matches) { + m = unused_matches; + unused_matches = unused_matches->next; + memset(m, 0, sizeof(match_t)); + } else { + m = new(match_t); + } +#endif + return m; } @@ -580,12 +597,20 @@ void recycle_if_unused(match_t **at_m) REMOVE_OWNERSHIP(m->child); REMOVE_OWNERSHIP(m->nextsibling); - LL_REMOVE(m); +#ifdef DEBUG_HEAP + DLL_REMOVE(m); // Remove from in_use_matches memset(m, 0, sizeof(match_t)); - LL_PREPEND(unused_matches, m); + DLL_PREPEND(unused_matches, m); +#else + memset(m, 0, sizeof(match_t)); + m->next = unused_matches; + unused_matches = m; +#endif + *at_m = NULL; } +#ifdef DEBUG_HEAP // // Force all match objects into the pool of unused match objects. // @@ -594,8 +619,8 @@ size_t recycle_all_matches(void) size_t count = 0; while (in_use_matches) { match_t *m = in_use_matches; - LL_REMOVE(m); - LL_PREPEND(unused_matches, m); + DLL_REMOVE(m); + DLL_PREPEND(unused_matches, m); ++count; } return count; @@ -610,12 +635,13 @@ size_t free_all_matches(void) recycle_all_matches(); while (unused_matches) { match_t *m = unused_matches; - LL_REMOVE(m); + DLL_REMOVE(m); free(m); ++count; } return count; } +#endif // // Deallocate memory associated with an op @@ -15,10 +15,12 @@ match_t *get_capture(match_t *m, const char **id); __attribute__((nonnull)) void destroy_op(vm_op_t *op); match_t *new_match(void); -size_t free_all_matches(void); __attribute__((nonnull)) void recycle_if_unused(match_t **at_m); +#ifdef DEBUG_HEAP +size_t free_all_matches(void); size_t recycle_all_matches(void); +#endif #endif // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1 |
