Mercurial > vim
comparison src/eval.c @ 8863:e1b84109506a v7.4.1719
commit https://github.com/vim/vim/commit/107e1eef1df3b786ad3ad49fbdb9e058649303b5
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Apr 8 17:07:19 2016 +0200
patch 7.4.1719
Problem: Leaking memory when there is a cycle involving a job and a
partial.
Solution: Add a copyID to job and channel. Set references in items referred
by them. Go through all jobs and channels to find unreferenced
items. Also, decrement reference counts when garbage collecting.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Fri, 08 Apr 2016 17:15:06 +0200 |
parents | 45fe799c9672 |
children | 30988ffb7498 |
comparison
equal
deleted
inserted
replaced
8862:e759159b4432 | 8863:e1b84109506a |
---|---|
428 static int eval_index(char_u **arg, typval_T *rettv, int evaluate, int verbose); | 428 static int eval_index(char_u **arg, typval_T *rettv, int evaluate, int verbose); |
429 static int get_option_tv(char_u **arg, typval_T *rettv, int evaluate); | 429 static int get_option_tv(char_u **arg, typval_T *rettv, int evaluate); |
430 static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate); | 430 static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate); |
431 static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate); | 431 static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate); |
432 static int get_list_tv(char_u **arg, typval_T *rettv, int evaluate); | 432 static int get_list_tv(char_u **arg, typval_T *rettv, int evaluate); |
433 static void list_free_contents(list_T *l); | |
434 static void list_free_list(list_T *l); | |
433 static long list_len(list_T *l); | 435 static long list_len(list_T *l); |
434 static int list_equal(list_T *l1, list_T *l2, int ic, int recursive); | 436 static int list_equal(list_T *l1, list_T *l2, int ic, int recursive); |
435 static int dict_equal(dict_T *d1, dict_T *d2, int ic, int recursive); | 437 static int dict_equal(dict_T *d1, dict_T *d2, int ic, int recursive); |
436 static int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive); | 438 static int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive); |
437 static long list_find_nr(list_T *l, long idx, int *errorp); | 439 static long list_find_nr(list_T *l, long idx, int *errorp); |
456 static int find_internal_func(char_u *name); | 458 static int find_internal_func(char_u *name); |
457 static char_u *deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload); | 459 static char_u *deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload); |
458 static int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict); | 460 static int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict); |
459 static void emsg_funcname(char *ermsg, char_u *name); | 461 static void emsg_funcname(char *ermsg, char_u *name); |
460 static int non_zero_arg(typval_T *argvars); | 462 static int non_zero_arg(typval_T *argvars); |
463 | |
464 static void dict_free_contents(dict_T *d); | |
465 static void dict_free_dict(dict_T *d); | |
461 | 466 |
462 #ifdef FEAT_FLOAT | 467 #ifdef FEAT_FLOAT |
463 static void f_abs(typval_T *argvars, typval_T *rettv); | 468 static void f_abs(typval_T *argvars, typval_T *rettv); |
464 static void f_acos(typval_T *argvars, typval_T *rettv); | 469 static void f_acos(typval_T *argvars, typval_T *rettv); |
465 #endif | 470 #endif |
5587 for (item = list_find(rettv->vval.v_list, n1); | 5592 for (item = list_find(rettv->vval.v_list, n1); |
5588 n1 <= n2; ++n1) | 5593 n1 <= n2; ++n1) |
5589 { | 5594 { |
5590 if (list_append_tv(l, &item->li_tv) == FAIL) | 5595 if (list_append_tv(l, &item->li_tv) == FAIL) |
5591 { | 5596 { |
5592 list_free(l, TRUE); | 5597 list_free(l); |
5593 return FAIL; | 5598 return FAIL; |
5594 } | 5599 } |
5595 item = item->li_next; | 5600 item = item->li_next; |
5596 } | 5601 } |
5597 clear_tv(rettv); | 5602 clear_tv(rettv); |
5928 | 5933 |
5929 return OK; | 5934 return OK; |
5930 } | 5935 } |
5931 | 5936 |
5932 static void | 5937 static void |
5933 partial_free(partial_T *pt, int recursive) | 5938 partial_free(partial_T *pt) |
5934 { | 5939 { |
5935 int i; | 5940 int i; |
5936 | 5941 |
5937 for (i = 0; i < pt->pt_argc; ++i) | 5942 for (i = 0; i < pt->pt_argc; ++i) |
5938 { | 5943 clear_tv(&pt->pt_argv[i]); |
5939 typval_T *tv = &pt->pt_argv[i]; | |
5940 | |
5941 if (recursive || (tv->v_type != VAR_DICT && tv->v_type != VAR_LIST)) | |
5942 clear_tv(tv); | |
5943 } | |
5944 vim_free(pt->pt_argv); | 5944 vim_free(pt->pt_argv); |
5945 if (recursive) | 5945 dict_unref(pt->pt_dict); |
5946 dict_unref(pt->pt_dict); | |
5947 func_unref(pt->pt_name); | 5946 func_unref(pt->pt_name); |
5948 vim_free(pt->pt_name); | 5947 vim_free(pt->pt_name); |
5949 vim_free(pt); | 5948 vim_free(pt); |
5950 } | 5949 } |
5951 | 5950 |
5955 */ | 5954 */ |
5956 void | 5955 void |
5957 partial_unref(partial_T *pt) | 5956 partial_unref(partial_T *pt) |
5958 { | 5957 { |
5959 if (pt != NULL && --pt->pt_refcount <= 0) | 5958 if (pt != NULL && --pt->pt_refcount <= 0) |
5960 partial_free(pt, TRUE); | 5959 partial_free(pt); |
5961 } | |
5962 | |
5963 /* | |
5964 * Like clear_tv(), but do not free lists or dictionaries. | |
5965 * This is when called via free_unref_items(). | |
5966 */ | |
5967 static void | |
5968 clear_tv_no_recurse(typval_T *tv) | |
5969 { | |
5970 if (tv->v_type == VAR_PARTIAL) | |
5971 { | |
5972 partial_T *pt = tv->vval.v_partial; | |
5973 | |
5974 /* We unref the partial but not the dict or any list it | |
5975 * refers to. */ | |
5976 if (pt != NULL && --pt->pt_refcount == 0) | |
5977 partial_free(pt, FALSE); | |
5978 } | |
5979 else if (tv->v_type != VAR_LIST && tv->v_type != VAR_DICT) | |
5980 clear_tv(tv); | |
5981 } | 5960 } |
5982 | 5961 |
5983 /* | 5962 /* |
5984 * Allocate a variable for a List and fill it from "*arg". | 5963 * Allocate a variable for a List and fill it from "*arg". |
5985 * Return OK or FAIL. | 5964 * Return OK or FAIL. |
6029 if (**arg != ']') | 6008 if (**arg != ']') |
6030 { | 6009 { |
6031 EMSG2(_("E697: Missing end of List ']': %s"), *arg); | 6010 EMSG2(_("E697: Missing end of List ']': %s"), *arg); |
6032 failret: | 6011 failret: |
6033 if (evaluate) | 6012 if (evaluate) |
6034 list_free(l, TRUE); | 6013 list_free(l); |
6035 return FAIL; | 6014 return FAIL; |
6036 } | 6015 } |
6037 | 6016 |
6038 *arg = skipwhite(*arg + 1); | 6017 *arg = skipwhite(*arg + 1); |
6039 if (evaluate) | 6018 if (evaluate) |
6093 */ | 6072 */ |
6094 void | 6073 void |
6095 list_unref(list_T *l) | 6074 list_unref(list_T *l) |
6096 { | 6075 { |
6097 if (l != NULL && --l->lv_refcount <= 0) | 6076 if (l != NULL && --l->lv_refcount <= 0) |
6098 list_free(l, TRUE); | 6077 list_free(l); |
6099 } | 6078 } |
6100 | 6079 |
6101 /* | 6080 /* |
6102 * Free a list, including all non-container items it points to. | 6081 * Free a list, including all non-container items it points to. |
6103 * Ignores the reference count. | 6082 * Ignores the reference count. |
6104 */ | 6083 */ |
6105 void | 6084 static void |
6106 list_free( | 6085 list_free_contents(list_T *l) |
6107 list_T *l, | |
6108 int recurse) /* Free Lists and Dictionaries recursively. */ | |
6109 { | 6086 { |
6110 listitem_T *item; | 6087 listitem_T *item; |
6111 | 6088 |
6089 for (item = l->lv_first; item != NULL; item = l->lv_first) | |
6090 { | |
6091 /* Remove the item before deleting it. */ | |
6092 l->lv_first = item->li_next; | |
6093 clear_tv(&item->li_tv); | |
6094 vim_free(item); | |
6095 } | |
6096 } | |
6097 | |
6098 static void | |
6099 list_free_list(list_T *l) | |
6100 { | |
6112 /* Remove the list from the list of lists for garbage collection. */ | 6101 /* Remove the list from the list of lists for garbage collection. */ |
6113 if (l->lv_used_prev == NULL) | 6102 if (l->lv_used_prev == NULL) |
6114 first_list = l->lv_used_next; | 6103 first_list = l->lv_used_next; |
6115 else | 6104 else |
6116 l->lv_used_prev->lv_used_next = l->lv_used_next; | 6105 l->lv_used_prev->lv_used_next = l->lv_used_next; |
6117 if (l->lv_used_next != NULL) | 6106 if (l->lv_used_next != NULL) |
6118 l->lv_used_next->lv_used_prev = l->lv_used_prev; | 6107 l->lv_used_next->lv_used_prev = l->lv_used_prev; |
6119 | 6108 |
6120 for (item = l->lv_first; item != NULL; item = l->lv_first) | |
6121 { | |
6122 /* Remove the item before deleting it. */ | |
6123 l->lv_first = item->li_next; | |
6124 if (recurse) | |
6125 clear_tv(&item->li_tv); | |
6126 else | |
6127 clear_tv_no_recurse(&item->li_tv); | |
6128 vim_free(item); | |
6129 } | |
6130 vim_free(l); | 6109 vim_free(l); |
6110 } | |
6111 | |
6112 void | |
6113 list_free(list_T *l) | |
6114 { | |
6115 if (!in_free_unref_items) | |
6116 { | |
6117 list_free_contents(l); | |
6118 list_free_list(l); | |
6119 } | |
6131 } | 6120 } |
6132 | 6121 |
6133 /* | 6122 /* |
6134 * Allocate a list item. | 6123 * Allocate a list item. |
6135 * It is not initialized, don't forget to set v_lock. | 6124 * It is not initialized, don't forget to set v_lock. |
7014 #ifdef FEAT_PYTHON3 | 7003 #ifdef FEAT_PYTHON3 |
7015 abort = abort || set_ref_in_python3(copyID); | 7004 abort = abort || set_ref_in_python3(copyID); |
7016 #endif | 7005 #endif |
7017 | 7006 |
7018 #ifdef FEAT_JOB_CHANNEL | 7007 #ifdef FEAT_JOB_CHANNEL |
7019 abort = abort || set_ref_in_channel(copyID); | 7008 // abort = abort || set_ref_in_channel(copyID); |
7020 #endif | 7009 #endif |
7021 | 7010 |
7022 if (!abort) | 7011 if (!abort) |
7023 { | 7012 { |
7024 /* | 7013 /* |
7054 | 7043 |
7055 return did_free; | 7044 return did_free; |
7056 } | 7045 } |
7057 | 7046 |
7058 /* | 7047 /* |
7059 * Free lists, dictionaries and jobs that are no longer referenced. | 7048 * Free lists, dictionaries, channels and jobs that are no longer referenced. |
7060 */ | 7049 */ |
7061 static int | 7050 static int |
7062 free_unref_items(int copyID) | 7051 free_unref_items(int copyID) |
7063 { | 7052 { |
7064 dict_T *dd, *dd_next; | 7053 dict_T *dd, *dd_next; |
7065 list_T *ll, *ll_next; | 7054 list_T *ll, *ll_next; |
7066 int did_free = FALSE; | 7055 int did_free = FALSE; |
7067 | 7056 |
7057 /* Let all "free" functions know that we are here. This means no | |
7058 * dictionaries, lists, channels or jobs are to be freed, because we will | |
7059 * do that here. */ | |
7060 in_free_unref_items = TRUE; | |
7061 | |
7062 /* | |
7063 * PASS 1: free the contents of the items. We don't free the items | |
7064 * themselves yet, so that it is possible to decrement refcount counters | |
7065 */ | |
7066 | |
7068 /* | 7067 /* |
7069 * Go through the list of dicts and free items without the copyID. | 7068 * Go through the list of dicts and free items without the copyID. |
7070 */ | 7069 */ |
7071 for (dd = first_dict; dd != NULL; ) | 7070 for (dd = first_dict; dd != NULL; dd = dd->dv_used_next) |
7072 { | |
7073 dd_next = dd->dv_used_next; | |
7074 if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) | 7071 if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) |
7075 { | 7072 { |
7076 /* Free the Dictionary and ordinary items it contains, but don't | 7073 /* Free the Dictionary and ordinary items it contains, but don't |
7077 * recurse into Lists and Dictionaries, they will be in the list | 7074 * recurse into Lists and Dictionaries, they will be in the list |
7078 * of dicts or list of lists. */ | 7075 * of dicts or list of lists. */ |
7079 dict_free(dd, FALSE); | 7076 dict_free_contents(dd); |
7080 did_free = TRUE; | 7077 did_free = TRUE; |
7081 } | 7078 } |
7082 dd = dd_next; | |
7083 } | |
7084 | 7079 |
7085 /* | 7080 /* |
7086 * Go through the list of lists and free items without the copyID. | 7081 * Go through the list of lists and free items without the copyID. |
7087 * But don't free a list that has a watcher (used in a for loop), these | 7082 * But don't free a list that has a watcher (used in a for loop), these |
7088 * are not referenced anywhere. | 7083 * are not referenced anywhere. |
7089 */ | 7084 */ |
7090 for (ll = first_list; ll != NULL; ) | 7085 for (ll = first_list; ll != NULL; ll = ll->lv_used_next) |
7086 if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK) | |
7087 && ll->lv_watch == NULL) | |
7088 { | |
7089 /* Free the List and ordinary items it contains, but don't recurse | |
7090 * into Lists and Dictionaries, they will be in the list of dicts | |
7091 * or list of lists. */ | |
7092 list_free_contents(ll); | |
7093 did_free = TRUE; | |
7094 } | |
7095 | |
7096 #ifdef FEAT_JOB_CHANNEL | |
7097 /* Go through the list of jobs and free items without the copyID. This | |
7098 * must happen before doing channels, because jobs refer to channels, but | |
7099 * the reference from the channel to the job isn't tracked. */ | |
7100 did_free |= free_unused_jobs_contents(copyID, COPYID_MASK); | |
7101 | |
7102 /* Go through the list of channels and free items without the copyID. */ | |
7103 did_free |= free_unused_channels_contents(copyID, COPYID_MASK); | |
7104 #endif | |
7105 | |
7106 /* | |
7107 * PASS 2: free the items themselves. | |
7108 */ | |
7109 for (dd = first_dict; dd != NULL; dd = dd_next) | |
7110 { | |
7111 dd_next = dd->dv_used_next; | |
7112 if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) | |
7113 dict_free_dict(dd); | |
7114 } | |
7115 | |
7116 for (ll = first_list; ll != NULL; ll = ll_next) | |
7091 { | 7117 { |
7092 ll_next = ll->lv_used_next; | 7118 ll_next = ll->lv_used_next; |
7093 if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK) | 7119 if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK) |
7094 && ll->lv_watch == NULL) | 7120 && ll->lv_watch == NULL) |
7095 { | 7121 { |
7096 /* Free the List and ordinary items it contains, but don't recurse | 7122 /* Free the List and ordinary items it contains, but don't recurse |
7097 * into Lists and Dictionaries, they will be in the list of dicts | 7123 * into Lists and Dictionaries, they will be in the list of dicts |
7098 * or list of lists. */ | 7124 * or list of lists. */ |
7099 list_free(ll, FALSE); | 7125 list_free_list(ll); |
7100 did_free = TRUE; | 7126 } |
7101 } | 7127 } |
7102 ll = ll_next; | 7128 |
7103 } | 7129 #ifdef FEAT_JOB_CHANNEL |
7130 /* Go through the list of jobs and free items without the copyID. This | |
7131 * must happen before doing channels, because jobs refer to channels, but | |
7132 * the reference from the channel to the job isn't tracked. */ | |
7133 free_unused_jobs(copyID, COPYID_MASK); | |
7134 | |
7135 /* Go through the list of channels and free items without the copyID. */ | |
7136 free_unused_channels(copyID, COPYID_MASK); | |
7137 #endif | |
7138 | |
7139 in_free_unref_items = FALSE; | |
7104 | 7140 |
7105 return did_free; | 7141 return did_free; |
7106 } | 7142 } |
7107 | 7143 |
7108 /* | 7144 /* |
7202 typval_T *tv, | 7238 typval_T *tv, |
7203 int copyID, | 7239 int copyID, |
7204 ht_stack_T **ht_stack, | 7240 ht_stack_T **ht_stack, |
7205 list_stack_T **list_stack) | 7241 list_stack_T **list_stack) |
7206 { | 7242 { |
7207 dict_T *dd; | |
7208 list_T *ll; | |
7209 int abort = FALSE; | 7243 int abort = FALSE; |
7210 | 7244 |
7211 if (tv->v_type == VAR_DICT || tv->v_type == VAR_PARTIAL) | 7245 if (tv->v_type == VAR_DICT) |
7212 { | 7246 { |
7213 if (tv->v_type == VAR_DICT) | 7247 dict_T *dd = tv->vval.v_dict; |
7214 dd = tv->vval.v_dict; | 7248 |
7215 else if (tv->vval.v_partial != NULL) | |
7216 dd = tv->vval.v_partial->pt_dict; | |
7217 else | |
7218 dd = NULL; | |
7219 if (dd != NULL && dd->dv_copyID != copyID) | 7249 if (dd != NULL && dd->dv_copyID != copyID) |
7220 { | 7250 { |
7221 /* Didn't see this dict yet. */ | 7251 /* Didn't see this dict yet. */ |
7222 dd->dv_copyID = copyID; | 7252 dd->dv_copyID = copyID; |
7223 if (ht_stack == NULL) | 7253 if (ht_stack == NULL) |
7235 newitem->prev = *ht_stack; | 7265 newitem->prev = *ht_stack; |
7236 *ht_stack = newitem; | 7266 *ht_stack = newitem; |
7237 } | 7267 } |
7238 } | 7268 } |
7239 } | 7269 } |
7240 if (tv->v_type == VAR_PARTIAL) | |
7241 { | |
7242 partial_T *pt = tv->vval.v_partial; | |
7243 int i; | |
7244 | |
7245 if (pt != NULL) | |
7246 for (i = 0; i < pt->pt_argc; ++i) | |
7247 abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID, | |
7248 ht_stack, list_stack); | |
7249 } | |
7250 } | 7270 } |
7251 else if (tv->v_type == VAR_LIST) | 7271 else if (tv->v_type == VAR_LIST) |
7252 { | 7272 { |
7253 ll = tv->vval.v_list; | 7273 list_T *ll = tv->vval.v_list; |
7274 | |
7254 if (ll != NULL && ll->lv_copyID != copyID) | 7275 if (ll != NULL && ll->lv_copyID != copyID) |
7255 { | 7276 { |
7256 /* Didn't see this list yet. */ | 7277 /* Didn't see this list yet. */ |
7257 ll->lv_copyID = copyID; | 7278 ll->lv_copyID = copyID; |
7258 if (list_stack == NULL) | 7279 if (list_stack == NULL) |
7272 *list_stack = newitem; | 7293 *list_stack = newitem; |
7273 } | 7294 } |
7274 } | 7295 } |
7275 } | 7296 } |
7276 } | 7297 } |
7298 else if (tv->v_type == VAR_PARTIAL) | |
7299 { | |
7300 partial_T *pt = tv->vval.v_partial; | |
7301 int i; | |
7302 | |
7303 /* A partial does not have a copyID, because it cannot contain itself. | |
7304 */ | |
7305 if (pt != NULL) | |
7306 { | |
7307 if (pt->pt_dict != NULL) | |
7308 { | |
7309 typval_T dtv; | |
7310 | |
7311 dtv.v_type = VAR_DICT; | |
7312 dtv.vval.v_dict = pt->pt_dict; | |
7313 set_ref_in_item(&dtv, copyID, ht_stack, list_stack); | |
7314 } | |
7315 | |
7316 for (i = 0; i < pt->pt_argc; ++i) | |
7317 abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID, | |
7318 ht_stack, list_stack); | |
7319 } | |
7320 } | |
7321 #ifdef FEAT_JOB_CHANNEL | |
7322 else if (tv->v_type == VAR_JOB) | |
7323 { | |
7324 job_T *job = tv->vval.v_job; | |
7325 typval_T dtv; | |
7326 | |
7327 if (job != NULL && job->jv_copyID != copyID) | |
7328 { | |
7329 if (job->jv_channel != NULL) | |
7330 { | |
7331 dtv.v_type = VAR_CHANNEL; | |
7332 dtv.vval.v_channel = job->jv_channel; | |
7333 set_ref_in_item(&dtv, copyID, ht_stack, list_stack); | |
7334 } | |
7335 if (job->jv_exit_partial != NULL) | |
7336 { | |
7337 dtv.v_type = VAR_PARTIAL; | |
7338 dtv.vval.v_partial = job->jv_exit_partial; | |
7339 set_ref_in_item(&dtv, copyID, ht_stack, list_stack); | |
7340 } | |
7341 } | |
7342 } | |
7343 else if (tv->v_type == VAR_CHANNEL) | |
7344 { | |
7345 channel_T *ch =tv->vval.v_channel; | |
7346 int part; | |
7347 typval_T dtv; | |
7348 jsonq_T *jq; | |
7349 cbq_T *cq; | |
7350 | |
7351 if (ch != NULL && ch->ch_copyID != copyID) | |
7352 { | |
7353 for (part = PART_SOCK; part <= PART_IN; ++part) | |
7354 { | |
7355 for (jq = ch->ch_part[part].ch_json_head.jq_next; jq != NULL; | |
7356 jq = jq->jq_next) | |
7357 set_ref_in_item(jq->jq_value, copyID, ht_stack, list_stack); | |
7358 for (cq = ch->ch_part[part].ch_cb_head.cq_next; cq != NULL; | |
7359 cq = cq->cq_next) | |
7360 if (cq->cq_partial != NULL) | |
7361 { | |
7362 dtv.v_type = VAR_PARTIAL; | |
7363 dtv.vval.v_partial = cq->cq_partial; | |
7364 set_ref_in_item(&dtv, copyID, ht_stack, list_stack); | |
7365 } | |
7366 if (ch->ch_part[part].ch_partial != NULL) | |
7367 { | |
7368 dtv.v_type = VAR_PARTIAL; | |
7369 dtv.vval.v_partial = ch->ch_part[part].ch_partial; | |
7370 set_ref_in_item(&dtv, copyID, ht_stack, list_stack); | |
7371 } | |
7372 } | |
7373 if (ch->ch_partial != NULL) | |
7374 { | |
7375 dtv.v_type = VAR_PARTIAL; | |
7376 dtv.vval.v_partial = ch->ch_partial; | |
7377 set_ref_in_item(&dtv, copyID, ht_stack, list_stack); | |
7378 } | |
7379 if (ch->ch_close_partial != NULL) | |
7380 { | |
7381 dtv.v_type = VAR_PARTIAL; | |
7382 dtv.vval.v_partial = ch->ch_close_partial; | |
7383 set_ref_in_item(&dtv, copyID, ht_stack, list_stack); | |
7384 } | |
7385 } | |
7386 } | |
7387 #endif | |
7277 return abort; | 7388 return abort; |
7278 } | 7389 } |
7279 | 7390 |
7280 /* | 7391 /* |
7281 * Allocate an empty header for a dictionary. | 7392 * Allocate an empty header for a dictionary. |
7330 */ | 7441 */ |
7331 void | 7442 void |
7332 dict_unref(dict_T *d) | 7443 dict_unref(dict_T *d) |
7333 { | 7444 { |
7334 if (d != NULL && --d->dv_refcount <= 0) | 7445 if (d != NULL && --d->dv_refcount <= 0) |
7335 dict_free(d, TRUE); | 7446 dict_free(d); |
7336 } | 7447 } |
7337 | 7448 |
7338 /* | 7449 /* |
7339 * Free a Dictionary, including all non-container items it contains. | 7450 * Free a Dictionary, including all non-container items it contains. |
7340 * Ignores the reference count. | 7451 * Ignores the reference count. |
7341 */ | 7452 */ |
7342 void | 7453 static void |
7343 dict_free( | 7454 dict_free_contents(dict_T *d) |
7344 dict_T *d, | |
7345 int recurse) /* Free Lists and Dictionaries recursively. */ | |
7346 { | 7455 { |
7347 int todo; | 7456 int todo; |
7348 hashitem_T *hi; | 7457 hashitem_T *hi; |
7349 dictitem_T *di; | 7458 dictitem_T *di; |
7350 | 7459 |
7460 /* Lock the hashtab, we don't want it to resize while freeing items. */ | |
7461 hash_lock(&d->dv_hashtab); | |
7462 todo = (int)d->dv_hashtab.ht_used; | |
7463 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) | |
7464 { | |
7465 if (!HASHITEM_EMPTY(hi)) | |
7466 { | |
7467 /* Remove the item before deleting it, just in case there is | |
7468 * something recursive causing trouble. */ | |
7469 di = HI2DI(hi); | |
7470 hash_remove(&d->dv_hashtab, hi); | |
7471 clear_tv(&di->di_tv); | |
7472 vim_free(di); | |
7473 --todo; | |
7474 } | |
7475 } | |
7476 hash_clear(&d->dv_hashtab); | |
7477 } | |
7478 | |
7479 static void | |
7480 dict_free_dict(dict_T *d) | |
7481 { | |
7351 /* Remove the dict from the list of dicts for garbage collection. */ | 7482 /* Remove the dict from the list of dicts for garbage collection. */ |
7352 if (d->dv_used_prev == NULL) | 7483 if (d->dv_used_prev == NULL) |
7353 first_dict = d->dv_used_next; | 7484 first_dict = d->dv_used_next; |
7354 else | 7485 else |
7355 d->dv_used_prev->dv_used_next = d->dv_used_next; | 7486 d->dv_used_prev->dv_used_next = d->dv_used_next; |
7356 if (d->dv_used_next != NULL) | 7487 if (d->dv_used_next != NULL) |
7357 d->dv_used_next->dv_used_prev = d->dv_used_prev; | 7488 d->dv_used_next->dv_used_prev = d->dv_used_prev; |
7358 | |
7359 /* Lock the hashtab, we don't want it to resize while freeing items. */ | |
7360 hash_lock(&d->dv_hashtab); | |
7361 todo = (int)d->dv_hashtab.ht_used; | |
7362 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) | |
7363 { | |
7364 if (!HASHITEM_EMPTY(hi)) | |
7365 { | |
7366 /* Remove the item before deleting it, just in case there is | |
7367 * something recursive causing trouble. */ | |
7368 di = HI2DI(hi); | |
7369 hash_remove(&d->dv_hashtab, hi); | |
7370 if (recurse) | |
7371 clear_tv(&di->di_tv); | |
7372 else | |
7373 clear_tv_no_recurse(&di->di_tv); | |
7374 vim_free(di); | |
7375 --todo; | |
7376 } | |
7377 } | |
7378 hash_clear(&d->dv_hashtab); | |
7379 vim_free(d); | 7489 vim_free(d); |
7490 } | |
7491 | |
7492 void | |
7493 dict_free(dict_T *d) | |
7494 { | |
7495 if (!in_free_unref_items) | |
7496 { | |
7497 dict_free_contents(d); | |
7498 dict_free_dict(d); | |
7499 } | |
7380 } | 7500 } |
7381 | 7501 |
7382 /* | 7502 /* |
7383 * Allocate a Dictionary item. | 7503 * Allocate a Dictionary item. |
7384 * The "key" is copied to the new item. | 7504 * The "key" is copied to the new item. |
7825 if (**arg != '}') | 7945 if (**arg != '}') |
7826 { | 7946 { |
7827 EMSG2(_("E723: Missing end of Dictionary '}': %s"), *arg); | 7947 EMSG2(_("E723: Missing end of Dictionary '}': %s"), *arg); |
7828 failret: | 7948 failret: |
7829 if (evaluate) | 7949 if (evaluate) |
7830 dict_free(d, TRUE); | 7950 dict_free(d); |
7831 return FAIL; | 7951 return FAIL; |
7832 } | 7952 } |
7833 | 7953 |
7834 *arg = skipwhite(*arg + 1); | 7954 *arg = skipwhite(*arg + 1); |
7835 if (evaluate) | 7955 if (evaluate) |
7839 ++d->dv_refcount; | 7959 ++d->dv_refcount; |
7840 } | 7960 } |
7841 | 7961 |
7842 return OK; | 7962 return OK; |
7843 } | 7963 } |
7844 | |
7845 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) | |
7846 #endif | |
7847 | 7964 |
7848 static char * | 7965 static char * |
7849 get_var_special_name(int nr) | 7966 get_var_special_name(int nr) |
7850 { | 7967 { |
7851 switch (nr) | 7968 switch (nr) |
15389 || list_append_number(rettv->vval.v_list, | 15506 || list_append_number(rettv->vval.v_list, |
15390 (varnumber_T)-1) == FAIL | 15507 (varnumber_T)-1) == FAIL |
15391 || list_append_number(rettv->vval.v_list, | 15508 || list_append_number(rettv->vval.v_list, |
15392 (varnumber_T)-1) == FAIL)) | 15509 (varnumber_T)-1) == FAIL)) |
15393 { | 15510 { |
15394 list_free(rettv->vval.v_list, TRUE); | 15511 list_free(rettv->vval.v_list); |
15395 rettv->vval.v_list = NULL; | 15512 rettv->vval.v_list = NULL; |
15396 goto theend; | 15513 goto theend; |
15397 } | 15514 } |
15398 } | 15515 } |
15399 else if (type == 2) | 15516 else if (type == 2) |
16486 --cnt; | 16603 --cnt; |
16487 } | 16604 } |
16488 | 16605 |
16489 if (failed) | 16606 if (failed) |
16490 { | 16607 { |
16491 list_free(rettv->vval.v_list, TRUE); | 16608 list_free(rettv->vval.v_list); |
16492 /* readfile doc says an empty list is returned on error */ | 16609 /* readfile doc says an empty list is returned on error */ |
16493 rettv->vval.v_list = list_alloc(); | 16610 rettv->vval.v_list = list_alloc(); |
16494 } | 16611 } |
16495 | 16612 |
16496 vim_free(prev); | 16613 vim_free(prev); |
20068 vim_free(infile); | 20185 vim_free(infile); |
20069 } | 20186 } |
20070 if (res != NULL) | 20187 if (res != NULL) |
20071 vim_free(res); | 20188 vim_free(res); |
20072 if (list != NULL) | 20189 if (list != NULL) |
20073 list_free(list, TRUE); | 20190 list_free(list); |
20074 } | 20191 } |
20075 | 20192 |
20076 /* | 20193 /* |
20077 * "system()" function | 20194 * "system()" function |
20078 */ | 20195 */ |