Patch 8.2.2985
Problem: Vim9: a compiled function cannot be debugged.
Solution: Add initial debugging support.
Files: src/vim9.h, src/vim9compile.c, src/proto/
vim9compile.pro,
src/vim.h, src/eval.c, src/vim9execute.c, src/userfunc.c,
src/vim9type.c, src/testdir/test_debugger.vim,
src/testdir/test_vim9_disassemble.vim
*** ../vim-8.2.2984/src/vim9.h 2021-06-06 17:02:49.753789485 +0200
--- src/vim9.h 2021-06-12 18:04:15.659477801 +0200
***************
*** 168,173 ****
--- 168,175 ----
ISN_PROF_START, // start a line for profiling
ISN_PROF_END, // end a line for profiling
+ ISN_DEBUG, // check for debug breakpoint
+
ISN_UNPACK, // unpack list into items, uses isn_arg.unpack
ISN_SHUFFLE, // move item on stack up or down
ISN_DROP, // pop stack and discard value
***************
*** 453,458 ****
--- 455,462 ----
isn_T *df_instr_prof; // like "df_instr" with profiling
int df_instr_prof_count; // size of "df_instr_prof"
#endif
+ isn_T *df_instr_debug; // like "df_instr" with debugging
+ int df_instr_debug_count; // size of "df_instr_debug"
int df_varcount; // number of local variables
int df_has_closure; // one if a closure was created
*** ../vim-8.2.2984/src/vim9compile.c 2021-06-12 18:30:51.510966898 +0200
--- src/vim9compile.c 2021-06-13 13:58:03.548742416 +0200
***************
*** 174,180 ****
char_u *ctx_line_start; // start of current line or NULL
garray_T ctx_instr; // generated instructions
! int ctx_profiling; // when TRUE generate ISN_PROF_START
garray_T ctx_locals; // currently visible local variables
int ctx_locals_count; // total number of local variables
--- 174,180 ----
char_u *ctx_line_start; // start of current line or NULL
garray_T ctx_instr; // generated instructions
! compiletype_T ctx_compile_type;
garray_T ctx_locals; // currently visible local variables
int ctx_locals_count; // total number of local variables
***************
*** 1857,1863 ****
* "profile" indicates profiling is to be done.
*/
int
! func_needs_compiling(ufunc_T *ufunc, int profile UNUSED)
{
switch (ufunc->uf_def_status)
{
--- 1857,1863 ----
* "profile" indicates profiling is to be done.
*/
int
! func_needs_compiling(ufunc_T *ufunc, compiletype_T compile_type)
{
switch (ufunc->uf_def_status)
{
***************
*** 1866,1880 ****
case UF_COMPILED:
{
- #ifdef FEAT_PROFILE
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ ufunc->uf_dfunc_idx;
! return profile ? dfunc->df_instr_prof == NULL
! : dfunc->df_instr == NULL;
! #else
! break;
! #endif
}
case UF_NOT_COMPILED:
--- 1866,1883 ----
case UF_COMPILED:
{
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ ufunc->uf_dfunc_idx;
! switch (compile_type)
! {
! case CT_NONE:
! return dfunc->df_instr == NULL;
! case CT_PROFILE:
! return dfunc->df_instr_prof == NULL;
! case CT_DEBUG:
! return dfunc->df_instr_debug == NULL;
! }
}
case UF_NOT_COMPILED:
***************
*** 1945,1953 ****
return FAIL;
}
}
! if (func_needs_compiling(ufunc, PROFILING(ufunc))
&& compile_def_function(ufunc, ufunc->uf_ret_type == NULL,
! PROFILING(ufunc), NULL) == FAIL)
return FAIL;
}
if (ufunc->uf_def_status == UF_COMPILE_ERROR)
--- 1948,1956 ----
return FAIL;
}
}
! if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
&& compile_def_function(ufunc, ufunc->uf_ret_type == NULL,
! COMPILE_TYPE(ufunc), NULL) == FAIL)
return FAIL;
}
if (ufunc->uf_def_status == UF_COMPILE_ERROR)
***************
*** 2313,2326 ****
garray_T *instr = &cctx->ctx_instr;
int idx = instr->ga_len;
! if (cctx->ctx_has_cmdmod && ((isn_T *)instr->ga_data)[idx - 1]
.isn_type == ISN_CMDMOD)
! --idx;
#ifdef FEAT_PROFILE
! if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[idx - 1]
! .isn_type == ISN_PROF_START)
! --idx;
#endif
return idx;
}
--- 2316,2343 ----
garray_T *instr = &cctx->ctx_instr;
int idx = instr->ga_len;
! while (idx > 0)
! {
! if (cctx->ctx_has_cmdmod && ((isn_T *)instr->ga_data)[idx - 1]
.isn_type == ISN_CMDMOD)
! {
! --idx;
! continue;
! }
#ifdef FEAT_PROFILE
! if (((isn_T *)instr->ga_data)[idx - 1].isn_type == ISN_PROF_START)
! {
! --idx;
! continue;
! }
#endif
+ if (((isn_T *)instr->ga_data)[idx - 1].isn_type == ISN_DEBUG)
+ {
+ --idx;
+ continue;
+ }
+ break;
+ }
return idx;
}
***************
*** 2328,2334 ****
static void
may_generate_prof_end(cctx_T *cctx, int prof_lnum)
{
! if (cctx->ctx_profiling && prof_lnum >= 0)
generate_instr(cctx, ISN_PROF_END);
}
#endif
--- 2345,2351 ----
static void
may_generate_prof_end(cctx_T *cctx, int prof_lnum)
{
! if (cctx->ctx_compile_type == CT_PROFILE && prof_lnum >= 0)
generate_instr(cctx, ISN_PROF_END);
}
#endif
***************
*** 2972,2979 ****
return FAIL;
// Need to compile any default values to get the argument types.
! if (func_needs_compiling(ufunc, PROFILING(ufunc))
! && compile_def_function(ufunc, TRUE, PROFILING(ufunc), NULL)
== FAIL)
return FAIL;
return generate_PUSHFUNC(cctx, ufunc->uf_name, ufunc->uf_func_type);
--- 2989,2996 ----
return FAIL;
// Need to compile any default values to get the argument types.
! if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
! && compile_def_function(ufunc, TRUE, COMPILE_TYPE(ufunc), NULL)
== FAIL)
return FAIL;
return generate_PUSHFUNC(cctx, ufunc->uf_name, ufunc->uf_func_type);
***************
*** 3570,3576 ****
// compile_return().
if (ufunc->uf_ret_type->tt_type == VAR_VOID)
ufunc->uf_ret_type = &t_unknown;
! compile_def_function(ufunc, FALSE, PROFILING(ufunc), cctx);
// evalarg.eval_tofree_cmdline may have a copy of the last line and "*arg"
// points into it. Point to the original line to avoid a dangling pointer.
--- 3587,3593 ----
// compile_return().
if (ufunc->uf_ret_type->tt_type == VAR_VOID)
ufunc->uf_ret_type = &t_unknown;
! compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), cctx);
// evalarg.eval_tofree_cmdline may have a copy of the last line and "*arg"
// points into it. Point to the original line to avoid a dangling pointer.
***************
*** 5566,5573 ****
}
}
! if (func_needs_compiling(ufunc, PROFILING(ufunc))
! && compile_def_function(ufunc, TRUE, PROFILING(ufunc), cctx)
== FAIL)
{
func_ptr_unref(ufunc);
--- 5583,5590 ----
}
}
! if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
! && compile_def_function(ufunc, TRUE, COMPILE_TYPE(ufunc), cctx)
== FAIL)
{
func_ptr_unref(ufunc);
***************
*** 7376,7382 ****
scope->se_u.se_if.is_if_label = -1;
#ifdef FEAT_PROFILE
! if (cctx->ctx_profiling && cctx->ctx_skip == SKIP_YES
&& skip_save != SKIP_YES)
{
// generated a profile start, need to generate a profile end, since it
--- 7393,7399 ----
scope->se_u.se_if.is_if_label = -1;
#ifdef FEAT_PROFILE
! if (cctx->ctx_compile_type == CT_PROFILE && cctx->ctx_skip == SKIP_YES
&& skip_save != SKIP_YES)
{
// generated a profile start, need to generate a profile end, since it
***************
*** 7457,7469 ****
{
cctx->ctx_skip = SKIP_UNKNOWN;
#ifdef FEAT_PROFILE
! if (cctx->ctx_profiling)
{
// the previous block was skipped, need to profile this line
generate_instr(cctx, ISN_PROF_START);
instr_count = instr->ga_len;
}
#endif
}
if (compile_expr1(&p, cctx, &ppconst) == FAIL)
{
--- 7474,7492 ----
{
cctx->ctx_skip = SKIP_UNKNOWN;
#ifdef FEAT_PROFILE
! if (cctx->ctx_compile_type == CT_PROFILE)
{
// the previous block was skipped, need to profile this line
generate_instr(cctx, ISN_PROF_START);
instr_count = instr->ga_len;
}
#endif
+ if (cctx->ctx_compile_type == CT_DEBUG)
+ {
+ // the previous block was skipped, may want to debug this line
+ generate_instr(cctx, ISN_DEBUG);
+ instr_count = instr->ga_len;
+ }
}
if (compile_expr1(&p, cctx, &ppconst) == FAIL)
{
***************
*** 7531,7542 ****
scope->se_u.se_if.is_seen_else = TRUE;
#ifdef FEAT_PROFILE
! if (cctx->ctx_profiling)
{
if (cctx->ctx_skip == SKIP_NOT
&& ((isn_T *)instr->ga_data)[instr->ga_len - 1]
.isn_type == ISN_PROF_START)
! // the previous block was executed, do not count "else" for profiling
--instr->ga_len;
if (cctx->ctx_skip == SKIP_YES && !scope->se_u.se_if.is_seen_skip_not)
{
--- 7554,7566 ----
scope->se_u.se_if.is_seen_else = TRUE;
#ifdef FEAT_PROFILE
! if (cctx->ctx_compile_type == CT_PROFILE)
{
if (cctx->ctx_skip == SKIP_NOT
&& ((isn_T *)instr->ga_data)[instr->ga_len - 1]
.isn_type == ISN_PROF_START)
! // the previous block was executed, do not count "else" for
! // profiling
--instr->ga_len;
if (cctx->ctx_skip == SKIP_YES && !scope->se_u.se_if.is_seen_skip_not)
{
***************
*** 7612,7618 ****
#ifdef FEAT_PROFILE
// even when skipping we count the endif as executed, unless the block it's
// in is skipped
! if (cctx->ctx_profiling && cctx->ctx_skip == SKIP_YES
&& scope->se_skip_save != SKIP_YES)
{
cctx->ctx_skip = SKIP_NOT;
--- 7636,7642 ----
#ifdef FEAT_PROFILE
// even when skipping we count the endif as executed, unless the block it's
// in is skipped
! if (cctx->ctx_compile_type == CT_PROFILE && cctx->ctx_skip == SKIP_YES
&& scope->se_skip_save != SKIP_YES)
{
cctx->ctx_skip = SKIP_NOT;
***************
*** 8183,8189 ****
{
#ifdef FEAT_PROFILE
// the profile-start should be after the jump
! if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
.isn_type == ISN_PROF_START)
--instr->ga_len;
#endif
--- 8207,8214 ----
{
#ifdef FEAT_PROFILE
// the profile-start should be after the jump
! if (cctx->ctx_compile_type == CT_PROFILE
! && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
.isn_type == ISN_PROF_START)
--instr->ga_len;
#endif
***************
*** 8203,8209 ****
isn->isn_arg.jump.jump_where = instr->ga_len;
}
#ifdef FEAT_PROFILE
! if (cctx->ctx_profiling)
{
// a "throw" that jumps here needs to be counted
generate_instr(cctx, ISN_PROF_END);
--- 8228,8234 ----
isn->isn_arg.jump.jump_where = instr->ga_len;
}
#ifdef FEAT_PROFILE
! if (cctx->ctx_compile_type == CT_PROFILE)
{
// a "throw" that jumps here needs to be counted
generate_instr(cctx, ISN_PROF_END);
***************
*** 8211,8216 ****
--- 8236,8243 ----
generate_instr(cctx, ISN_PROF_START);
}
#endif
+ if (cctx->ctx_compile_type == CT_DEBUG)
+ generate_instr(cctx, ISN_DEBUG);
}
p = skipwhite(arg);
***************
*** 8298,8304 ****
this_instr = instr->ga_len;
#ifdef FEAT_PROFILE
! if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
.isn_type == ISN_PROF_START)
// jump to the profile start of the "finally"
--this_instr;
--- 8325,8332 ----
this_instr = instr->ga_len;
#ifdef FEAT_PROFILE
! if (cctx->ctx_compile_type == CT_PROFILE
! && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
.isn_type == ISN_PROF_START)
// jump to the profile start of the "finally"
--this_instr;
***************
*** 8367,8373 ****
}
#ifdef FEAT_PROFILE
! if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
.isn_type == ISN_PROF_START)
// move the profile start after "endtry" so that it's not counted when
// the exception is rethrown.
--- 8395,8402 ----
}
#ifdef FEAT_PROFILE
! if (cctx->ctx_compile_type == CT_PROFILE
! && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
.isn_type == ISN_PROF_START)
// move the profile start after "endtry" so that it's not counted when
// the exception is rethrown.
***************
*** 8399,8405 ****
&& generate_instr(cctx, ISN_ENDTRY) == NULL)
return NULL;
#ifdef FEAT_PROFILE
! if (cctx->ctx_profiling)
generate_instr(cctx, ISN_PROF_START);
#endif
}
--- 8428,8434 ----
&& generate_instr(cctx, ISN_ENDTRY) == NULL)
return NULL;
#ifdef FEAT_PROFILE
! if (cctx->ctx_compile_type == CT_PROFILE)
generate_instr(cctx, ISN_PROF_START);
#endif
}
***************
*** 8965,8974 ****
*/
int
compile_def_function(
! ufunc_T *ufunc,
! int check_return_type,
! int profiling UNUSED,
! cctx_T *outer_cctx)
{
char_u *line = NULL;
char_u *line_to_free = NULL;
--- 8994,9003 ----
*/
int
compile_def_function(
! ufunc_T *ufunc,
! int check_return_type,
! compiletype_T compile_type,
! cctx_T *outer_cctx)
{
char_u *line = NULL;
char_u *line_to_free = NULL;
***************
*** 8987,8992 ****
--- 9016,9022 ----
#ifdef FEAT_PROFILE
int prof_lnum = -1;
#endif
+ int debug_lnum = -1;
// When using a function that was compiled before: Free old instructions.
// The index is reused. Otherwise add a new entry in "def_functions".
***************
*** 9007,9015 ****
CLEAR_FIELD(cctx);
! #ifdef FEAT_PROFILE
! cctx.ctx_profiling = profiling;
! #endif
cctx.ctx_ufunc = ufunc;
cctx.ctx_lnum = -1;
cctx.ctx_outer = outer_cctx;
--- 9037,9043 ----
CLEAR_FIELD(cctx);
! cctx.ctx_compile_type = compile_type;
cctx.ctx_ufunc = ufunc;
cctx.ctx_lnum = -1;
cctx.ctx_outer = outer_cctx;
***************
*** 9159,9166 ****
}
#ifdef FEAT_PROFILE
! if (cctx.ctx_profiling && cctx.ctx_lnum != prof_lnum &&
! cctx.ctx_skip != SKIP_YES)
{
may_generate_prof_end(&cctx, prof_lnum);
--- 9187,9194 ----
}
#ifdef FEAT_PROFILE
! if (cctx.ctx_compile_type == CT_PROFILE && cctx.ctx_lnum != prof_lnum
! && cctx.ctx_skip != SKIP_YES)
{
may_generate_prof_end(&cctx, prof_lnum);
***************
*** 9168,9173 ****
--- 9196,9207 ----
generate_instr(&cctx, ISN_PROF_START);
}
#endif
+ if (cctx.ctx_compile_type == CT_DEBUG && cctx.ctx_lnum != debug_lnum
+ && cctx.ctx_skip != SKIP_YES)
+ {
+ debug_lnum = cctx.ctx_lnum;
+ generate_instr(&cctx, ISN_DEBUG);
+ }
// Some things can be recognized by the first character.
switch (*ea.cmd)
***************
*** 9617,9629 ****
dfunc->df_deleted = FALSE;
dfunc->df_script_seq = current_sctx.sc_seq;
#ifdef FEAT_PROFILE
! if (cctx.ctx_profiling)
{
dfunc->df_instr_prof = instr->ga_data;
dfunc->df_instr_prof_count = instr->ga_len;
}
else
#endif
{
dfunc->df_instr = instr->ga_data;
dfunc->df_instr_count = instr->ga_len;
--- 9651,9669 ----
dfunc->df_deleted = FALSE;
dfunc->df_script_seq = current_sctx.sc_seq;
#ifdef FEAT_PROFILE
! if (cctx.ctx_compile_type == CT_PROFILE)
{
dfunc->df_instr_prof = instr->ga_data;
dfunc->df_instr_prof_count = instr->ga_len;
}
else
#endif
+ if (cctx.ctx_compile_type == CT_DEBUG)
+ {
+ dfunc->df_instr_debug = instr->ga_data;
+ dfunc->df_instr_debug_count = instr->ga_len;
+ }
+ else
{
dfunc->df_instr = instr->ga_data;
dfunc->df_instr_count = instr->ga_len;
***************
*** 9919,9924 ****
--- 9959,9965 ----
case ISN_COMPARESTRING:
case ISN_CONCAT:
case ISN_COND2BOOL:
+ case ISN_DEBUG:
case ISN_DROP:
case ISN_ECHO:
case ISN_ECHOERR:
***************
*** 9927,9932 ****
--- 9968,9974 ----
case ISN_EXECCONCAT:
case ISN_EXECUTE:
case ISN_FINALLY:
+ case ISN_FINISH:
case ISN_FOR:
case ISN_GETITEM:
case ISN_JUMP:
***************
*** 9949,9955 ****
case ISN_NEWLIST:
case ISN_OPANY:
case ISN_OPFLOAT:
- case ISN_FINISH:
case ISN_OPNR:
case ISN_PCALL:
case ISN_PCALL_END:
--- 9991,9996 ----
*** ../vim-8.2.2984/src/proto/
vim9compile.pro 2021-04-07 21:21:09.473817695 +0200
--- src/proto/
vim9compile.pro 2021-06-12 18:59:23.230860742 +0200
***************
*** 3,9 ****
int check_compare_types(exprtype_T type, typval_T *tv1, typval_T *tv2);
int use_typecheck(type_T *actual, type_T *expected);
int need_type(type_T *actual, type_T *expected, int offset, int arg_idx, cctx_T *cctx, int silent, int actual_is_const);
! int func_needs_compiling(ufunc_T *ufunc, int profile);
int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx);
imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx);
imported_T *find_imported_in_script(char_u *name, size_t len, int sid);
--- 3,9 ----
int check_compare_types(exprtype_T type, typval_T *tv1, typval_T *tv2);
int use_typecheck(type_T *actual, type_T *expected);
int need_type(type_T *actual, type_T *expected, int offset, int arg_idx, cctx_T *cctx, int silent, int actual_is_const);
! int func_needs_compiling(ufunc_T *ufunc, compiletype_T compile_type);
int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx);
imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx);
imported_T *find_imported_in_script(char_u *name, size_t len, int sid);
***************
*** 17,23 ****
int assignment_len(char_u *p, int *heredoc);
void vim9_declare_error(char_u *name);
int check_vim9_unlet(char_u *name);
! int compile_def_function(ufunc_T *ufunc, int check_return_type, int profiling, cctx_T *outer_cctx);
void set_function_type(ufunc_T *ufunc);
void delete_instr(isn_T *isn);
void unlink_def_function(ufunc_T *ufunc);
--- 17,23 ----
int assignment_len(char_u *p, int *heredoc);
void vim9_declare_error(char_u *name);
int check_vim9_unlet(char_u *name);
! int compile_def_function(ufunc_T *ufunc, int check_return_type, compiletype_T compile_type, cctx_T *outer_cctx);
void set_function_type(ufunc_T *ufunc);
void delete_instr(isn_T *isn);
void unlink_def_function(ufunc_T *ufunc);
*** ../vim-8.2.2984/src/vim.h 2021-06-10 21:07:45.411050902 +0200
--- src/vim.h 2021-06-12 18:56:17.735305076 +0200
***************
*** 1794,1803 ****
typedef int proftime_T; // dummy for function prototypes
#endif
#ifdef FEAT_PROFILE
! # define PROFILING(ufunc) (do_profiling == PROF_YES && (ufunc)->uf_profiling)
#else
! # define PROFILING(ufunc) FALSE
#endif
/*
--- 1794,1810 ----
typedef int proftime_T; // dummy for function prototypes
#endif
+ // Type of compilation passed to compile_def_function()
+ typedef enum {
+ CT_NONE, // use df_instr
+ CT_PROFILE, // use df_instr_prof
+ CT_DEBUG // use df_instr_debug, overrules CT_PROFILE
+ } compiletype_T;
+
#ifdef FEAT_PROFILE
! # define COMPILE_TYPE(ufunc) (debug_break_level > 0 ? CT_DEBUG : do_profiling == PROF_YES && (ufunc)->uf_profiling ? CT_PROFILE : CT_NONE)
#else
! # define COMPILE_TYPE(ufunc) debug_break_level > 0 ? CT_DEBUG : CT_NONE
#endif
/*
*** ../vim-8.2.2984/src/eval.c 2021-06-12 15:58:12.482675579 +0200
--- src/eval.c 2021-06-13 13:21:56.749646030 +0200
***************
*** 3536,3542 ****
if (ufunc->uf_ret_type->tt_type == VAR_VOID)
ufunc->uf_ret_type = &t_unknown;
if (compile_def_function(ufunc,
! FALSE, PROFILING(ufunc), NULL) == FAIL)
{
clear_tv(rettv);
ret = FAIL;
--- 3536,3542 ----
if (ufunc->uf_ret_type->tt_type == VAR_VOID)
ufunc->uf_ret_type = &t_unknown;
if (compile_def_function(ufunc,
! FALSE, COMPILE_TYPE(ufunc), NULL) == FAIL)
{
clear_tv(rettv);
ret = FAIL;
*** ../vim-8.2.2984/src/vim9execute.c 2021-06-09 19:29:59.888951195 +0200
--- src/vim9execute.c 2021-06-13 13:56:32.788875420 +0200
***************
*** 204,211 ****
// Profiling might be enabled/disabled along the way. This should not
// fail, since the function was compiled before and toggling profiling
// doesn't change any errors.
! if (func_needs_compiling(ufunc, PROFILING(ufunc))
! && compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL)
== FAIL)
return FAIL;
}
--- 204,211 ----
// Profiling might be enabled/disabled along the way. This should not
// fail, since the function was compiled before and toggling profiling
// doesn't change any errors.
! if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
! && compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL)
== FAIL)
return FAIL;
}
***************
*** 264,269 ****
--- 264,270 ----
// If depth of calling is getting too high, don't execute the function.
if (funcdepth_increment() == FAIL)
return FAIL;
+ ++ex_nesting_level;
// Only make a copy of funclocal if it contains something to restore.
if (ectx->ec_funclocal.floc_restore_cmdmod)
***************
*** 647,652 ****
--- 648,654 ----
ectx->ec_stack.ga_len = top;
funcdepth_decrement();
+ --ex_nesting_level;
return OK;
}
***************
*** 737,749 ****
int idx;
int did_emsg_before = did_emsg;
#ifdef FEAT_PROFILE
! int profiling = do_profiling == PROF_YES && ufunc->uf_profiling;
#else
! # define profiling FALSE
#endif
! if (func_needs_compiling(ufunc, profiling)
! && compile_def_function(ufunc, FALSE, profiling, NULL) == FAIL)
return FAIL;
if (ufunc->uf_def_status == UF_COMPILED)
{
--- 739,753 ----
int idx;
int did_emsg_before = did_emsg;
#ifdef FEAT_PROFILE
! compiletype_T compile_type = do_profiling == PROF_YES
! && ufunc->uf_profiling ? CT_PROFILE : CT_NONE;
#else
! # define compile_type CT_NONE
#endif
! if (func_needs_compiling(ufunc, compile_type)
! && compile_def_function(ufunc, FALSE, compile_type, NULL)
! == FAIL)
return FAIL;
if (ufunc->uf_def_status == UF_COMPILED)
{
***************
*** 4099,4104 ****
--- 4103,4124 ----
}
break;
+ case ISN_DEBUG:
+ if (ex_nesting_level <= debug_break_level)
+ {
+ char_u *line;
+ ufunc_T *ufunc = (((dfunc_T *)def_functions.ga_data)
+ + ectx->ec_dfunc_idx)->df_ufunc;
+
+ SOURCING_LNUM = iptr->isn_lnum;
+ line = ((char_u **)ufunc->uf_lines.ga_data)[
+ iptr->isn_lnum - 1];
+ if (line == NULL)
+ line = (char_u *)"[empty]";
+ do_debug(line);
+ }
+ break;
+
case ISN_SHUFFLE:
{
typval_T tmp_tv;
***************
*** 4258,4263 ****
--- 4278,4284 ----
int save_emsg_silent_def = emsg_silent_def;
int save_did_emsg_def = did_emsg_def;
int orig_funcdepth;
+ int orig_nesting_level = ex_nesting_level;
// Get pointer to item in the stack.
#undef STACK_TV
***************
*** 4273,4280 ****
if (ufunc->uf_def_status == UF_NOT_COMPILED
|| ufunc->uf_def_status == UF_COMPILE_ERROR
! || (func_needs_compiling(ufunc, PROFILING(ufunc))
! && compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL)
== FAIL))
{
if (did_emsg_cumul + did_emsg == did_emsg_before)
--- 4294,4301 ----
if (ufunc->uf_def_status == UF_NOT_COMPILED
|| ufunc->uf_def_status == UF_COMPILE_ERROR
! || (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
! && compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL)
== FAIL))
{
if (did_emsg_cumul + did_emsg == did_emsg_before)
***************
*** 4310,4315 ****
--- 4331,4337 ----
ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10);
ga_init2(&ectx.ec_funcrefs, sizeof(partial_T *), 10);
ectx.ec_did_emsg_before = did_emsg_before;
+ ++ex_nesting_level;
idx = argc - ufunc->uf_args.ga_len;
if (idx > 0 && ufunc->uf_va_name == NULL)
***************
*** 4553,4558 ****
--- 4575,4581 ----
// Free all local variables, but not arguments.
for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx)
clear_tv(STACK_TV(idx));
+ ex_nesting_level = orig_nesting_level;
vim_free(ectx.ec_stack.ga_data);
vim_free(ectx.ec_trystack.ga_data);
***************
*** 5315,5327 ****
case ISN_CMDMOD_REV: smsg("%s%4d CMDMOD_REV", pfx, current); break;
case ISN_PROF_START:
! smsg("%s%4d PROFILE START line %d", pfx, current, iptr->isn_lnum);
break;
case ISN_PROF_END:
smsg("%s%4d PROFILE END", pfx, current);
break;
case ISN_UNPACK: smsg("%s%4d UNPACK %d%s", pfx, current,
iptr->isn_arg.unpack.unp_count,
iptr->isn_arg.unpack.unp_semicolon ? " semicolon" : "");
--- 5338,5355 ----
case ISN_CMDMOD_REV: smsg("%s%4d CMDMOD_REV", pfx, current); break;
case ISN_PROF_START:
! smsg("%s%4d PROFILE START line %d", pfx, current,
! iptr->isn_lnum);
break;
case ISN_PROF_END:
smsg("%s%4d PROFILE END", pfx, current);
break;
+ case ISN_DEBUG:
+ smsg("%s%4d DEBUG line %d", pfx, current, iptr->isn_lnum);
+ break;
+
case ISN_UNPACK: smsg("%s%4d UNPACK %d%s", pfx, current,
iptr->isn_arg.unpack.unp_count,
iptr->isn_arg.unpack.unp_semicolon ? " semicolon" : "");
***************
*** 5358,5363 ****
--- 5386,5403 ----
isn_T *instr;
int instr_count;
int is_global = FALSE;
+ compiletype_T compile_type = CT_NONE;
+
+ if (STRNCMP(arg, "profile", 7) == 0)
+ {
+ compile_type = CT_PROFILE;
+ arg = skipwhite(arg + 7);
+ }
+ else if (STRNCMP(arg, "debug", 5) == 0)
+ {
+ compile_type = CT_DEBUG;
+ arg = skipwhite(arg + 5);
+ }
if (STRNCMP(arg, "<lambda>", 8) == 0)
{
***************
*** 5389,5396 ****
semsg(_(e_cannot_find_function_str), eap->arg);
return;
}
! if (func_needs_compiling(ufunc, eap->forceit)
! && compile_def_function(ufunc, FALSE, eap->forceit, NULL) == FAIL)
return;
if (ufunc->uf_def_status != UF_COMPILED)
{
--- 5429,5436 ----
semsg(_(e_cannot_find_function_str), eap->arg);
return;
}
! if (func_needs_compiling(ufunc, compile_type)
! && compile_def_function(ufunc, FALSE, compile_type, NULL) == FAIL)
return;
if (ufunc->uf_def_status != UF_COMPILED)
{
***************
*** 5403,5416 ****
msg((char *)ufunc->uf_name);
dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
#ifdef FEAT_PROFILE
! instr = eap->forceit ? dfunc->df_instr_prof : dfunc->df_instr;
! instr_count = eap->forceit ? dfunc->df_instr_prof_count
! : dfunc->df_instr_count;
! #else
! instr = dfunc->df_instr;
! instr_count = dfunc->df_instr_count;
#endif
list_instructions("", instr, instr_count, ufunc);
}
--- 5443,5466 ----
msg((char *)ufunc->uf_name);
dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
+ switch (compile_type)
+ {
+ case CT_PROFILE:
#ifdef FEAT_PROFILE
! instr = dfunc->df_instr_prof;
! instr_count = dfunc->df_instr_prof_count;
! break;
#endif
+ // FALLTHROUGH
+ case CT_NONE:
+ instr = dfunc->df_instr;
+ instr_count = dfunc->df_instr_count;
+ break;
+ case CT_DEBUG:
+ instr = dfunc->df_instr_debug;
+ instr_count = dfunc->df_instr_debug_count;
+ break;
+ }
list_instructions("", instr, instr_count, ufunc);
}
*** ../vim-8.2.2984/src/userfunc.c 2021-06-12 15:58:12.486675568 +0200
--- src/userfunc.c 2021-06-13 13:25:30.633326829 +0200
***************
*** 4395,4401 ****
&& ufunc->uf_def_status == UF_TO_BE_COMPILED
&& (ufunc->uf_flags & FC_DEAD) == 0)
{
! (void)compile_def_function(ufunc, FALSE, FALSE, NULL);
if (func_hashtab.ht_changed != changed)
{
--- 4395,4401 ----
&& ufunc->uf_def_status == UF_TO_BE_COMPILED
&& (ufunc->uf_flags & FC_DEAD) == 0)
{
! (void)compile_def_function(ufunc, FALSE, CT_NONE, NULL);
if (func_hashtab.ht_changed != changed)
{
*** ../vim-8.2.2984/src/vim9type.c 2021-05-07 17:55:51.971584412 +0200
--- src/vim9type.c 2021-06-13 13:25:05.817369362 +0200
***************
*** 349,355 ****
// May need to get the argument types from default values by
// compiling the function.
if (ufunc->uf_def_status == UF_TO_BE_COMPILED
! && compile_def_function(ufunc, TRUE, FALSE, NULL)
== FAIL)
return NULL;
if (ufunc->uf_func_type == NULL)
--- 349,355 ----
// May need to get the argument types from default values by
// compiling the function.
if (ufunc->uf_def_status == UF_TO_BE_COMPILED
! && compile_def_function(ufunc, TRUE, CT_NONE, NULL)
== FAIL)
return NULL;
if (ufunc->uf_func_type == NULL)
*** ../vim-8.2.2984/src/testdir/test_debugger.vim 2020-12-18 19:49:52.345571854 +0100
--- src/testdir/test_debugger.vim 2021-06-13 13:36:38.339864912 +0200
***************
*** 884,902 ****
\ ':debug call GlobalFunction()',
\ ['cmd: call GlobalFunction()'])
! " FIXME: Vim9 lines are not debugged!
! call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
! " But they do appear in the backtrace
call RunDbgCmd(buf, 'backtrace', [
\ '\V>backtrace',
! \ '\V 2 function GlobalFunction[1]',
! \ '\V 1 <SNR>\.\*_CallAFunction[1]',
! \ '\V->0 <SNR>\.\*_SourceAnotherFile',
! \ '\Vline 1: source Xtest2.vim'],
\ #{match: 'pattern'})
!
call RunDbgCmd(buf, 'step', ['line 1: vim9script'])
call RunDbgCmd(buf, 'step', ['line 3: def DoAThing(): number'])
call RunDbgCmd(buf, 'step', ['line 9: export def File2Function()'])
--- 884,903 ----
\ ':debug call GlobalFunction()',
\ ['cmd: call GlobalFunction()'])
! call RunDbgCmd(buf, 'step', ['line 1: CallAFunction()'])
! " FIXME: not quite right
call RunDbgCmd(buf, 'backtrace', [
\ '\V>backtrace',
! \ '\V->0 function GlobalFunction',
! \ '\Vline 1: CallAFunction()',
! \ ],
\ #{match: 'pattern'})
! call RunDbgCmd(buf, 'step', ['line 1: SourceAnotherFile()'])
! call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
! " FIXME: repeated line
! call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
call RunDbgCmd(buf, 'step', ['line 1: vim9script'])
call RunDbgCmd(buf, 'step', ['line 3: def DoAThing(): number'])
call RunDbgCmd(buf, 'step', ['line 9: export def File2Function()'])
***************
*** 913,919 ****
\ #{match: 'pattern'})
" Don't step into compiled functions...
! call RunDbgCmd(buf, 'step', ['line 15: End of sourced file'])
call RunDbgCmd(buf, 'backtrace', [
\ '\V>backtrace',
\ '\V 3 function GlobalFunction[1]',
--- 914,920 ----
\ #{match: 'pattern'})
" Don't step into compiled functions...
! call RunDbgCmd(buf, 'next', ['line 15: End of sourced file'])
call RunDbgCmd(buf, 'backtrace', [
\ '\V>backtrace',
\ '\V 3 function GlobalFunction[1]',
***************
*** 923,929 ****
\ '\Vline 15: End of sourced file'],
\ #{match: 'pattern'})
-
call StopVimInTerminal(buf)
call delete('Xtest1.vim')
call delete('Xtest2.vim')
--- 924,929 ----
***************
*** 1116,1121 ****
--- 1116,1122 ----
\ [ 'E121: Undefined variable: s:file1_var' ] )
call RunDbgCmd(buf, 'echo s:file2_var', [ 'file2' ] )
+ call RunDbgCmd(buf, 'cont')
call StopVimInTerminal(buf)
call delete('Xtest1.vim')
call delete('Xtest2.vim')
*** ../vim-8.2.2984/src/testdir/test_vim9_disassemble.vim 2021-06-06 17:02:49.753789485 +0200
--- src/testdir/test_vim9_disassemble.vim 2021-06-13 13:59:16.264623917 +0200
***************
*** 2153,2159 ****
if !has('profile')
MissingFeature 'profile'
endif
! var res = execute('disass! s:Profiled')
assert_match('<SNR>\d*_Profiled\_s*' ..
'echo "profiled"\_s*' ..
'\d PROFILE START line 1\_s*' ..
--- 2153,2159 ----
if !has('profile')
MissingFeature 'profile'
endif
! var res = execute('disass profile s:Profiled')
assert_match('<SNR>\d*_Profiled\_s*' ..
'echo "profiled"\_s*' ..
'\d PROFILE START line 1\_s*' ..
***************
*** 2168,2173 ****
--- 2168,2187 ----
res)
enddef
+ def Test_debugged()
+ var res = execute('disass debug s:Profiled')
+ assert_match('<SNR>\d*_Profiled\_s*' ..
+ 'echo "profiled"\_s*' ..
+ '\d DEBUG line 1\_s*' ..
+ '\d PUSHS "profiled"\_s*' ..
+ '\d ECHO 1\_s*' ..
+ 'return "done"\_s*' ..
+ '\d DEBUG line 2\_s*' ..
+ '\d PUSHS "done"\_s*' ..
+ '\d RETURN\_s*',
+ res)
+ enddef
+
def s:EchoMessages()
echohl ErrorMsg | echom v:exception | echohl NONE
enddef
*** ../vim-8.2.2984/src/version.c 2021-06-12 18:30:51.510966898 +0200
--- src/version.c 2021-06-13 13:59:49.728566286 +0200
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 2985,
/**/
--
"Beware of bugs in the above code; I have only proved
it correct, not tried it." -- Donald Knuth
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///