To: vim_dev@googlegroups.com Subject: Patch 8.2.2985 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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, "", 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 \.\*_CallAFunction[1]', ! \ '\V->0 \.\*_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('\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('\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('\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 -- Bram@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 ///