comparison src/userfunc.c @ 18991:847cc7932c42 v8.2.0056

patch 8.2.0056: execution stack is incomplete and inefficient Commit: https://github.com/vim/vim/commit/1a47ae32cdc19b0fd5a82e19fe5fddf45db1a506 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Dec 29 23:04:25 2019 +0100 patch 8.2.0056: execution stack is incomplete and inefficient Problem: Execution stack is incomplete and inefficient. Solution: Introduce a proper execution stack and use it instead of sourcing_name/sourcing_lnum. Create a string only when used.
author Bram Moolenaar <Bram@vim.org>
date Sun, 29 Dec 2019 23:15:04 +0100
parents af44ca0ddf49
children dd9ab0674eec
comparison
equal deleted inserted replaced
18990:1219ae40b086 18991:847cc7932c42
224 ((ufunc_T **)current_funccal->fc_funcs.ga_data) 224 ((ufunc_T **)current_funccal->fc_funcs.ga_data)
225 [current_funccal->fc_funcs.ga_len++] = fp; 225 [current_funccal->fc_funcs.ga_len++] = fp;
226 return OK; 226 return OK;
227 } 227 }
228 228
229 static void
230 set_ufunc_name(ufunc_T *fp, char_u *name)
231 {
232 STRCPY(fp->uf_name, name);
233
234 if (name[0] == K_SPECIAL)
235 {
236 fp->uf_name_exp = alloc(STRLEN(name) + 3);
237 if (fp->uf_name_exp != NULL)
238 {
239 STRCPY(fp->uf_name_exp, "<SNR>");
240 STRCAT(fp->uf_name_exp, fp->uf_name + 3);
241 }
242 }
243 }
244
229 /* 245 /*
230 * Parse a lambda expression and get a Funcref from "*arg". 246 * Parse a lambda expression and get a Funcref from "*arg".
231 * Return OK or FAIL. Returns NOTDONE for dict or {expr}. 247 * Return OK or FAIL. Returns NOTDONE for dict or {expr}.
232 */ 248 */
233 int 249 int
307 ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p; 323 ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
308 STRCPY(p, "return "); 324 STRCPY(p, "return ");
309 vim_strncpy(p + 7, s, e - s); 325 vim_strncpy(p + 7, s, e - s);
310 326
311 fp->uf_refcount = 1; 327 fp->uf_refcount = 1;
312 STRCPY(fp->uf_name, name); 328 set_ufunc_name(fp, name);
313 hash_add(&func_hashtab, UF2HIKEY(fp)); 329 hash_add(&func_hashtab, UF2HIKEY(fp));
314 fp->uf_args = newargs; 330 fp->uf_args = newargs;
315 ga_init(&fp->uf_def_args); 331 ga_init(&fp->uf_def_args);
316 fp->uf_lines = newlines; 332 fp->uf_lines = newlines;
317 if (current_funccal != NULL && eval_lavars) 333 if (current_funccal != NULL && eval_lavars)
331 flags |= FC_SANDBOX; 347 flags |= FC_SANDBOX;
332 fp->uf_varargs = TRUE; 348 fp->uf_varargs = TRUE;
333 fp->uf_flags = flags; 349 fp->uf_flags = flags;
334 fp->uf_calls = 0; 350 fp->uf_calls = 0;
335 fp->uf_script_ctx = current_sctx; 351 fp->uf_script_ctx = current_sctx;
336 fp->uf_script_ctx.sc_lnum += sourcing_lnum - newlines.ga_len; 352 fp->uf_script_ctx.sc_lnum += SOURCING_LNUM - newlines.ga_len;
337 353
338 pt->pt_func = fp; 354 pt->pt_func = fp;
339 pt->pt_refcount = 1; 355 pt->pt_refcount = 1;
340 rettv->vval.v_partial = pt; 356 rettv->vval.v_partial = pt;
341 rettv->v_type = VAR_PARTIAL; 357 rettv->v_type = VAR_PARTIAL;
757 typval_T *rettv, // return value 773 typval_T *rettv, // return value
758 linenr_T firstline, // first line of range 774 linenr_T firstline, // first line of range
759 linenr_T lastline, // last line of range 775 linenr_T lastline, // last line of range
760 dict_T *selfdict) // Dictionary for "self" 776 dict_T *selfdict) // Dictionary for "self"
761 { 777 {
762 char_u *save_sourcing_name;
763 linenr_T save_sourcing_lnum;
764 sctx_T save_current_sctx; 778 sctx_T save_current_sctx;
765 int using_sandbox = FALSE; 779 int using_sandbox = FALSE;
766 funccall_T *fc; 780 funccall_T *fc;
767 int save_did_emsg; 781 int save_did_emsg;
768 int default_arg_err = FALSE; 782 int default_arg_err = FALSE;
772 int i; 786 int i;
773 int ai; 787 int ai;
774 int islambda = FALSE; 788 int islambda = FALSE;
775 char_u numbuf[NUMBUFLEN]; 789 char_u numbuf[NUMBUFLEN];
776 char_u *name; 790 char_u *name;
777 size_t len;
778 #ifdef FEAT_PROFILE 791 #ifdef FEAT_PROFILE
779 proftime_T wait_start; 792 proftime_T wait_start;
780 proftime_T call_start; 793 proftime_T call_start;
781 int started_profiling = FALSE; 794 int started_profiling = FALSE;
782 #endif 795 #endif
946 } 959 }
947 } 960 }
948 961
949 // Don't redraw while executing the function. 962 // Don't redraw while executing the function.
950 ++RedrawingDisabled; 963 ++RedrawingDisabled;
951 save_sourcing_name = sourcing_name;
952 save_sourcing_lnum = sourcing_lnum;
953 sourcing_lnum = 1;
954 964
955 if (fp->uf_flags & FC_SANDBOX) 965 if (fp->uf_flags & FC_SANDBOX)
956 { 966 {
957 using_sandbox = TRUE; 967 using_sandbox = TRUE;
958 ++sandbox; 968 ++sandbox;
959 } 969 }
960 970
961 // need space for function name + ("function " + 3) or "[number]" 971 estack_push_ufunc(ETYPE_UFUNC, fp, 1);
962 len = (save_sourcing_name == NULL ? 0 : STRLEN(save_sourcing_name)) 972 if (p_verbose >= 12)
963 + STRLEN(fp->uf_name) + 20; 973 {
964 sourcing_name = alloc(len); 974 ++no_wait_return;
965 if (sourcing_name != NULL) 975 verbose_enter_scroll();
966 { 976
967 if (save_sourcing_name != NULL 977 smsg(_("calling %s"), SOURCING_NAME);
968 && STRNCMP(save_sourcing_name, "function ", 9) == 0) 978 if (p_verbose >= 14)
969 sprintf((char *)sourcing_name, "%s[%d]..", 979 {
970 save_sourcing_name, (int)save_sourcing_lnum); 980 char_u buf[MSG_BUF_LEN];
971 else 981 char_u numbuf2[NUMBUFLEN];
972 STRCPY(sourcing_name, "function "); 982 char_u *tofree;
973 cat_func_name(sourcing_name + STRLEN(sourcing_name), fp); 983 char_u *s;
974 984
975 if (p_verbose >= 12) 985 msg_puts("(");
976 { 986 for (i = 0; i < argcount; ++i)
977 ++no_wait_return; 987 {
978 verbose_enter_scroll(); 988 if (i > 0)
979 989 msg_puts(", ");
980 smsg(_("calling %s"), sourcing_name); 990 if (argvars[i].v_type == VAR_NUMBER)
981 if (p_verbose >= 14) 991 msg_outnum((long)argvars[i].vval.v_number);
982 { 992 else
983 char_u buf[MSG_BUF_LEN];
984 char_u numbuf2[NUMBUFLEN];
985 char_u *tofree;
986 char_u *s;
987
988 msg_puts("(");
989 for (i = 0; i < argcount; ++i)
990 { 993 {
991 if (i > 0) 994 // Do not want errors such as E724 here.
992 msg_puts(", "); 995 ++emsg_off;
993 if (argvars[i].v_type == VAR_NUMBER) 996 s = tv2string(&argvars[i], &tofree, numbuf2, 0);
994 msg_outnum((long)argvars[i].vval.v_number); 997 --emsg_off;
995 else 998 if (s != NULL)
996 { 999 {
997 // Do not want errors such as E724 here. 1000 if (vim_strsize(s) > MSG_BUF_CLEN)
998 ++emsg_off;
999 s = tv2string(&argvars[i], &tofree, numbuf2, 0);
1000 --emsg_off;
1001 if (s != NULL)
1002 { 1001 {
1003 if (vim_strsize(s) > MSG_BUF_CLEN) 1002 trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
1004 { 1003 s = buf;
1005 trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
1006 s = buf;
1007 }
1008 msg_puts((char *)s);
1009 vim_free(tofree);
1010 } 1004 }
1005 msg_puts((char *)s);
1006 vim_free(tofree);
1011 } 1007 }
1012 } 1008 }
1013 msg_puts(")"); 1009 }
1014 } 1010 msg_puts(")");
1015 msg_puts("\n"); // don't overwrite this either 1011 }
1016 1012 msg_puts("\n"); // don't overwrite this either
1017 verbose_leave_scroll(); 1013
1018 --no_wait_return; 1014 verbose_leave_scroll();
1019 } 1015 --no_wait_return;
1020 } 1016 }
1021 #ifdef FEAT_PROFILE 1017 #ifdef FEAT_PROFILE
1022 if (do_profiling == PROF_YES) 1018 if (do_profiling == PROF_YES)
1023 { 1019 {
1024 if (!fp->uf_profiling && has_profiling(FALSE, fp->uf_name, NULL)) 1020 if (!fp->uf_profiling && has_profiling(FALSE, fp->uf_name, NULL))
1083 { 1079 {
1084 ++no_wait_return; 1080 ++no_wait_return;
1085 verbose_enter_scroll(); 1081 verbose_enter_scroll();
1086 1082
1087 if (aborting()) 1083 if (aborting())
1088 smsg(_("%s aborted"), sourcing_name); 1084 smsg(_("%s aborted"), SOURCING_NAME);
1089 else if (fc->rettv->v_type == VAR_NUMBER) 1085 else if (fc->rettv->v_type == VAR_NUMBER)
1090 smsg(_("%s returning #%ld"), sourcing_name, 1086 smsg(_("%s returning #%ld"), SOURCING_NAME,
1091 (long)fc->rettv->vval.v_number); 1087 (long)fc->rettv->vval.v_number);
1092 else 1088 else
1093 { 1089 {
1094 char_u buf[MSG_BUF_LEN]; 1090 char_u buf[MSG_BUF_LEN];
1095 char_u numbuf2[NUMBUFLEN]; 1091 char_u numbuf2[NUMBUFLEN];
1107 if (vim_strsize(s) > MSG_BUF_CLEN) 1103 if (vim_strsize(s) > MSG_BUF_CLEN)
1108 { 1104 {
1109 trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN); 1105 trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
1110 s = buf; 1106 s = buf;
1111 } 1107 }
1112 smsg(_("%s returning %s"), sourcing_name, s); 1108 smsg(_("%s returning %s"), SOURCING_NAME, s);
1113 vim_free(tofree); 1109 vim_free(tofree);
1114 } 1110 }
1115 } 1111 }
1116 msg_puts("\n"); // don't overwrite this either 1112 msg_puts("\n"); // don't overwrite this either
1117 1113
1118 verbose_leave_scroll(); 1114 verbose_leave_scroll();
1119 --no_wait_return; 1115 --no_wait_return;
1120 } 1116 }
1121 1117
1122 vim_free(sourcing_name); 1118 estack_pop();
1123 sourcing_name = save_sourcing_name;
1124 sourcing_lnum = save_sourcing_lnum;
1125 current_sctx = save_current_sctx; 1119 current_sctx = save_current_sctx;
1126 #ifdef FEAT_PROFILE 1120 #ifdef FEAT_PROFILE
1127 if (do_profiling == PROF_YES) 1121 if (do_profiling == PROF_YES)
1128 script_prof_restore(&wait_start); 1122 script_prof_restore(&wait_start);
1129 #endif 1123 #endif
1130 if (using_sandbox) 1124 if (using_sandbox)
1131 --sandbox; 1125 --sandbox;
1132 1126
1133 if (p_verbose >= 12 && sourcing_name != NULL) 1127 if (p_verbose >= 12 && SOURCING_NAME != NULL)
1134 { 1128 {
1135 ++no_wait_return; 1129 ++no_wait_return;
1136 verbose_enter_scroll(); 1130 verbose_enter_scroll();
1137 1131
1138 smsg(_("continuing in %s"), sourcing_name); 1132 smsg(_("continuing in %s"), SOURCING_NAME);
1139 msg_puts("\n"); // don't overwrite this either 1133 msg_puts("\n"); // don't overwrite this either
1140 1134
1141 verbose_leave_scroll(); 1135 verbose_leave_scroll();
1142 --no_wait_return; 1136 --no_wait_return;
1143 } 1137 }
1202 func_clear_items(ufunc_T *fp) 1196 func_clear_items(ufunc_T *fp)
1203 { 1197 {
1204 ga_clear_strings(&(fp->uf_args)); 1198 ga_clear_strings(&(fp->uf_args));
1205 ga_clear_strings(&(fp->uf_def_args)); 1199 ga_clear_strings(&(fp->uf_def_args));
1206 ga_clear_strings(&(fp->uf_lines)); 1200 ga_clear_strings(&(fp->uf_lines));
1201 VIM_CLEAR(fp->uf_name_exp);
1207 #ifdef FEAT_PROFILE 1202 #ifdef FEAT_PROFILE
1208 vim_free(fp->uf_tml_count); 1203 VIM_CLEAR(fp->uf_tml_count);
1209 fp->uf_tml_count = NULL; 1204 VIM_CLEAR(fp->uf_tml_total);
1210 vim_free(fp->uf_tml_total); 1205 VIM_CLEAR(fp->uf_tml_self);
1211 fp->uf_tml_total = NULL;
1212 vim_free(fp->uf_tml_self);
1213 fp->uf_tml_self = NULL;
1214 #endif 1206 #endif
1215 } 1207 }
1216 1208
1217 /* 1209 /*
1218 * Free all things that a function contains. Does not free the function 1210 * Free all things that a function contains. Does not free the function
1734 1726
1735 msg_start(); 1727 msg_start();
1736 if (indent) 1728 if (indent)
1737 msg_puts(" "); 1729 msg_puts(" ");
1738 msg_puts("function "); 1730 msg_puts("function ");
1739 if (fp->uf_name[0] == K_SPECIAL) 1731 if (fp->uf_name_exp != NULL)
1740 { 1732 msg_puts((char *)fp->uf_name_exp);
1741 msg_puts_attr("<SNR>", HL_ATTR(HLF_8));
1742 msg_puts((char *)fp->uf_name + 3);
1743 }
1744 else 1733 else
1745 msg_puts((char *)fp->uf_name); 1734 msg_puts((char *)fp->uf_name);
1746 msg_putchar('('); 1735 msg_putchar('(');
1747 for (j = 0; j < fp->uf_args.ga_len; ++j) 1736 for (j = 0; j < fp->uf_args.ga_len; ++j)
1748 { 1737 {
2306 msg_putchar('\n'); // don't overwrite the function name 2295 msg_putchar('\n'); // don't overwrite the function name
2307 cmdline_row = msg_row; 2296 cmdline_row = msg_row;
2308 } 2297 }
2309 2298
2310 // Save the starting line number. 2299 // Save the starting line number.
2311 sourcing_lnum_top = sourcing_lnum; 2300 sourcing_lnum_top = SOURCING_LNUM;
2312 2301
2313 indent = 2; 2302 indent = 2;
2314 nesting = 0; 2303 nesting = 0;
2315 for (;;) 2304 for (;;)
2316 { 2305 {
2349 { 2338 {
2350 emsg(_("E126: Missing :endfunction")); 2339 emsg(_("E126: Missing :endfunction"));
2351 goto erret; 2340 goto erret;
2352 } 2341 }
2353 2342
2354 // Detect line continuation: sourcing_lnum increased more than one. 2343 // Detect line continuation: SOURCING_LNUM increased more than one.
2355 sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie); 2344 sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie);
2356 if (sourcing_lnum < sourcing_lnum_off) 2345 if (SOURCING_LNUM < sourcing_lnum_off)
2357 sourcing_lnum_off -= sourcing_lnum; 2346 sourcing_lnum_off -= SOURCING_LNUM;
2358 else 2347 else
2359 sourcing_lnum_off = 0; 2348 sourcing_lnum_off = 0;
2360 2349
2361 if (skip_until != NULL) 2350 if (skip_until != NULL)
2362 { 2351 {
2629 int slen, plen; 2618 int slen, plen;
2630 char_u *scriptname; 2619 char_u *scriptname;
2631 2620
2632 // Check that the autoload name matches the script name. 2621 // Check that the autoload name matches the script name.
2633 j = FAIL; 2622 j = FAIL;
2634 if (sourcing_name != NULL) 2623 if (SOURCING_NAME != NULL)
2635 { 2624 {
2636 scriptname = autoload_name(name); 2625 scriptname = autoload_name(name);
2637 if (scriptname != NULL) 2626 if (scriptname != NULL)
2638 { 2627 {
2639 p = vim_strchr(scriptname, '/'); 2628 p = vim_strchr(scriptname, '/');
2640 plen = (int)STRLEN(p); 2629 plen = (int)STRLEN(p);
2641 slen = (int)STRLEN(sourcing_name); 2630 slen = (int)STRLEN(SOURCING_NAME);
2642 if (slen > plen && fnamecmp(p, 2631 if (slen > plen && fnamecmp(p,
2643 sourcing_name + slen - plen) == 0) 2632 SOURCING_NAME + slen - plen) == 0)
2644 j = OK; 2633 j = OK;
2645 vim_free(scriptname); 2634 vim_free(scriptname);
2646 } 2635 }
2647 } 2636 }
2648 if (j == FAIL) 2637 if (j == FAIL)
2683 // behave like "dict" was used 2672 // behave like "dict" was used
2684 flags |= FC_DICT; 2673 flags |= FC_DICT;
2685 } 2674 }
2686 2675
2687 // insert the new function in the function list 2676 // insert the new function in the function list
2688 STRCPY(fp->uf_name, name); 2677 set_ufunc_name(fp, name);
2689 if (overwrite) 2678 if (overwrite)
2690 { 2679 {
2691 hi = hash_find(&func_hashtab, name); 2680 hi = hash_find(&func_hashtab, name);
2692 hi->hi_key = UF2HIKEY(fp); 2681 hi->hi_key = UF2HIKEY(fp);
2693 } 2682 }
3351 3340
3352 // If breakpoints have been added/deleted need to check for it. 3341 // If breakpoints have been added/deleted need to check for it.
3353 if (fcp->dbg_tick != debug_tick) 3342 if (fcp->dbg_tick != debug_tick)
3354 { 3343 {
3355 fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, 3344 fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
3356 sourcing_lnum); 3345 SOURCING_LNUM);
3357 fcp->dbg_tick = debug_tick; 3346 fcp->dbg_tick = debug_tick;
3358 } 3347 }
3359 #ifdef FEAT_PROFILE 3348 #ifdef FEAT_PROFILE
3360 if (do_profiling == PROF_YES) 3349 if (do_profiling == PROF_YES)
3361 func_line_end(cookie); 3350 func_line_end(cookie);
3374 if (fcp->linenr >= gap->ga_len) 3363 if (fcp->linenr >= gap->ga_len)
3375 retval = NULL; 3364 retval = NULL;
3376 else 3365 else
3377 { 3366 {
3378 retval = vim_strsave(((char_u **)(gap->ga_data))[fcp->linenr++]); 3367 retval = vim_strsave(((char_u **)(gap->ga_data))[fcp->linenr++]);
3379 sourcing_lnum = fcp->linenr; 3368 SOURCING_LNUM = fcp->linenr;
3380 #ifdef FEAT_PROFILE 3369 #ifdef FEAT_PROFILE
3381 if (do_profiling == PROF_YES) 3370 if (do_profiling == PROF_YES)
3382 func_line_start(cookie); 3371 func_line_start(cookie);
3383 #endif 3372 #endif
3384 } 3373 }
3385 } 3374 }
3386 3375
3387 // Did we encounter a breakpoint? 3376 // Did we encounter a breakpoint?
3388 if (fcp->breakpoint != 0 && fcp->breakpoint <= sourcing_lnum) 3377 if (fcp->breakpoint != 0 && fcp->breakpoint <= SOURCING_LNUM)
3389 { 3378 {
3390 dbg_breakpoint(fp->uf_name, sourcing_lnum); 3379 dbg_breakpoint(fp->uf_name, SOURCING_LNUM);
3391 // Find next breakpoint. 3380 // Find next breakpoint.
3392 fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, 3381 fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
3393 sourcing_lnum); 3382 SOURCING_LNUM);
3394 fcp->dbg_tick = debug_tick; 3383 fcp->dbg_tick = debug_tick;
3395 } 3384 }
3396 3385
3397 return retval; 3386 return retval;
3398 } 3387 }