Mercurial > vim
comparison src/vim9execute.c @ 19532:b8f778dda1a1 v8.2.0323
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.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Wed, 26 Feb 2020 21:30:04 +0100 |
parents | 3b026343f398 |
children | 7df9c8df26f1 |
comparison
equal
deleted
inserted
replaced
19531:d984a63f23df | 19532:b8f778dda1a1 |
---|---|
265 return OK; | 265 return OK; |
266 } | 266 } |
267 | 267 |
268 /* | 268 /* |
269 * Execute a user defined function. | 269 * Execute a user defined function. |
270 * "iptr" can be used to replace the instruction with a more efficient one. | |
270 */ | 271 */ |
271 static int | 272 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) |
273 { | 274 { |
274 typval_T argvars[MAX_FUNC_ARGS]; | 275 typval_T argvars[MAX_FUNC_ARGS]; |
275 funcexe_T funcexe; | 276 funcexe_T funcexe; |
276 int error; | 277 int error; |
277 int idx; | 278 int idx; |
278 | 279 |
279 if (ufunc->uf_dfunc_idx >= 0) | 280 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 } | |
281 return call_dfunc(ufunc->uf_dfunc_idx, argcount, ectx); | 290 return call_dfunc(ufunc->uf_dfunc_idx, argcount, ectx); |
291 } | |
282 | 292 |
283 if (call_prepare(argcount, argvars, ectx) == FAIL) | 293 if (call_prepare(argcount, argvars, ectx) == FAIL) |
284 return FAIL; | 294 return FAIL; |
285 vim_memset(&funcexe, 0, sizeof(funcexe)); | 295 vim_memset(&funcexe, 0, sizeof(funcexe)); |
286 funcexe.evaluate = TRUE; | 296 funcexe.evaluate = TRUE; |
303 } | 313 } |
304 | 314 |
305 /* | 315 /* |
306 * Execute a function by "name". | 316 * Execute a function by "name". |
307 * This can be a builtin function or a user function. | 317 * This can be a builtin function or a user function. |
318 * "iptr" can be used to replace the instruction with a more efficient one. | |
308 * Returns FAIL if not found without an error message. | 319 * Returns FAIL if not found without an error message. |
309 */ | 320 */ |
310 static int | 321 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) |
312 { | 323 { |
313 ufunc_T *ufunc; | 324 ufunc_T *ufunc; |
314 | 325 |
315 if (builtin_function(name, -1)) | 326 if (builtin_function(name, -1)) |
316 { | 327 { |
323 return call_bfunc(func_idx, argcount, ectx); | 334 return call_bfunc(func_idx, argcount, ectx); |
324 } | 335 } |
325 | 336 |
326 ufunc = find_func(name, NULL); | 337 ufunc = find_func(name, NULL); |
327 if (ufunc != NULL) | 338 if (ufunc != NULL) |
328 return call_ufunc(ufunc, argcount, ectx); | 339 return call_ufunc(ufunc, argcount, ectx, iptr); |
329 | 340 |
330 return FAIL; | 341 return FAIL; |
331 } | 342 } |
332 | 343 |
333 static int | 344 static int |
339 if (tv->v_type == VAR_PARTIAL) | 350 if (tv->v_type == VAR_PARTIAL) |
340 { | 351 { |
341 partial_T *pt = tv->vval.v_partial; | 352 partial_T *pt = tv->vval.v_partial; |
342 | 353 |
343 if (pt->pt_func != NULL) | 354 if (pt->pt_func != NULL) |
344 return call_ufunc(pt->pt_func, argcount, ectx); | 355 return call_ufunc(pt->pt_func, argcount, ectx, NULL); |
345 name = pt->pt_name; | 356 name = pt->pt_name; |
346 } | 357 } |
347 else | 358 else |
348 name = tv->vval.v_string; | 359 name = tv->vval.v_string; |
349 if (call_by_name(name, argcount, ectx) == FAIL) | 360 if (call_by_name(name, argcount, ectx, NULL) == FAIL) |
350 { | 361 { |
351 if (called_emsg == called_emsg_before) | 362 if (called_emsg == called_emsg_before) |
352 semsg(_(e_unknownfunc), name); | 363 semsg(_(e_unknownfunc), name); |
353 return FAIL; | 364 return FAIL; |
354 } | 365 } |
370 } | 381 } |
371 | 382 |
372 /* | 383 /* |
373 * Execute a function by "name". | 384 * Execute a function by "name". |
374 * This can be a builtin function, user function or a funcref. | 385 * 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. | |
375 */ | 387 */ |
376 static int | 388 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) |
378 { | 390 { |
379 int called_emsg_before = called_emsg; | 391 int called_emsg_before = called_emsg; |
380 | 392 |
381 if (call_by_name(name, argcount, ectx) == FAIL | 393 if (call_by_name(name, argcount, ectx, iptr) == FAIL |
382 && called_emsg == called_emsg_before) | 394 && called_emsg == called_emsg_before) |
383 { | 395 { |
384 // "name" may be a variable that is a funcref or partial | 396 // "name" may be a variable that is a funcref or partial |
385 // if find variable | 397 // if find variable |
386 // call_partial() | 398 // call_partial() |
981 { | 993 { |
982 cufunc_T *cufunc = &iptr->isn_arg.ufunc; | 994 cufunc_T *cufunc = &iptr->isn_arg.ufunc; |
983 | 995 |
984 SOURCING_LNUM = iptr->isn_lnum; | 996 SOURCING_LNUM = iptr->isn_lnum; |
985 if (call_eval_func(cufunc->cuf_name, | 997 if (call_eval_func(cufunc->cuf_name, |
986 cufunc->cuf_argcount, &ectx) == FAIL) | 998 cufunc->cuf_argcount, &ectx, iptr) == FAIL) |
987 goto failed; | 999 goto failed; |
988 } | 1000 } |
989 break; | 1001 break; |
990 | 1002 |
991 // return from a :def function call | 1003 // return from a :def function call |
1556 { | 1568 { |
1557 int error = FALSE; | 1569 int error = FALSE; |
1558 | 1570 |
1559 tv = STACK_TV_BOT(-1); | 1571 tv = STACK_TV_BOT(-1); |
1560 if (check_not_string(tv) == FAIL) | 1572 if (check_not_string(tv) == FAIL) |
1561 { | 1573 goto failed; |
1562 --ectx.ec_stack.ga_len; | |
1563 goto failed; | |
1564 } | |
1565 (void)tv_get_number_chk(tv, &error); | 1574 (void)tv_get_number_chk(tv, &error); |
1566 if (error) | 1575 if (error) |
1567 goto failed; | 1576 goto failed; |
1568 } | 1577 } |
1569 break; | 1578 break; |
1625 *rettv = *tv; | 1634 *rettv = *tv; |
1626 tv->v_type = VAR_UNKNOWN; | 1635 tv->v_type = VAR_UNKNOWN; |
1627 ret = OK; | 1636 ret = OK; |
1628 | 1637 |
1629 failed: | 1638 failed: |
1639 // When failed need to unwind the call stack. | |
1640 while (ectx.ec_frame != initial_frame_ptr) | |
1641 func_return(&ectx); | |
1642 | |
1630 for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx) | 1643 for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx) |
1631 clear_tv(STACK_TV(idx)); | 1644 clear_tv(STACK_TV(idx)); |
1632 vim_free(ectx.ec_stack.ga_data); | 1645 vim_free(ectx.ec_stack.ga_data); |
1633 return ret; | 1646 return ret; |
1634 } | 1647 } |