• R/O
  • SSH

vim: 提交

Mirror of the Vim source from https://github.com/vim/vim


Commit MetaInfo

修訂b8f778dda1a13342c57a4b304425ab1dbce99805 (tree)
時間2020-02-27 05:30:04
作者Bram Moolenaar <Bram@vim....>
CommiterBram Moolenaar

Log Message

patch 8.2.0323: Vim9: calling a function that is defined later is slow

Commit: https://github.com/vim/vim/commit/7eeefd4a395fe3d7c7a2a0879467cf7ed4c29fe6
Author: Bram Moolenaar <Bram@vim.org>
Date: Wed Feb 26 21:24:23 2020 +0100

patch 8.2.0323: Vim9: calling a function that is defined later is slow
Problem: Vim9: calling a function that is defined later is slow.
Solution: Once the function is found update the instruction so it can be
called directly.

Change Summary

差異

diff -r d984a63f23df -r b8f778dda1a1 src/testdir/test_vim9_disassemble.vim
--- a/src/testdir/test_vim9_disassemble.vim Wed Feb 26 20:30:10 2020 +0100
+++ b/src/testdir/test_vim9_disassemble.vim Wed Feb 26 21:30:04 2020 +0100
@@ -222,6 +222,38 @@
222222 enddef
223223
224224
225+def FuncWithForwardCall(): string
226+ return DefinedLater("yes")
227+enddef
228+
229+def DefinedLater(arg: string): string
230+ return arg
231+enddef
232+
233+def Test_disassemble_update_instr()
234+ let res = execute('disass FuncWithForwardCall')
235+ assert_match('FuncWithForwardCall.*'
236+ \ .. 'return DefinedLater("yes").*'
237+ \ .. '\d PUSHS "yes".*'
238+ \ .. '\d UCALL DefinedLater(argc 1).*'
239+ \ .. '\d CHECKTYPE string stack\[-1].*'
240+ \ .. '\d RETURN.*'
241+ \, res)
242+
243+ " Calling the function will change UCALL into the faster DCALL
244+ assert_equal('yes', FuncWithForwardCall())
245+
246+ res = execute('disass FuncWithForwardCall')
247+ assert_match('FuncWithForwardCall.*'
248+ \ .. 'return DefinedLater("yes").*'
249+ \ .. '\d PUSHS "yes".*'
250+ \ .. '\d DCALL DefinedLater(argc 1).*'
251+ \ .. '\d CHECKTYPE string stack\[-1].*'
252+ \ .. '\d RETURN.*'
253+ \, res)
254+enddef
255+
256+
225257 def FuncWithDefault(arg: string = 'default'): string
226258 return arg
227259 enddef
diff -r d984a63f23df -r b8f778dda1a1 src/testdir/test_vim9_script.vim
--- a/src/testdir/test_vim9_script.vim Wed Feb 26 20:30:10 2020 +0100
+++ b/src/testdir/test_vim9_script.vim Wed Feb 26 21:30:04 2020 +0100
@@ -212,6 +212,19 @@
212212 return a:arg
213213 endfunc
214214
215+def FuncWithForwardCall()
216+ return DefinedEvenLater("yes")
217+enddef
218+
219+def DefinedEvenLater(arg: string): string
220+ return arg
221+enddef
222+
223+def Test_error_in_nested_function()
224+ " Error in called function requires unwinding the call stack.
225+ assert_fails('call FuncWithForwardCall()', 'E1029')
226+enddef
227+
215228 def Test_return_type_wrong()
216229 CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 'expected number but got string')
217230 CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected string but got number')
diff -r d984a63f23df -r b8f778dda1a1 src/version.c
--- a/src/version.c Wed Feb 26 20:30:10 2020 +0100
+++ b/src/version.c Wed Feb 26 21:30:04 2020 +0100
@@ -739,6 +739,8 @@
739739 static int included_patches[] =
740740 { /* Add new patch number below this line */
741741 /**/
742+ 323,
743+/**/
742744 322,
743745 /**/
744746 321,
diff -r d984a63f23df -r b8f778dda1a1 src/vim9execute.c
--- a/src/vim9execute.c Wed Feb 26 20:30:10 2020 +0100
+++ b/src/vim9execute.c Wed Feb 26 21:30:04 2020 +0100
@@ -267,9 +267,10 @@
267267
268268 /*
269269 * Execute a user defined function.
270+ * "iptr" can be used to replace the instruction with a more efficient one.
270271 */
271272 static int
272-call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx)
273+call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx, isn_T *iptr)
273274 {
274275 typval_T argvars[MAX_FUNC_ARGS];
275276 funcexe_T funcexe;
@@ -277,8 +278,17 @@
277278 int idx;
278279
279280 if (ufunc->uf_dfunc_idx >= 0)
280- // The function has been compiled, can call it quickly.
281+ {
282+ // The function has been compiled, can call it quickly. For a function
283+ // that was defined later: we can call it directly next time.
284+ if (iptr != NULL)
285+ {
286+ iptr->isn_type = ISN_DCALL;
287+ iptr->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx;
288+ iptr->isn_arg.dfunc.cdf_argcount = argcount;
289+ }
281290 return call_dfunc(ufunc->uf_dfunc_idx, argcount, ectx);
291+ }
282292
283293 if (call_prepare(argcount, argvars, ectx) == FAIL)
284294 return FAIL;
@@ -305,10 +315,11 @@
305315 /*
306316 * Execute a function by "name".
307317 * This can be a builtin function or a user function.
318+ * "iptr" can be used to replace the instruction with a more efficient one.
308319 * Returns FAIL if not found without an error message.
309320 */
310321 static int
311-call_by_name(char_u *name, int argcount, ectx_T *ectx)
322+call_by_name(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr)
312323 {
313324 ufunc_T *ufunc;
314325
@@ -325,7 +336,7 @@
325336
326337 ufunc = find_func(name, NULL);
327338 if (ufunc != NULL)
328- return call_ufunc(ufunc, argcount, ectx);
339+ return call_ufunc(ufunc, argcount, ectx, iptr);
329340
330341 return FAIL;
331342 }
@@ -341,12 +352,12 @@
341352 partial_T *pt = tv->vval.v_partial;
342353
343354 if (pt->pt_func != NULL)
344- return call_ufunc(pt->pt_func, argcount, ectx);
355+ return call_ufunc(pt->pt_func, argcount, ectx, NULL);
345356 name = pt->pt_name;
346357 }
347358 else
348359 name = tv->vval.v_string;
349- if (call_by_name(name, argcount, ectx) == FAIL)
360+ if (call_by_name(name, argcount, ectx, NULL) == FAIL)
350361 {
351362 if (called_emsg == called_emsg_before)
352363 semsg(_(e_unknownfunc), name);
@@ -372,13 +383,14 @@
372383 /*
373384 * Execute a function by "name".
374385 * This can be a builtin function, user function or a funcref.
386+ * "iptr" can be used to replace the instruction with a more efficient one.
375387 */
376388 static int
377-call_eval_func(char_u *name, int argcount, ectx_T *ectx)
389+call_eval_func(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr)
378390 {
379391 int called_emsg_before = called_emsg;
380392
381- if (call_by_name(name, argcount, ectx) == FAIL
393+ if (call_by_name(name, argcount, ectx, iptr) == FAIL
382394 && called_emsg == called_emsg_before)
383395 {
384396 // "name" may be a variable that is a funcref or partial
@@ -983,7 +995,7 @@
983995
984996 SOURCING_LNUM = iptr->isn_lnum;
985997 if (call_eval_func(cufunc->cuf_name,
986- cufunc->cuf_argcount, &ectx) == FAIL)
998+ cufunc->cuf_argcount, &ectx, iptr) == FAIL)
987999 goto failed;
9881000 }
9891001 break;
@@ -1558,10 +1570,7 @@
15581570
15591571 tv = STACK_TV_BOT(-1);
15601572 if (check_not_string(tv) == FAIL)
1561- {
1562- --ectx.ec_stack.ga_len;
15631573 goto failed;
1564- }
15651574 (void)tv_get_number_chk(tv, &error);
15661575 if (error)
15671576 goto failed;
@@ -1627,6 +1636,10 @@
16271636 ret = OK;
16281637
16291638 failed:
1639+ // When failed need to unwind the call stack.
1640+ while (ectx.ec_frame != initial_frame_ptr)
1641+ func_return(&ectx);
1642+
16301643 for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx)
16311644 clear_tv(STACK_TV(idx));
16321645 vim_free(ectx.ec_stack.ga_data);
Show on old repository browser