@@ -209,7 +209,9 @@ static hashtab_T func_hashtab;
209209/* The names of packages that once were loaded are remembered. */
210210static garray_T ga_loaded = {0, 0, sizeof(char_u *), 4, NULL};
211211
212- /* list heads for garbage collection */
212+ /* List heads for garbage collection. Although there can be a reference loop
213+ * from partial to dict to partial, we don't need to keep track of the partial,
214+ * since it will get freed when the dict is unused and gets freed. */
213215static dict_T *first_dict = NULL; /* list of all dicts */
214216static list_T *first_list = NULL; /* list of all lists */
215217
@@ -7130,9 +7132,14 @@ set_ref_in_item(
71307132 list_T *ll;
71317133 int abort = FALSE;
71327134
7133- if (tv->v_type == VAR_DICT)
7135+ if (tv->v_type == VAR_DICT || tv->v_type == VAR_PARTIAL )
71347136 {
7135- dd = tv->vval.v_dict;
7137+ if (tv->v_type == VAR_DICT)
7138+ dd = tv->vval.v_dict;
7139+ else if (tv->vval.v_partial != NULL)
7140+ dd = tv->vval.v_partial->pt_dict;
7141+ else
7142+ dd = NULL;
71367143 if (dd != NULL && dd->dv_copyID != copyID)
71377144 {
71387145 /* Didn't see this dict yet. */
@@ -7184,6 +7191,32 @@ set_ref_in_item(
71847191 return abort;
71857192}
71867193
7194+ static void
7195+ partial_free(partial_T *pt, int free_dict)
7196+ {
7197+ int i;
7198+
7199+ for (i = 0; i < pt->pt_argc; ++i)
7200+ clear_tv(&pt->pt_argv[i]);
7201+ vim_free(pt->pt_argv);
7202+ if (free_dict)
7203+ dict_unref(pt->pt_dict);
7204+ func_unref(pt->pt_name);
7205+ vim_free(pt->pt_name);
7206+ vim_free(pt);
7207+ }
7208+
7209+ /*
7210+ * Unreference a closure: decrement the reference count and free it when it
7211+ * becomes zero.
7212+ */
7213+ void
7214+ partial_unref(partial_T *pt)
7215+ {
7216+ if (pt != NULL && --pt->pt_refcount <= 0)
7217+ partial_free(pt, TRUE);
7218+ }
7219+
71877220/*
71887221 * Allocate an empty header for a dictionary.
71897222 */
@@ -7275,7 +7308,18 @@ dict_free(
72757308 hash_remove(&d->dv_hashtab, hi);
72767309 if (recurse || (di->di_tv.v_type != VAR_LIST
72777310 && di->di_tv.v_type != VAR_DICT))
7278- clear_tv(&di->di_tv);
7311+ {
7312+ if (!recurse && di->di_tv.v_type == VAR_PARTIAL)
7313+ {
7314+ partial_T *pt = di->di_tv.vval.v_partial;
7315+
7316+ /* We unref the partial but not the dict it refers to. */
7317+ if (pt != NULL && --pt->pt_refcount == 0)
7318+ partial_free(pt, FALSE);
7319+ }
7320+ else
7321+ clear_tv(&di->di_tv);
7322+ }
72797323 vim_free(di);
72807324 --todo;
72817325 }
@@ -12011,31 +12055,6 @@ f_function(typval_T *argvars, typval_T *rettv)
1201112055 }
1201212056}
1201312057
12014- static void
12015- partial_free(partial_T *pt)
12016- {
12017- int i;
12018-
12019- for (i = 0; i < pt->pt_argc; ++i)
12020- clear_tv(&pt->pt_argv[i]);
12021- vim_free(pt->pt_argv);
12022- dict_unref(pt->pt_dict);
12023- func_unref(pt->pt_name);
12024- vim_free(pt->pt_name);
12025- vim_free(pt);
12026- }
12027-
12028- /*
12029- * Unreference a closure: decrement the reference count and free it when it
12030- * becomes zero.
12031- */
12032- void
12033- partial_unref(partial_T *pt)
12034- {
12035- if (pt != NULL && --pt->pt_refcount <= 0)
12036- partial_free(pt);
12037- }
12038-
1203912058/*
1204012059 * "garbagecollect()" function
1204112060 */
0 commit comments