mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
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.
This commit is contained in:
parent
b3f07b2468
commit
2b7f460716
@ -5560,8 +5560,10 @@ static int free_unref_items(int copyID)
|
|||||||
bool did_free = false;
|
bool did_free = false;
|
||||||
|
|
||||||
// Go through the list of dicts and free items without the copyID.
|
// 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; ) {
|
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
|
// Free the Dictionary and ordinary items it contains, but don't
|
||||||
// recurse into Lists and Dictionaries, they will be in the list
|
// recurse into Lists and Dictionaries, they will be in the list
|
||||||
// of dicts or list of lists. */
|
// 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_scope = 0;
|
||||||
d->dv_refcount = 0;
|
d->dv_refcount = 0;
|
||||||
d->dv_copyID = 0;
|
d->dv_copyID = 0;
|
||||||
|
d->internal_refcount = 0;
|
||||||
|
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
@ -20064,6 +20067,7 @@ static inline void common_job_callbacks(dict_T *vopts, ufunc_T **on_stdout,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vopts->internal_refcount++;
|
||||||
vopts->dv_refcount++;
|
vopts->dv_refcount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20097,7 +20101,11 @@ static inline void free_term_job_data(TerminalJobData *data) {
|
|||||||
if (data->on_exit) {
|
if (data->on_exit) {
|
||||||
user_func_unref(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);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +111,8 @@ struct dictvar_S {
|
|||||||
dict_T *dv_copydict; /* copied dict used by deepcopy() */
|
dict_T *dv_copydict; /* copied dict used by deepcopy() */
|
||||||
dict_T *dv_used_next; /* next dict in used dicts list */
|
dict_T *dv_used_next; /* next dict in used dicts list */
|
||||||
dict_T *dv_used_prev; /* previous 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
|
#endif // NVIM_EVAL_DEFS_H
|
||||||
|
Loading…
Reference in New Issue
Block a user