diff options
author | Thiago de Arruda <tpadilha84@gmail.com> | 2015-04-02 09:31:41 -0300 |
---|---|---|
committer | Thiago de Arruda <tpadilha84@gmail.com> | 2015-04-02 11:33:48 -0300 |
commit | 2b7f460716e5c979817f23ba5d9e33d3ab3c9ca0 (patch) | |
tree | 486fd73bf030ea15e9e38f3649097b2b6cc566e7 /src | |
parent | b3f07b2468edb02a3104082f6e9730f2c9221c19 (diff) | |
download | rneovim-2b7f460716e5c979817f23ba5d9e33d3ab3c9ca0.tar.gz rneovim-2b7f460716e5c979817f23ba5d9e33d3ab3c9ca0.tar.bz2 rneovim-2b7f460716e5c979817f23ba5d9e33d3ab3c9ca0.zip |
eval: Add internal_refcount field to dict_T
Due to the way vimscript garbage collection handles cyclic references, its not
possible to rely on incrementing `dv_refcount` to prevent dicts still used
internally from being collected: If a object with dv_refcount > 0 isn't
reachable by vimscript code, it will be freed when `garbage_collect()` is
called. Add the `internal_refcount` field to prevent this.
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval.c | 12 | ||||
-rw-r--r-- | src/nvim/eval_defs.h | 2 |
2 files changed, 12 insertions, 2 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 9d8421ef04..dae688eb5a 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -5560,8 +5560,10 @@ static int free_unref_items(int copyID) bool did_free = false; // Go through the list of dicts and free items without the copyID. + // Don't free dicts that are referenced internally. for (dict_T *dd = first_dict; dd != NULL; ) { - if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) { + if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK) + && !dd->internal_refcount) { // Free the Dictionary and ordinary items it contains, but don't // recurse into Lists and Dictionaries, they will be in the list // of dicts or list of lists. */ @@ -5671,6 +5673,7 @@ dict_T *dict_alloc(void) FUNC_ATTR_NONNULL_RET d->dv_scope = 0; d->dv_refcount = 0; d->dv_copyID = 0; + d->internal_refcount = 0; return d; } @@ -20064,6 +20067,7 @@ static inline void common_job_callbacks(dict_T *vopts, ufunc_T **on_stdout, return; } + vopts->internal_refcount++; vopts->dv_refcount++; } @@ -20097,7 +20101,11 @@ static inline void free_term_job_data(TerminalJobData *data) { if (data->on_exit) { user_func_unref(data->on_exit); } - dict_unref(data->self); + + if (data->self) { + data->self->internal_refcount--; + dict_unref(data->self); + } free(data); } diff --git a/src/nvim/eval_defs.h b/src/nvim/eval_defs.h index d2de830d6c..34a36004d6 100644 --- a/src/nvim/eval_defs.h +++ b/src/nvim/eval_defs.h @@ -111,6 +111,8 @@ struct dictvar_S { dict_T *dv_copydict; /* copied dict used by deepcopy() */ dict_T *dv_used_next; /* next dict in used dicts list */ dict_T *dv_used_prev; /* previous dict in used dicts list */ + int internal_refcount; // number of internal references to + // prevent garbage collection }; #endif // NVIM_EVAL_DEFS_H |