]> granicus.if.org Git - vim/commitdiff
patch 8.2.2985: Vim9: a compiled function cannot be debugged v8.2.2985
authorBram Moolenaar <Bram@vim.org>
Sun, 13 Jun 2021 12:01:26 +0000 (14:01 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 13 Jun 2021 12:01:26 +0000 (14:01 +0200)
Problem:    Vim9: a compiled function cannot be debugged.
Solution:   Add initial debugging support.

src/eval.c
src/proto/vim9compile.pro
src/testdir/test_debugger.vim
src/testdir/test_vim9_disassemble.vim
src/userfunc.c
src/version.c
src/vim.h
src/vim9.h
src/vim9compile.c
src/vim9execute.c
src/vim9type.c

index 8a6539e3fcf4bd726e8994ba7bef21e3bb179a6d..ffc7122cde4cd9ee5096b95120dafde1b0e7770d 100644 (file)
@@ -3536,7 +3536,7 @@ eval7(
                        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)
+                                    FALSE, COMPILE_TYPE(ufunc), NULL) == FAIL)
                        {
                            clear_tv(rettv);
                            ret = FAIL;
index 39624aef1979fefc3675efe86d78aea4c4388d3c..881dddc510bf244d6141231acfb7036f4a931725 100644 (file)
@@ -3,7 +3,7 @@ int check_defined(char_u *p, size_t len, cctx_T *cctx, int is_arg);
 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 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,7 +17,7 @@ void fill_exarg_from_cctx(exarg_T *eap, cctx_T *cctx);
 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);
+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);
index 029b9dbc9cfa1b153d1346430ffe34a3a37f712a..ed4baccf11d9b7665c8d48e5a649f9a95aef56e1 100644 (file)
@@ -884,19 +884,20 @@ func Test_Backtrace_DefFunction()
                 \ ':debug call GlobalFunction()',
                 \ ['cmd: call GlobalFunction()'])
 
-  " FIXME: Vim9 lines are not debugged!
-  call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
+  call RunDbgCmd(buf, 'step', ['line 1:   CallAFunction()'])
 
-  " But they do appear in the backtrace
+  " FIXME: not quite right
   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'],
+        \ '\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,7 +914,7 @@ func Test_Backtrace_DefFunction()
         \ #{match: 'pattern'})
 
   " Don't step into compiled functions...
