@@ -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,30 +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- func_unref(pt->pt_name);
12023- vim_free(pt->pt_name);
12024- vim_free(pt);
12025- }
12026-
12027- /*
12028- * Unreference a closure: decrement the reference count and free it when it
12029- * becomes zero.
12030- */
12031- void
12032- partial_unref(partial_T *pt)
12033- {
12034- if (pt != NULL && --pt->pt_refcount <= 0)
12035- partial_free(pt);
12036- }
12037-
1203812058/*
1203912059 * "garbagecollect()" function
1204012060 */
@@ -21824,16 +21844,20 @@ handle_subscript(
2182421844 selfdict = NULL;
2182521845 if (rettv->v_type == VAR_FUNC)
2182621846 {
21827- /* just a function: use selfdict */
21847+ /* Just a function: Take over the function name and use
21848+ * selfdict. */
2182821849 pt->pt_name = rettv->vval.v_string;
2182921850 }
2183021851 else
2183121852 {
2183221853 partial_T *ret_pt = rettv->vval.v_partial;
2183321854 int i;
2183421855
21835- /* partial: use selfdict and copy args */
21856+ /* Partial: copy the function name, use selfdict and copy
21857+ * args. Can't take over name or args, the partial might
21858+ * be referenced elsewhere. */
2183621859 pt->pt_name = vim_strsave(ret_pt->pt_name);
21860+ func_ref(pt->pt_name);
2183721861 if (ret_pt->pt_argc > 0)
2183821862 {
2183921863 pt->pt_argv = (typval_T *)alloc(
@@ -21850,7 +21874,6 @@ handle_subscript(
2185021874 }
2185121875 partial_unref(ret_pt);
2185221876 }
21853- func_ref(pt->pt_name);
2185421877 rettv->v_type = VAR_PARTIAL;
2185521878 rettv->vval.v_partial = pt;
2185621879 }
0 commit comments