To: vim_dev@googlegroups.com Subject: Patch 8.2.2614 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2614 Problem: Vim9: function is deleted while executing. Solution: increment the call count, when more than zero do not delete the function but mark it as dead. (closes #7977) Files: src/vim9execute.c, src/userfunc.c, src/testdir/test_vim9_script.vim *** ../vim-8.2.2613/src/vim9execute.c 2021-03-14 18:38:50.016676652 +0100 --- src/vim9execute.c 2021-03-17 14:36:37.714004999 +0100 *************** *** 323,328 **** --- 323,330 ---- else ectx->ec_outer = NULL; + ++ufunc->uf_calls; + // Set execution state to the start of the called function. ectx->ec_dfunc_idx = cdf_idx; ectx->ec_instr = INSTRUCTIONS(dfunc); *************** *** 556,561 **** --- 558,566 ---- } } #endif + // TODO: when is it safe to delete the function when it is no longer used? + --dfunc->df_ufunc->uf_calls; + // execution context goes one level up entry = estack_pop(); if (entry != NULL) *************** *** 1334,1340 **** ++ectx.ec_stack.ga_len; } if (ufunc->uf_va_name != NULL) ! ++ectx.ec_stack.ga_len; // Frame pointer points to just after arguments. ectx.ec_frame_idx = ectx.ec_stack.ga_len; --- 1339,1345 ---- ++ectx.ec_stack.ga_len; } if (ufunc->uf_va_name != NULL) ! ++ectx.ec_stack.ga_len; // Frame pointer points to just after arguments. ectx.ec_frame_idx = ectx.ec_stack.ga_len; *************** *** 1407,1412 **** --- 1412,1420 ---- // Do turn errors into exceptions. suppress_errthrow = FALSE; + // Do not delete the function while executing it. + ++ufunc->uf_calls; + // When ":silent!" was used before calling then we still abort the // function. If ":silent!" is used in the function then we don't. emsg_silent_def = emsg_silent; *************** *** 3838,3843 **** --- 3846,3854 ---- estack_pop(); current_sctx = save_current_sctx; + // TODO: when is it safe to delete the function if it is no longer used? + --ufunc->uf_calls; + if (*msg_list != NULL && saved_msg_list != NULL) { msglist_T **plist = saved_msg_list; *** ../vim-8.2.2613/src/userfunc.c 2021-03-06 22:33:09.009928681 +0100 --- src/userfunc.c 2021-03-17 14:48:52.748558096 +0100 *************** *** 1359,1367 **** // function, so we can find the index when defining the function again. // Do remove it when it's a copy. if (fp->uf_def_status == UF_COMPILED && (fp->uf_flags & FC_COPY) == 0) fp->uf_flags |= FC_DEAD; ! else ! hash_remove(&func_hashtab, hi); return TRUE; } return FALSE; --- 1359,1370 ---- // function, so we can find the index when defining the function again. // Do remove it when it's a copy. if (fp->uf_def_status == UF_COMPILED && (fp->uf_flags & FC_COPY) == 0) + { fp->uf_flags |= FC_DEAD; ! return FALSE; ! } ! hash_remove(&func_hashtab, hi); ! fp->uf_flags |= FC_DELETED; return TRUE; } return FALSE; *************** *** 2134,2144 **** int changed = func_hashtab.ht_changed; fp->uf_flags |= FC_DEAD; ! func_clear(fp, TRUE); ! // When clearing a function another function can be cleared ! // as a side effect. When that happens start over. ! if (changed != func_hashtab.ht_changed) ! break; } --todo; } --- 2137,2159 ---- int changed = func_hashtab.ht_changed; fp->uf_flags |= FC_DEAD; ! ! if (fp->uf_calls > 0) ! { ! // Function is executing, don't free it but do remove ! // it from the hashtable. ! if (func_remove(fp)) ! fp->uf_refcount--; ! } ! else ! { ! func_clear(fp, TRUE); ! // When clearing a function another function can be ! // cleared as a side effect. When that happens start ! // over. ! if (changed != func_hashtab.ht_changed) ! break; ! } } --todo; } *************** *** 4251,4257 **** // do remove it from the hashtable. if (func_remove(fp)) fp->uf_refcount--; - fp->uf_flags |= FC_DELETED; } else func_clear_free(fp, FALSE); --- 4266,4271 ---- *** ../vim-8.2.2613/src/testdir/test_vim9_script.vim 2021-03-14 12:13:30.192279488 +0100 --- src/testdir/test_vim9_script.vim 2021-03-17 14:56:02.523543957 +0100 *************** *** 1561,1566 **** --- 1561,1595 ---- delete('Xreload.vim') enddef + " Define CallFunc so that the test can be compiled + command CallFunc echo 'nop' + + def Test_script_reload_from_function() + var lines =<< trim END + vim9script + + if exists('g:loaded') + finish + endif + g:loaded = 1 + delcommand CallFunc + command CallFunc Func() + def Func() + so /tmp/test.vim + g:didTheFunc = 1 + enddef + END + writefile(lines, 'XreloadFunc.vim') + source XreloadFunc.vim + CallFunc + assert_equal(1, g:didTheFunc) + + delete('XreloadFunc.vim') + delcommand CallFunc + unlet g:loaded + unlet g:didTheFunc + enddef + def Test_script_var_shadows_function() var lines =<< trim END vim9script *** ../vim-8.2.2613/src/version.c 2021-03-17 13:39:30.657050576 +0100 --- src/version.c 2021-03-17 14:30:06.690693111 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2614, /**/ -- Engineers are always delighted to share wisdom, even in areas in which they have no experience whatsoever. Their logic provides them with inherent insight into any field of expertise. This can be a problem when dealing with the illogical people who believe that knowledge can only be derived through experience. (Scott Adams - The Dilbert principle) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///