-  call RunDbgCmd(buf, 'step', ['line 15: End of sourced file'])
+  call RunDbgCmd(buf, 'next', ['line 15: End of sourced file'])
   call RunDbgCmd(buf, 'backtrace', [
         \ '\V>backtrace',
         \ '\V  3 function GlobalFunction[1]',
@@ -923,7 +924,6 @@ func Test_Backtrace_DefFunction()
         \ '\Vline 15: End of sourced file'],
         \ #{match: 'pattern'})
 
-
   call StopVimInTerminal(buf)
   call delete('Xtest1.vim')
   call delete('Xtest2.vim')
@@ -1116,6 +1116,7 @@ func Test_debug_backtrace_level()
         \ [ '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')
index 965399bca1ef467ad3121209da397e217c72afad..e1ed6754db225e6fae0d6280e4c71af95c77160f 100644 (file)
@@ -2153,7 +2153,7 @@ def Test_profiled()
   if !has('profile')
     MissingFeature 'profile'
   endif
-  var res = execute('disass! s:Profiled')
+  var res = execute('disass profile s:Profiled')
   assert_match('<SNR>\d*_Profiled\_s*' ..
         'echo "profiled"\_s*' ..
         '\d PROFILE START line 1\_s*' ..
@@ -2168,6 +2168,20 @@ def Test_profiled()
         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
index f610c022d61b5722a0f21220f57b8e8177829713..56b7df32f5310dac19e72cd332d13417d7cee53e 100644 (file)
@@ -4395,7 +4395,7 @@ ex_defcompile(exarg_T *eap UNUSED)
                    && ufunc->uf_def_status == UF_TO_BE_COMPILED
                    && (ufunc->uf_flags & FC_DEAD) == 0)
            {
-               (void)compile_def_function(ufunc, FALSE, FALSE, NULL);
+               (void)compile_def_function(ufunc, FALSE, CT_NONE, NULL);
 
                if (func_hashtab.ht_changed != changed)
                {
index 7f459c27af0b2ea868228d27af19dca8d7ef46ff..ad399ce486417018d793fbd7fa3ad34f3bcd055a 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2985,
 /**/
     2984,
 /**/
index e1e68f965024a0817cfa033ab48e24c7198640bb..784fa3a8c0d3c52b7683b9732e006bfe1a74e3e3 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -1794,10 +1794,17 @@ typedef struct timeval proftime_T;
 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 PROFILING(ufunc) (do_profiling == PROF_YES && (ufunc)->uf_profiling)
+# define COMPILE_TYPE(ufunc) (debug_break_level > 0 ? CT_DEBUG : do_profiling == PROF_YES && (ufunc)->uf_profiling ? CT_PROFILE : CT_NONE)
 #else
-# define PROFILING(ufunc) FALSE
+# define COMPILE_TYPE(ufunc) debug_break_level > 0 ? CT_DEBUG : CT_NONE
 #endif
 
 /*
index d4d3b7d6c1ceafb16cc54213a6c9a20b0755d07b..f434602d2b6400aa972cf2e0b85e0dcd4e4705e2 100644 (file)
@@ -168,6 +168,8 @@ typedef enum {
     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,6 +455,8 @@ struct dfunc_S {
     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
index 47847af3aaa1553cab77cd608117edc6e3c37cb7..7c0190677f2a1c85e540c1391d99ba18e2dd7d2e 100644 (file)
@@ -174,7 +174,7 @@ struct cctx_S {
     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
+    compiletype_T ctx_compile_type;
 
     garray_T   ctx_locals;         // currently visible local variables
     int                ctx_locals_count;   // total number of local variables
@@ -1857,7 +1857,7 @@ generate_BLOBAPPEND(cctx_T *cctx)
  * "profile" indicates profiling is to be done.
  */
     int
-func_needs_compiling(ufunc_T *ufunc, int profile UNUSED)
+func_needs_compiling(ufunc_T *ufunc, compiletype_T compile_type)
 {
     switch (ufunc->uf_def_status)
     {
@@ -1866,15 +1866,18 @@ func_needs_compiling(ufunc_T *ufunc, int profile UNUSED)
 
        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
+           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,9 +1948,9 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
                return FAIL;
            }
        }
-       if (func_needs_compiling(ufunc, PROFILING(ufunc))
+       if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
                && compile_def_function(ufunc, ufunc->uf_ret_type == NULL,
-                                              PROFILING(ufunc), NULL) == FAIL)
+                                           COMPILE_TYPE(ufunc), NULL) == FAIL)
            return FAIL;
     }
     if (ufunc->uf_def_status == UF_COMPILE_ERROR)
@@ -2313,14 +2316,28 @@ current_instr_idx(cctx_T *cctx)
     garray_T   *instr = &cctx->ctx_instr;
     int                idx = instr->ga_len;
 
-    if (cctx->ctx_has_cmdmod && ((isn_T *)instr->ga_data)[idx - 1]
+    while (idx > 0)
+    {
+       if (cctx->ctx_has_cmdmod && ((isn_T *)instr->ga_data)[idx - 1]
                                                       .isn_type == ISN_CMDMOD)
-       --idx;
+       {
+           --idx;
+           continue;
+       }
 #ifdef FEAT_PROFILE
-    if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[idx - 1]
-                                                  .isn_type == ISN_PROF_START)
-       --idx;
+       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,7 +2345,7 @@ current_instr_idx(cctx_T *cctx)
     static void
 may_generate_prof_end(cctx_T *cctx, int prof_lnum)
 {
-    if (cctx->ctx_profiling && prof_lnum >= 0)
+    if (cctx->ctx_compile_type == CT_PROFILE && prof_lnum >= 0)
        generate_instr(cctx, ISN_PROF_END);
 }
 #endif
@@ -2972,8 +2989,8 @@ generate_funcref(cctx_T *cctx, char_u *name)
        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)
