@@ -93,7 +93,6 @@ typedef struct lval_S
9393 char_u *ll_newkey; /* New key for Dict in alloc. mem or NULL. */
9494} lval_T;
9595
96-
9796static char *e_letunexp = N_("E18: Unexpected characters in :let");
9897static char *e_listidx = N_("E684: list index out of range: %ld");
9998static char *e_undefvar = N_("E121: Undefined variable: %s");
@@ -6811,6 +6810,7 @@ list_join(gap, l, sep, echo_style, copyID)
68116810garbage_collect()
68126811{
68136812 int copyID;
6813+ int abort = FALSE;
68146814 buf_T *buf;
68156815 win_T *wp;
68166816 int i;
@@ -6841,82 +6841,95 @@ garbage_collect()
68416841 * the item is referenced elsewhere the funccal must not be freed. */
68426842 for (fc = previous_funccal; fc != NULL; fc = fc->caller)
68436843 {
6844- set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1);
6845- set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1);
6844+ abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1,
6845+ NULL);
6846+ abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1,
6847+ NULL);
68466848 }
68476849
68486850 /* script-local variables */
68496851 for (i = 1; i <= ga_scripts.ga_len; ++i)
6850- set_ref_in_ht(&SCRIPT_VARS(i), copyID);
6852+ abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL );
68516853
68526854 /* buffer-local variables */
68536855 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
6854- set_ref_in_item(&buf->b_bufvar.di_tv, copyID);
6856+ abort = abort || set_ref_in_item(&buf->b_bufvar.di_tv, copyID,
6857+ NULL, NULL);
68556858
68566859 /* window-local variables */
68576860 FOR_ALL_TAB_WINDOWS(tp, wp)
6858- set_ref_in_item(&wp->w_winvar.di_tv, copyID);
6861+ abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID,
6862+ NULL, NULL);
68596863#ifdef FEAT_AUTOCMD
68606864 if (aucmd_win != NULL)
6861- set_ref_in_item(&aucmd_win->w_winvar.di_tv, copyID);
6865+ abort = abort || set_ref_in_item(&aucmd_win->w_winvar.di_tv, copyID,
6866+ NULL, NULL);
68626867#endif
68636868
68646869#ifdef FEAT_WINDOWS
68656870 /* tabpage-local variables */
68666871 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
6867- set_ref_in_item(&tp->tp_winvar.di_tv, copyID);
6872+ abort = abort || set_ref_in_item(&tp->tp_winvar.di_tv, copyID,
6873+ NULL, NULL);
68686874#endif
68696875
68706876 /* global variables */
6871- set_ref_in_ht(&globvarht, copyID);
6877+ abort = abort || set_ref_in_ht(&globvarht, copyID, NULL );
68726878
68736879 /* function-local variables */
68746880 for (fc = current_funccal; fc != NULL; fc = fc->caller)
68756881 {
6876- set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID);
6877- set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID);
6882+ abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL );
6883+ abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL );
68786884 }
68796885
68806886 /* v: vars */
6881- set_ref_in_ht(&vimvarht, copyID);
6887+ abort = abort || set_ref_in_ht(&vimvarht, copyID, NULL );
68826888
68836889#ifdef FEAT_LUA
6884- set_ref_in_lua(copyID);
6890+ abort = abort || set_ref_in_lua(copyID);
68856891#endif
68866892
68876893#ifdef FEAT_PYTHON
6888- set_ref_in_python(copyID);
6894+ abort = abort || set_ref_in_python(copyID);
68896895#endif
68906896
68916897#ifdef FEAT_PYTHON3
6892- set_ref_in_python3(copyID);
6898+ abort = abort || set_ref_in_python3(copyID);
68936899#endif
68946900
6895- /*
6896- * 2. Free lists and dictionaries that are not referenced.
6897- */
6898- did_free = free_unref_items(copyID);
6899-
6900- /*
6901- * 3. Check if any funccal can be freed now.
6902- */
6903- for (pfc = &previous_funccal; *pfc != NULL; )
6901+ if (!abort)
69046902 {
6905- if (can_free_funccal(*pfc, copyID))
6903+ /*
6904+ * 2. Free lists and dictionaries that are not referenced.
6905+ */
6906+ did_free = free_unref_items(copyID);
6907+
6908+ /*
6909+ * 3. Check if any funccal can be freed now.
6910+ */
6911+ for (pfc = &previous_funccal; *pfc != NULL; )
69066912 {
6907- fc = *pfc;
6908- *pfc = fc->caller;
6909- free_funccal(fc, TRUE);
6910- did_free = TRUE;
6911- did_free_funccal = TRUE;
6913+ if (can_free_funccal(*pfc, copyID))
6914+ {
6915+ fc = *pfc;
6916+ *pfc = fc->caller;
6917+ free_funccal(fc, TRUE);
6918+ did_free = TRUE;
6919+ did_free_funccal = TRUE;
6920+ }
6921+ else
6922+ pfc = &(*pfc)->caller;
69126923 }
6913- else
6914- pfc = &(*pfc)->caller;
6924+ if (did_free_funccal)
6925+ /* When a funccal was freed some more items might be garbage
6926+ * collected, so run again. */
6927+ (void)garbage_collect();
6928+ }
6929+ else if (p_verbose > 0)
6930+ {
6931+ verb_msg((char_u *)_("Not enough memory to set references, garbage collection aborted!"));
69156932 }
6916- if (did_free_funccal)
6917- /* When a funccal was freed some more items might be garbage
6918- * collected, so run again. */
6919- (void)garbage_collect();
69206933
69216934 return did_free;
69226935}
@@ -6976,48 +6989,112 @@ free_unref_items(copyID)
69766989
69776990/*
69786991 * Mark all lists and dicts referenced through hashtab "ht" with "copyID".
6992+ * "list_stack" is used to add lists to be marked. Can be NULL.
6993+ *
6994+ * Returns TRUE if setting references failed somehow.
69796995 */
6980- void
6981- set_ref_in_ht(ht, copyID)
6982- hashtab_T *ht;
6983- int copyID;
6996+ int
6997+ set_ref_in_ht(ht, copyID, list_stack)
6998+ hashtab_T *ht;
6999+ int copyID;
7000+ list_stack_T **list_stack;
69847001{
69857002 int todo;
7003+ int abort = FALSE;
69867004 hashitem_T *hi;
7005+ hashtab_T *cur_ht;
7006+ ht_stack_T *ht_stack = NULL;
7007+ ht_stack_T *tempitem;
69877008
6988- todo = (int)ht->ht_used;
6989- for (hi = ht->ht_array; todo > 0; ++hi)
6990- if (!HASHITEM_EMPTY(hi))
7009+ cur_ht = ht;
7010+ for (;;)
7011+ {
7012+ if (!abort)
69917013 {
6992- --todo;
6993- set_ref_in_item(&HI2DI(hi)->di_tv, copyID);
7014+ /* Mark each item in the hashtab. If the item contains a hashtab
7015+ * it is added to ht_stack, if it contains a list it is added to
7016+ * list_stack. */
7017+ todo = (int)cur_ht->ht_used;
7018+ for (hi = cur_ht->ht_array; todo > 0; ++hi)
7019+ if (!HASHITEM_EMPTY(hi))
7020+ {
7021+ --todo;
7022+ abort = abort || set_ref_in_item(&HI2DI(hi)->di_tv, copyID,
7023+ &ht_stack, list_stack);
7024+ }
69947025 }
7026+
7027+ if (ht_stack == NULL)
7028+ break;
7029+
7030+ /* take an item from the stack */
7031+ cur_ht = ht_stack->ht;
7032+ tempitem = ht_stack;
7033+ ht_stack = ht_stack->prev;
7034+ free(tempitem);
7035+ }
7036+
7037+ return abort;
69957038}
69967039
69977040/*
69987041 * Mark all lists and dicts referenced through list "l" with "copyID".
7042+ * "ht_stack" is used to add hashtabs to be marked. Can be NULL.
7043+ *
7044+ * Returns TRUE if setting references failed somehow.
69997045 */
7000- void
7001- set_ref_in_list(l, copyID)
7046+ int
7047+ set_ref_in_list(l, copyID, ht_stack )
70027048 list_T *l;
70037049 int copyID;
7050+ ht_stack_T **ht_stack;
70047051{
7005- listitem_T *li;
7052+ listitem_T *li;
7053+ int abort = FALSE;
7054+ list_T *cur_l;
7055+ list_stack_T *list_stack = NULL;
7056+ list_stack_T *tempitem;
70067057
7007- for (li = l->lv_first; li != NULL; li = li->li_next)
7008- set_ref_in_item(&li->li_tv, copyID);
7058+ cur_l = l;
7059+ for (;;)
7060+ {
7061+ if (!abort)
7062+ /* Mark each item in the list. If the item contains a hashtab
7063+ * it is added to ht_stack, if it contains a list it is added to
7064+ * list_stack. */
7065+ for (li = cur_l->lv_first; !abort && li != NULL; li = li->li_next)
7066+ abort = abort || set_ref_in_item(&li->li_tv, copyID,
7067+ ht_stack, &list_stack);
7068+ if (list_stack == NULL)
7069+ break;
7070+
7071+ /* take an item from the stack */
7072+ cur_l = list_stack->list;
7073+ tempitem = list_stack;
7074+ list_stack = list_stack->prev;
7075+ free(tempitem);
7076+ }
7077+
7078+ return abort;
70097079}
70107080
70117081/*
70127082 * Mark all lists and dicts referenced through typval "tv" with "copyID".
7083+ * "list_stack" is used to add lists to be marked. Can be NULL.
7084+ * "ht_stack" is used to add hashtabs to be marked. Can be NULL.
7085+ *
7086+ * Returns TRUE if setting references failed somehow.
70137087 */
7014- void
7015- set_ref_in_item(tv, copyID)
7016- typval_T *tv;
7017- int copyID;
7088+ int
7089+ set_ref_in_item(tv, copyID, ht_stack, list_stack)
7090+ typval_T *tv;
7091+ int copyID;
7092+ ht_stack_T **ht_stack;
7093+ list_stack_T **list_stack;
70187094{
70197095 dict_T *dd;
70207096 list_T *ll;
7097+ int abort = FALSE;
70217098
70227099 switch (tv->v_type)
70237100 {
@@ -7027,7 +7104,23 @@ set_ref_in_item(tv, copyID)
70277104 {
70287105 /* Didn't see this dict yet. */
70297106 dd->dv_copyID = copyID;
7030- set_ref_in_ht(&dd->dv_hashtab, copyID);
7107+ if (ht_stack == NULL)
7108+ {
7109+ abort = set_ref_in_ht(&dd->dv_hashtab, copyID, list_stack);
7110+ }
7111+ else
7112+ {
7113+ ht_stack_T *newitem = (ht_stack_T*)malloc(
7114+ sizeof(ht_stack_T));
7115+ if (newitem == NULL)
7116+ abort = TRUE;
7117+ else
7118+ {
7119+ newitem->ht = &dd->dv_hashtab;
7120+ newitem->prev = *ht_stack;
7121+ *ht_stack = newitem;
7122+ }
7123+ }
70317124 }
70327125 break;
70337126
@@ -7037,11 +7130,27 @@ set_ref_in_item(tv, copyID)
70377130 {
70387131 /* Didn't see this list yet. */
70397132 ll->lv_copyID = copyID;
7040- set_ref_in_list(ll, copyID);
7133+ if (list_stack == NULL)
7134+ {
7135+ abort = set_ref_in_list(ll, copyID, ht_stack);
7136+ }
7137+ else
7138+ {
7139+ list_stack_T *newitem = (list_stack_T*)malloc(
7140+ sizeof(list_stack_T));
7141+ if (newitem == NULL)
7142+ abort = TRUE;
7143+ else
7144+ {
7145+ newitem->list = ll;
7146+ newitem->prev = *list_stack;
7147+ *list_stack = newitem;
7148+ }
7149+ }
70417150 }
70427151 break;
70437152 }
7044- return;
7153+ return abort ;
70457154}
70467155
70477156/*
0 commit comments