@@ -65,7 +65,7 @@ static int
6565# endif
6666 prof_self_cmp (const void * s1 , const void * s2 );
6767#endif
68- static void funccal_unref (funccall_T * fc , ufunc_T * fp );
68+ static void funccal_unref (funccall_T * fc , ufunc_T * fp , int force );
6969
7070 void
7171func_init ()
@@ -182,10 +182,9 @@ register_closure(ufunc_T *fp)
182182 if (fp -> uf_scoped == current_funccal )
183183 /* no change */
184184 return OK ;
185- funccal_unref (fp -> uf_scoped , fp );
185+ funccal_unref (fp -> uf_scoped , fp , FALSE );
186186 fp -> uf_scoped = current_funccal ;
187187 current_funccal -> fc_refcount ++ ;
188- func_ptr_ref (current_funccal -> func );
189188
190189 if (ga_grow (& current_funccal -> fc_funcs , 1 ) == FAIL )
191190 return FAIL ;
@@ -603,14 +602,12 @@ free_funccal(
603602 {
604603 ufunc_T * fp = ((ufunc_T * * )(fc -> fc_funcs .ga_data ))[i ];
605604
606- if (fp != NULL )
607- {
608- /* Function may have been redefined and point to another
609- * funccall_T, don't clear it then. */
610- if (fp -> uf_scoped == fc )
611- fp -> uf_scoped = NULL ;
612- func_ptr_unref (fc -> func );
613- }
605+ /* When garbage collecting a funccall_T may be freed before the
606+ * function that references it, clear its uf_scoped field.
607+ * The function may have been redefined and point to another
608+ * funccall_T, don't clear it then. */
609+ if (fp != NULL && fp -> uf_scoped == fc )
610+ fp -> uf_scoped = NULL ;
614611 }
615612 ga_clear (& fc -> fc_funcs );
616613
@@ -1030,20 +1027,21 @@ call_user_func(
10301027/*
10311028 * Unreference "fc": decrement the reference count and free it when it
10321029 * becomes zero. "fp" is detached from "fc".
1030+ * When "force" is TRUE we are exiting.
10331031 */
10341032 static void
1035- funccal_unref (funccall_T * fc , ufunc_T * fp )
1033+ funccal_unref (funccall_T * fc , ufunc_T * fp , int force )
10361034{
10371035 funccall_T * * pfc ;
10381036 int i ;
10391037
10401038 if (fc == NULL )
10411039 return ;
10421040
1043- if (-- fc -> fc_refcount <= 0
1044- && fc -> l_varlist .lv_refcount == DO_NOT_FREE_CNT
1041+ if (-- fc -> fc_refcount <= 0 && ( force || (
1042+ fc -> l_varlist .lv_refcount == DO_NOT_FREE_CNT
10451043 && fc -> l_vars .dv_refcount == DO_NOT_FREE_CNT
1046- && fc -> l_avars .dv_refcount == DO_NOT_FREE_CNT )
1044+ && fc -> l_avars .dv_refcount == DO_NOT_FREE_CNT )))
10471045 for (pfc = & previous_funccal ; * pfc != NULL ; pfc = & (* pfc )-> caller )
10481046 {
10491047 if (fc == * pfc )
@@ -1054,13 +1052,8 @@ funccal_unref(funccall_T *fc, ufunc_T *fp)
10541052 }
10551053 }
10561054 for (i = 0 ; i < fc -> fc_funcs .ga_len ; ++ i )
1057- {
10581055 if (((ufunc_T * * )(fc -> fc_funcs .ga_data ))[i ] == fp )
1059- {
1060- func_ptr_unref (fc -> func );
10611056 ((ufunc_T * * )(fc -> fc_funcs .ga_data ))[i ] = NULL ;
1062- }
1063- }
10641057}
10651058
10661059/*
@@ -1083,9 +1076,10 @@ func_remove(ufunc_T *fp)
10831076
10841077/*
10851078 * Free a function and remove it from the list of functions.
1079+ * When "force" is TRUE we are exiting.
10861080 */
10871081 static void
1088- func_free (ufunc_T * fp )
1082+ func_free (ufunc_T * fp , int force )
10891083{
10901084 /* clear this function */
10911085 ga_clear_strings (& (fp -> uf_args ));
@@ -1100,7 +1094,7 @@ func_free(ufunc_T *fp)
11001094 if ((fp -> uf_flags & (FC_DELETED | FC_REMOVED )) == 0 )
11011095 func_remove (fp );
11021096
1103- funccal_unref (fp -> uf_scoped , fp );
1097+ funccal_unref (fp -> uf_scoped , fp , force );
11041098
11051099 vim_free (fp );
11061100}
@@ -1117,7 +1111,7 @@ free_all_functions(void)
11171111 for (hi = func_hashtab .ht_array ; ; ++ hi )
11181112 if (!HASHITEM_EMPTY (hi ))
11191113 {
1120- func_free (HI2UF (hi ));
1114+ func_free (HI2UF (hi ), TRUE );
11211115 break ;
11221116 }
11231117 hash_clear (& func_hashtab );
@@ -1331,7 +1325,7 @@ call_func(
13311325 if (-- fp -> uf_calls <= 0 && fp -> uf_refcount <= 0 )
13321326 /* Function was unreferenced while being used, free it
13331327 * now. */
1334- func_free (fp );
1328+ func_free (fp , FALSE );
13351329 if (did_save_redo )
13361330 restoreRedobuff ();
13371331 restore_search_patterns ();
@@ -1674,6 +1668,20 @@ trans_function_name(
16741668 return name ;
16751669}
16761670
1671+ /*
1672+ * There are two kinds of function names:
1673+ * 1. ordinary names, function defined with :function
1674+ * 2. numbered functions and lambdas
1675+ * For the first we only count the name stored in func_hashtab as a reference,
1676+ * using function() does not count as a reference, because the function is
1677+ * looked up by name.
1678+ */
1679+ static int
1680+ func_name_refcount (char_u * name )
1681+ {
1682+ return isdigit (* name ) || * name == '<' ;
1683+ }
1684+
16771685/*
16781686 * ":function"
16791687 */
@@ -1721,7 +1729,7 @@ ex_function(exarg_T *eap)
17211729 {
17221730 -- todo ;
17231731 fp = HI2UF (hi );
1724- if (!isdigit ( * fp -> uf_name ))
1732+ if (!func_name_refcount ( fp -> uf_name ))
17251733 list_func_head (fp , FALSE);
17261734 }
17271735 }
@@ -2655,20 +2663,6 @@ get_user_func_name(expand_T *xp, int idx)
26552663
26562664#endif /* FEAT_CMDL_COMPL */
26572665
2658- /*
2659- * There are two kinds of function names:
2660- * 1. ordinary names, function defined with :function
2661- * 2. numbered functions and lambdas
2662- * For the first we only count the name stored in func_hashtab as a reference,
2663- * using function() does not count as a reference, because the function is
2664- * looked up by name.
2665- */
2666- static int
2667- func_name_refcount (char_u * name )
2668- {
2669- return isdigit (* name ) || * name == '<' ;
2670- }
2671-
26722666/*
26732667 * ":delfunction {name}"
26742668 */
@@ -2738,7 +2732,7 @@ ex_delfunction(exarg_T *eap)
27382732 fp -> uf_flags |= FC_DELETED ;
27392733 }
27402734 else
2741- func_free (fp );
2735+ func_free (fp , FALSE );
27422736 }
27432737 }
27442738}
@@ -2767,7 +2761,7 @@ func_unref(char_u *name)
27672761 /* Only delete it when it's not being used. Otherwise it's done
27682762 * when "uf_calls" becomes zero. */
27692763 if (fp -> uf_calls == 0 )
2770- func_free (fp );
2764+ func_free (fp , FALSE );
27712765 }
27722766}
27732767
@@ -2783,7 +2777,7 @@ func_ptr_unref(ufunc_T *fp)
27832777 /* Only delete it when it's not being used. Otherwise it's done
27842778 * when "uf_calls" becomes zero. */
27852779 if (fp -> uf_calls == 0 )
2786- func_free (fp );
2780+ func_free (fp , FALSE );
27872781 }
27882782}
27892783
@@ -3676,6 +3670,21 @@ set_ref_in_previous_funccal(int copyID)
36763670 return abort ;
36773671}
36783672
3673+ static int
3674+ set_ref_in_funccal (funccall_T * fc , int copyID )
3675+ {
3676+ int abort = FALSE;
3677+
3678+ if (fc -> fc_copyID != copyID )
3679+ {
3680+ fc -> fc_copyID = copyID ;
3681+ abort = abort || set_ref_in_ht (& fc -> l_vars .dv_hashtab , copyID , NULL );
3682+ abort = abort || set_ref_in_ht (& fc -> l_avars .dv_hashtab , copyID , NULL );
3683+ abort = abort || set_ref_in_func (NULL , fc -> func , copyID );
3684+ }
3685+ return abort ;
3686+ }
3687+
36793688/*
36803689 * Set "copyID" in all local vars and arguments in the call stack.
36813690 */
@@ -3686,10 +3695,31 @@ set_ref_in_call_stack(int copyID)
36863695 funccall_T * fc ;
36873696
36883697 for (fc = current_funccal ; fc != NULL ; fc = fc -> caller )
3698+ abort = abort || set_ref_in_funccal (fc , copyID );
3699+ return abort ;
3700+ }
3701+
3702+ /*
3703+ * Set "copyID" in all functions available by name.
3704+ */
3705+ int
3706+ set_ref_in_functions (int copyID )
3707+ {
3708+ int todo ;
3709+ hashitem_T * hi = NULL ;
3710+ int abort = FALSE;
3711+ ufunc_T * fp ;
3712+
3713+ todo = (int )func_hashtab .ht_used ;
3714+ for (hi = func_hashtab .ht_array ; todo > 0 && !got_int ; ++ hi )
36893715 {
3690- fc -> fc_copyID = copyID ;
3691- abort = abort || set_ref_in_ht (& fc -> l_vars .dv_hashtab , copyID , NULL );
3692- abort = abort || set_ref_in_ht (& fc -> l_avars .dv_hashtab , copyID , NULL );
3716+ if (!HASHITEM_EMPTY (hi ))
3717+ {
3718+ -- todo ;
3719+ fp = HI2UF (hi );
3720+ if (!func_name_refcount (fp -> uf_name ))
3721+ abort = abort || set_ref_in_func (NULL , fp , copyID );
3722+ }
36933723 }
36943724 return abort ;
36953725}
@@ -3711,9 +3741,6 @@ set_ref_in_func_args(int copyID)
37113741
37123742/*
37133743 * Mark all lists and dicts referenced through function "name" with "copyID".
3714- * "list_stack" is used to add lists to be marked. Can be NULL.
3715- * "ht_stack" is used to add hashtabs to be marked. Can be NULL.
3716- *
37173744 * Returns TRUE if setting references failed somehow.
37183745 */
37193746 int
@@ -3725,6 +3752,7 @@ set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
37253752 char_u fname_buf [FLEN_FIXED + 1 ];
37263753 char_u * tofree = NULL ;
37273754 char_u * fname ;
3755+ int abort = FALSE;
37283756
37293757 if (name == NULL && fp_in == NULL )
37303758 return FALSE;
@@ -3737,17 +3765,10 @@ set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
37373765 if (fp != NULL )
37383766 {
37393767 for (fc = fp -> uf_scoped ; fc != NULL ; fc = fc -> func -> uf_scoped )
3740- {
3741- if (fc -> fc_copyID != copyID )
3742- {
3743- fc -> fc_copyID = copyID ;
3744- set_ref_in_ht (& fc -> l_vars .dv_hashtab , copyID , NULL );
3745- set_ref_in_ht (& fc -> l_avars .dv_hashtab , copyID , NULL );
3746- }
3747- }
3768+ abort = abort || set_ref_in_funccal (fc , copyID );
37483769 }
37493770 vim_free (tofree );
3750- return FALSE ;
3771+ return abort ;
37513772}
37523773
37533774#endif /* FEAT_EVAL */
0 commit comments