+    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,7 +3587,7 @@ compile_lambda(char_u **arg, cctx_T *cctx)
     // 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);
+    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,8 +5583,8 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
        }
     }
 
-    if (func_needs_compiling(ufunc, PROFILING(ufunc))
-           && compile_def_function(ufunc, TRUE, PROFILING(ufunc), cctx)
+    if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
+           && compile_def_function(ufunc, TRUE, COMPILE_TYPE(ufunc), cctx)
                                                                       == FAIL)
     {
        func_ptr_unref(ufunc);
@@ -7376,7 +7393,7 @@ compile_if(char_u *arg, cctx_T *cctx)
        scope->se_u.se_if.is_if_label = -1;
 
 #ifdef FEAT_PROFILE
-    if (cctx->ctx_profiling && cctx->ctx_skip == SKIP_YES
+    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,13 +7474,19 @@ compile_elseif(char_u *arg, cctx_T *cctx)
     {
        cctx->ctx_skip = SKIP_UNKNOWN;
 #ifdef FEAT_PROFILE
-       if (cctx->ctx_profiling)
+       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,12 +7554,13 @@ compile_else(char_u *arg, cctx_T *cctx)
     scope->se_u.se_if.is_seen_else = TRUE;
 
 #ifdef FEAT_PROFILE
-    if (cctx->ctx_profiling)
+    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
+           // 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,7 +7636,7 @@ compile_endif(char_u *arg, cctx_T *cctx)
 #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
+    if (cctx->ctx_compile_type == CT_PROFILE && cctx->ctx_skip == SKIP_YES
                                            && scope->se_skip_save != SKIP_YES)
     {
        cctx->ctx_skip = SKIP_NOT;
@@ -8183,7 +8207,8 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED)
     {
 #ifdef FEAT_PROFILE
        // the profile-start should be after the jump
-       if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
+       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,7 +8228,7 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED)
            isn->isn_arg.jump.jump_where = instr->ga_len;
        }
 #ifdef FEAT_PROFILE
-       if (cctx->ctx_profiling)
+       if (cctx->ctx_compile_type == CT_PROFILE)
        {
            // a "throw" that jumps here needs to be counted
            generate_instr(cctx, ISN_PROF_END);
@@ -8211,6 +8236,8 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED)
            generate_instr(cctx, ISN_PROF_START);
        }
 #endif
+       if (cctx->ctx_compile_type == CT_DEBUG)
+           generate_instr(cctx, ISN_DEBUG);
     }
 
     p = skipwhite(arg);
@@ -8298,7 +8325,8 @@ compile_finally(char_u *arg, cctx_T *cctx)
 
     this_instr = instr->ga_len;
 #ifdef FEAT_PROFILE
-    if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
+    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,7 +8395,8 @@ compile_endtry(char_u *arg, cctx_T *cctx)
        }
 
 #ifdef FEAT_PROFILE
-       if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
+       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,7 +8428,7 @@ compile_endtry(char_u *arg, cctx_T *cctx)
                                   && generate_instr(cctx, ISN_ENDTRY) == NULL)
            return NULL;
 #ifdef FEAT_PROFILE
-       if (cctx->ctx_profiling)
+       if (cctx->ctx_compile_type == CT_PROFILE)
            generate_instr(cctx, ISN_PROF_START);
 #endif
     }
@@ -8965,10 +8994,10 @@ add_def_function(ufunc_T *ufunc)
  */
     int
 compile_def_function(
-       ufunc_T     *ufunc,
-       int         check_return_type,
-       int         profiling UNUSED,
-       cctx_T      *outer_cctx)
+       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,6 +9016,7 @@ compile_def_function(
 #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,9 +9037,7 @@ compile_def_function(
 
     CLEAR_FIELD(cctx);
 
-#ifdef FEAT_PROFILE
-    cctx.ctx_profiling = profiling;
-#endif
+    cctx.ctx_compile_type = compile_type;
     cctx.ctx_ufunc = ufunc;
     cctx.ctx_lnum = -1;
     cctx.ctx_outer = outer_cctx;
@@ -9159,8 +9187,8 @@ compile_def_function(
        }
 
 #ifdef FEAT_PROFILE
-       if (cctx.ctx_profiling && cctx.ctx_lnum != prof_lnum &&
-                                                    cctx.ctx_skip != SKIP_YES)
+       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,6 +9196,12 @@ compile_def_function(
            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,13 +9651,19 @@ nextline:
        dfunc->df_deleted = FALSE;
        dfunc->df_script_seq = current_sctx.sc_seq;
 #ifdef FEAT_PROFILE
-       if (cctx.ctx_profiling)
+       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,6 +9959,7 @@ delete_instr(isn_T *isn)
        case ISN_COMPARESTRING:
        case ISN_CONCAT:
        case ISN_COND2BOOL:
+       case ISN_DEBUG:
        case ISN_DROP:
        case ISN_ECHO:
        case ISN_ECHOERR:
@@ -9927,6 +9968,7 @@ delete_instr(isn_T *isn)
        case ISN_EXECCONCAT:
        case ISN_EXECUTE:
        case ISN_FINALLY:
+       case ISN_FINISH:
        case ISN_FOR:
        case ISN_GETITEM:
        case ISN_JUMP:
@@ -9949,7 +9991,6 @@ delete_instr(isn_T *isn)
        case ISN_NEWLIST:
        case ISN_OPANY:
        case ISN_OPFLOAT:
-       case ISN_FINISH:
        case ISN_OPNR:
        case ISN_PCALL:
        case ISN_PCALL_END:
index 767dcea3c82bc896f927925ee2f514d3c6a89a45..c1e40a68f48b6958dd7dd98b9a54ce66c08fd70e 100644 (file)
@@ -204,8 +204,8 @@ call_dfunc(
        // 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)
+       if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
+               && compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL)
                                                                       == FAIL)
            return FAIL;
     }
@@ -264,6 +264,7 @@ call_dfunc(
     // 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,6 +648,7 @@ func_return(ectx_T *ectx)
        ectx->ec_stack.ga_len = top;
 
     funcdepth_decrement();
+    --ex_nesting_level;
     return OK;
 }
 
@@ -737,13 +739,15 @@ call_ufunc(
     int                idx;
     int                did_emsg_before = did_emsg;
 #ifdef FEAT_PROFILE
-    int                profiling = do_profiling == PROF_YES && ufunc->uf_profiling;
+    compiletype_T compile_type = do_profiling == PROF_YES
+                                && ufunc->uf_profiling ? CT_PROFILE : CT_NONE;
 #else
-# define profiling FALSE
+# define compile_type CT_NONE
 #endif
 
-    if (func_needs_compiling(ufunc, profiling)
-               && compile_def_function(ufunc, FALSE, profiling, NULL) == FAIL)
+    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,6 +4103,22 @@ exec_instructions(ectx_T *ectx)
                }
                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,6 +4278,7 @@ call_def_function(
     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,8 +4294,8 @@ call_def_function(
 
     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)
+           || (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,6 +4331,7 @@ call_def_function(
     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,6 +4575,7 @@ failed_early:
     // 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,13 +5338,18 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
            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);
+                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,6 +5386,18 @@ ex_disassemble(exarg_T *eap)
     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,8 +5429,8 @@ ex_disassemble(exarg_T *eap)
        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)
+    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,14 +5443,24 @@ ex_disassemble(exarg_T *eap)
        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 = 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;
+           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);
 }
index 4dec1e7704416d61ebb47dfbfbaa555ea2a9c65e..f3718e4685b0ec675a9757209c99423b4704f52e 100644 (file)
@@ -349,7 +349,7 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int do_member)
            // 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)
+                           && compile_def_function(ufunc, TRUE, CT_NONE, NULL)
                                                                       == FAIL)
                return NULL;
            if (ufunc->uf_func_type == NULL)