Mercurial > hg > octave-lojdl
changeset 7901:3e4c9b69069d
call stack changes
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 08 Jul 2008 12:00:32 -0400 |
parents | 5b077861d168 |
children | c51ae36fcbce |
files | src/ChangeLog src/debug.cc src/ls-mat5.cc src/mex.cc src/ov-fcn-handle.cc src/ov-usr-fcn.cc src/parse.y src/symtab.cc src/symtab.h src/toplev.cc src/toplev.h |
diffstat | 11 files changed, 380 insertions(+), 160 deletions(-) [+] |
line wrap: on
line diff
--- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,60 @@ +2008-06-28 John W. Eaton <jwe@octave.org> + + * debug.cc (push_dummy_call_stack_elt): Delete. + (Fdbstack): Don't push dummy stack elt. Use nskip instead of + nframes, and curr_frame instead of idx. Pass curr_frame to + octave_call_stack::backtrace. + + * ls-mat5.cc (read_mat5_binary_element): Explicitly pass 0 for + current_context in call to symbol_table::varref. + * ov-fcn-handle.cc (octave_fcn_handle::load_ascii): Likewise. + Fix test. + + * mex.cc (mexGetVariable, mexPutVariable): Use octave_call_stack + methods to manipulate scope and context. + * parse.y (source_file, Fassignin, Fevalin): Likewise. + + * ov-usr-fcn.cc (octave_user_function::do_multi_index_op): + Call octave_call_stack::push after call to symbol_table::push_scope. + Call unwind_protect::add with octave_call_stack::unwind_pop + immediately after call to octave_call_stack::push. + + * symtab.cc (symbol_table::xcurrent_caller_scope): Delete definition. + * symtab.h (symbol_table::xcurrent_caller_scope): Delete decl. + Delete all uses. + (xcurrent_context_this_table): Delete. Delete all uses. + (symbol_table::current_caller_scope): Delete. + + * toplev.cc (octave_call_stack::do_num_user_code_frames): + New function. + (octave_call_stack::do_backtrace): New arg, curr_user_frame. + Rename nframes arg to nskip. Correctly handle curr_frame not at + end of stack. + (octave_call_stack::do_goto_frame_relative): Rename n arg to nskip. + Correctly handle curr_frame not at end of stack. + (octave_call_stack::do_goto_caller_frame): New function. + (octave_call_stack::do_goto_base_frame): New function. + * toplev.h: Provide decls for new functions. + (octave_call_stack::call_stack_elt::prev): New data member. + Initialize it in constructor. + (octave_call_stack::const_reverse_iterator, + octave_call_stack::reverse_iterator): New typedefs. + (octave_call_stack::symbol_table::scope_id current_scope, + octave_call_stack::symbol_table::context_id current_context, + octave_call_stack::num_user_code_frames, + octave_call_stack::goto_caller_frame, + octave_call_stack::goto_base_frame, + octave_call_stack::do_num_user_code_frames, + octave_call_stack::do_current_scope, + octave_call_stack::do_current_context): New functions. + + (octave_call_stack::push): Default value for context arg is + symbol_table::current_context, not 0. + (octave_call_stack::do_push): Save previous frame. Always push + new frame on back of stack. Call symbol_table::set_scope_and_context. + (octave_call_stack::do_pop): Restore previous frame. Always pop + frame from back of stack. Call symbol_table::set_scope_and_context. + 2008-06-26 John W. Eaton <jwe@octave.org> * token.h: Omit "class symbol_table::symbol_record" decl;
--- a/src/debug.cc +++ b/src/debug.cc @@ -695,12 +695,6 @@ return retval; } -void -push_dummy_call_stack_elt (void *) -{ - octave_call_stack::push (static_cast<octave_function *> (0)); -} - DEFCMD (dbstack, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {[@var{stack}, @var{idx}]} dbstack (@var{n})\n\ @@ -713,18 +707,9 @@ unwind_protect::begin_frame ("Fdbstack"); - // Debugging functions should not be included in the call stack, so - // we pop the dbstack function from the stack and then set up to - // restore a stack element when we exit this function (or when it is - // cleaned up). + octave_idx_type curr_frame = -1; - octave_call_stack::pop (); - - unwind_protect::add (push_dummy_call_stack_elt, 0); - - size_t total_frames = octave_call_stack::size (); - - size_t nframes = total_frames; + size_t nskip = 0; if (args.length () == 1) { @@ -742,18 +727,14 @@ n = args(0).int_value (); if (n > 0) - nframes = n; + nskip = n; else error ("dbstack: expecting N to be a nonnegative integer"); } if (! error_state) { - size_t curr_frame = octave_call_stack::current_frame (); - - Octave_map stk = octave_call_stack::backtrace (nframes); - - octave_idx_type idx = total_frames - curr_frame; + Octave_map stk = octave_call_stack::backtrace (nskip, curr_frame); if (nargout == 0) { @@ -773,7 +754,7 @@ octave_value line = lines(i); octave_value column = columns(i); - octave_stdout << (i == idx ? "--> " : " ") + octave_stdout << (i == curr_frame ? "--> " : " ") << name.string_value () << " at line " << line.int_value () << " column " << column.int_value () @@ -783,7 +764,7 @@ } else { - retval(1) = idx < 0 ? 1 : idx + 1; + retval(1) = curr_frame < 0 ? 1 : curr_frame + 1; retval(0) = stk; } }
--- a/src/ls-mat5.cc +++ b/src/ls-mat5.cc @@ -874,7 +874,7 @@ std::string key = m2.key(p0); octave_value val = m2.contents(p0)(0); - symbol_table::varref (key, local_scope) = val; + symbol_table::varref (key, local_scope, 0) = val; } }
--- a/src/mex.cc +++ b/src/mex.cc @@ -3268,16 +3268,22 @@ val = get_global_value (name); else { - symbol_table::scope_id scope = -1; - - if (! strcmp (space, "caller")) - scope = symbol_table::current_caller_scope (); - else if (! strcmp (space, "base")) - scope = symbol_table::top_scope (); + bool caller = ! strcmp (space, "caller"); + bool base = ! strcmp (space, "base"); + + if (caller || base) + { + if (caller) + octave_call_stack::goto_caller_frame (); + else + octave_call_stack::goto_base_frame (); + + val = symbol_table::varval (name); + + octave_call_stack::pop (); + } else mexErrMsgTxt ("mexGetVariable: symbol table does not exist"); - - val = symbol_table::varval (name, scope); } if (val.is_defined ()) @@ -3317,16 +3323,22 @@ { // FIXME -- should this be in variables.cc? - symbol_table::scope_id scope = -1; - - if (! strcmp (space, "caller")) - scope = symbol_table::current_caller_scope (); - else if (! strcmp (space, "base")) - scope = symbol_table::top_scope (); + bool caller = ! strcmp (space, "caller"); + bool base = ! strcmp (space, "base"); + + if (caller || base) + { + if (caller) + octave_call_stack::goto_caller_frame (); + else + octave_call_stack::goto_base_frame (); + + symbol_table::varref (name) = mxArray::as_octave_value (ptr); + + octave_call_stack::pop (); + } else mexErrMsgTxt ("mexPutVariable: symbol table does not exist"); - - symbol_table::varref (name, scope) = mxArray::as_octave_value (ptr); } return 0;
--- a/src/ov-fcn-handle.cc +++ b/src/ov-fcn-handle.cc @@ -342,7 +342,7 @@ break; } - symbol_table::varref (name, local_scope) = t2; + symbol_table::varref (name, local_scope, 0) = t2; } } } @@ -1122,8 +1122,8 @@ %! if (!isempty(findstr(octave_config_info ("DEFS"),"HAVE_HDF5"))) %! modes(end+1) = "-hdf5"; %! endif -%! for i = modes -%! mode = modes{1}; +%! for i = 1:numel (modes) +%! mode = modes{i}; %! nm = tmpnam(); %! unwind_protect %! save (mode, nm, "f2", "g2", "hm2", "hdld2", "hbi2");
--- a/src/ov-usr-fcn.cc +++ b/src/ov-usr-fcn.cc @@ -389,11 +389,12 @@ // Save old and set current symbol table context, for // eval_undefined_error(). - octave_call_stack::push (this, local_scope, call_depth); - symbol_table::push_scope (local_scope); unwind_protect::add (symbol_table::pop_scope); + octave_call_stack::push (this, local_scope, call_depth); + unwind_protect::add (octave_call_stack::unwind_pop, 0); + if (call_depth > 0) { symbol_table::push_context (); @@ -406,8 +407,6 @@ unwind_protect::add (symbol_table::clear_variables); } - unwind_protect::add (octave_call_stack::unwind_pop, 0); - if (! (is_nested_function () || is_inline_function ())) { unwind_protect_ptr (curr_parent_function);
--- a/src/parse.y +++ b/src/parse.y @@ -3407,14 +3407,14 @@ if (! context.empty ()) { if (context == "caller") - symbol_table::push_scope (symbol_table::current_caller_scope ()); + octave_call_stack::goto_caller_frame (); else if (context == "base") - symbol_table::push_scope (symbol_table::top_scope ()); + octave_call_stack::goto_base_frame (); else error ("source: context must be \"caller\" or \"base\""); if (! error_state) - unwind_protect::add (symbol_table::pop_scope); + unwind_protect::add (octave_call_stack::unwind_pop); } if (! error_state) @@ -3965,22 +3965,16 @@ symbol_table::scope_id scope = -1; if (context == "caller") - { - if (symbol_table::current_scope () == symbol_table::current_caller_scope ()) - { - error ("assignin: assignment in caller not implemented yet for direct recursion"); - return retval; - } - else - scope = symbol_table::current_caller_scope (); - } + octave_call_stack::goto_caller_frame (); else if (context == "base") - scope = symbol_table::top_scope (); + octave_call_stack::goto_base_frame (); else error ("assignin: context must be \"caller\" or \"base\""); if (! error_state) { + unwind_protect::add (octave_call_stack::unwind_pop); + std::string nm = args(1).string_value (); if (! error_state) @@ -4024,23 +4018,15 @@ unwind_protect::begin_frame ("Fevalin"); if (context == "caller") - { - if (symbol_table::current_scope () == symbol_table::current_caller_scope ()) - { - error ("evalin: evaluation in caller not implemented yet for direct recursion"); - return retval; - } - else - symbol_table::push_scope (symbol_table::current_caller_scope ()); - } + octave_call_stack::goto_caller_frame (); else if (context == "base") - symbol_table::push_scope (symbol_table::top_scope ()); + octave_call_stack::goto_base_frame (); else error ("evalin: context must be \"caller\" or \"base\""); if (! error_state) { - unwind_protect::add (symbol_table::pop_scope); + unwind_protect::add (octave_call_stack::unwind_pop); if (nargin > 2) {
--- a/src/symtab.cc +++ b/src/symtab.cc @@ -57,7 +57,6 @@ const symbol_table::scope_id symbol_table::xtop_scope = 1; symbol_table::scope_id symbol_table::xcurrent_scope = 1; -symbol_table::scope_id symbol_table::xcurrent_caller_scope = -1; symbol_table::scope_id symbol_table::xparent_scope = -1;
--- a/src/symtab.h +++ b/src/symtab.h @@ -859,7 +859,6 @@ static scope_id top_scope (void) { return xtop_scope; } static scope_id current_scope (void) { return xcurrent_scope; } - static scope_id current_caller_scope (void) { return xcurrent_caller_scope; } static context_id current_context (void) { return xcurrent_context; } @@ -887,7 +886,7 @@ instance = p->second; xcurrent_scope = scope; - xcurrent_context = instance->xcurrent_context_this_table; + xcurrent_context = 0; } } @@ -921,8 +920,6 @@ if (scope_stack.empty ()) scope_stack.push_front (xtop_scope); - xcurrent_caller_scope = xcurrent_scope; - set_scope (scope); scope_stack.push_front (scope); @@ -933,8 +930,6 @@ scope_stack.pop_front (); set_scope (scope_stack[0]); - - xcurrent_caller_scope = scope_stack.size () > 1 ? scope_stack[1] : -1; } static void pop_scope (void *) { pop_scope (); } @@ -946,8 +941,6 @@ scope_stack.push_front (xtop_scope); set_scope (xtop_scope); - - xcurrent_caller_scope = -1; } static void set_parent_scope (scope_id scope) @@ -1825,19 +1818,16 @@ static const scope_id xtop_scope; static scope_id xcurrent_scope; - static scope_id xcurrent_caller_scope; // We use parent_scope to handle parsing subfunctions. static scope_id xparent_scope; - // Used to handle recursive calls. - context_id xcurrent_context_this_table; static context_id xcurrent_context; static std::deque<scope_id> scope_stack; symbol_table (void) - : table_name (), table (), xcurrent_context_this_table () { } + : table_name (), table () { } ~symbol_table (void) { } @@ -2025,16 +2015,12 @@ void do_push_context (void) { - xcurrent_context = ++xcurrent_context_this_table; - for (table_iterator p = table.begin (); p != table.end (); p++) p->second.push_context (); } void do_pop_context (void) { - xcurrent_context = --xcurrent_context_this_table; - for (table_iterator p = table.begin (); p != table.end (); ) { if (p->second.pop_context () == 0)
--- a/src/toplev.cc +++ b/src/toplev.cc @@ -167,6 +167,43 @@ return retval; } +size_t +octave_call_stack::do_num_user_code_frames (octave_idx_type& curr_user_frame) const +{ + size_t retval = 0; + + curr_user_frame = 0; + + // Look for the caller of dbstack. + size_t frame = cs[curr_frame].prev; + + bool found = false; + + size_t k = cs.size (); + + for (const_reverse_iterator p = cs.rbegin (); p != cs.rend (); p++) + { + octave_function *f = (*p).fcn; + + if (--k == frame) + found = true; + + if (f && f->is_user_code ()) + { + if (! found) + curr_user_frame++; + + retval++; + } + } + + // We counted how many user frames were not the one, in reverse. + // Now set curr_user_frame to be the index in the other direction. + curr_user_frame = retval - curr_user_frame - 1; + + return retval; +} + octave_user_script * octave_call_stack::do_caller_user_script (difference_type q) const { @@ -237,72 +274,76 @@ } Octave_map -octave_call_stack::do_backtrace (int nframes) const +octave_call_stack::do_backtrace (size_t nskip, + octave_idx_type& curr_user_frame) const { Octave_map retval; - if (nframes > 0 && nframes <= cs.size ()) - { - Cell keys (6, 1); + size_t user_code_frames = do_num_user_code_frames (curr_user_frame); + + size_t nframes = nskip <= user_code_frames ? user_code_frames - nskip : 0; - keys(0) = "file"; - keys(1) = "name"; - keys(2) = "line"; - keys(3) = "column"; - keys(4) = "scope"; - keys(5) = "context"; + // Our list is reversed. + curr_user_frame = nframes - curr_user_frame - 1; + + Cell keys (6, 1); - Cell file (nframes, 1); - Cell name (nframes, 1); - Cell line (nframes, 1); - Cell column (nframes, 1); - Cell scope (nframes, 1); - Cell context (nframes, 1); - - octave_idx_type k = nframes - 1; + keys(0) = "file"; + keys(1) = "name"; + keys(2) = "line"; + keys(3) = "column"; + keys(4) = "scope"; + keys(5) = "context"; - const_iterator p = cs.begin (); + Cell file (nframes, 1); + Cell name (nframes, 1); + Cell line (nframes, 1); + Cell column (nframes, 1); + Cell scope (nframes, 1); + Cell context (nframes, 1); - while (k >= 0) + if (nframes > 0) + { + int k = 0; + + for (const_reverse_iterator p = cs.rbegin (); p != cs.rend (); p++) { - const call_stack_elt& elt = *p++; - - scope(k) = elt.scope; - context(k) = elt.context; + const call_stack_elt& elt = *p; octave_function *f = elt.fcn; - if (f) + if (f && f->is_user_code ()) { - file(k) = f->fcn_file_name (); - std::string parent_fcn_name = f->parent_fcn_name (); - if (parent_fcn_name == std::string ()) - name(k) = f->name (); - else - name(k) = f->parent_fcn_name () + Vfilemarker + f->name (); - - tree_statement *stmt = elt.stmt; - - if (stmt) - { - line(k) = stmt->line (); - column(k) = stmt->column (); - } + if (nskip > 0) + nskip--; else { - line(k) = -1; - column(k) = -1; + scope(k) = elt.scope; + context(k) = elt.context; + + file(k) = f->fcn_file_name (); + std::string parent_fcn_name = f->parent_fcn_name (); + if (parent_fcn_name == std::string ()) + name(k) = f->name (); + else + name(k) = f->parent_fcn_name () + Vfilemarker + f->name (); + + tree_statement *stmt = elt.stmt; + + if (stmt) + { + line(k) = stmt->line (); + column(k) = stmt->column (); + } + else + { + line(k) = -1; + column(k) = -1; + } + + k++; } } - else - { - file(k) = "<unknown>"; - name(k) = "<unknown>"; - line(k) = -1; - column(k) = -1; - } - - k--; } retval.assign ("file", file); @@ -356,26 +397,126 @@ } bool -octave_call_stack::do_goto_frame_relative (int n, bool verbose) +octave_call_stack::do_goto_frame_relative (int nskip, bool verbose) { bool retval = false; - size_t sz = cs.size (); - - if (n == 0) + if (nskip == 0) retval = true; else { - size_t frame = static_cast<size_t> (n) + curr_frame; + int incr = nskip < 0 ? -1 : 1; + + // Start looking with the caller of dbup/dbdown. + size_t frame = cs[curr_frame].prev; + + while (true) + { + if ((incr < 0 && frame == 0) || (incr > 0 && frame == cs.size () - 1)) + break; + + frame += incr; + + const call_stack_elt& elt = cs[frame]; + + octave_function *f = elt.fcn; + + if (f && f->is_user_code ()) + { + if (nskip > 0) + nskip--; + else if (nskip < 0) + nskip++; + + if (nskip == 0) + { + curr_frame = frame; + cs[cs.size () - 1].prev = curr_frame; - if ((n > 0 && frame < sz) || (n < 0 && frame >= 0)) - retval = goto_frame (frame, verbose); + if (verbose) + { + tree_statement *s = elt.stmt; + int l = -1; + int c = -1; + if (s) + { + l = s->line (); + c = s->column (); + } + + std::ostringstream buf; + buf << f->name () << ": " << " line " << l + << ", column " << c << std::endl; + + octave_stdout << buf.str (); + } + + retval = true; + break; + } + } + } + + // There is no need to set scope and context here. That will + // happen when the dbup/dbdown frame is popped and we jump to + // the new "prev" frame set above. } return retval; } void +octave_call_stack::do_goto_caller_frame (void) +{ + size_t frame = curr_frame; + + bool skipped = false; + + while (frame != 0) + { + frame = cs[frame].prev; + + const call_stack_elt& elt = cs[frame]; + + octave_function *f = elt.fcn; + + if (f && f->is_user_code ()) + { + if (! skipped) + // We found the current user code frame, so skip it. + skipped = true; + else + { + // We found the caller user code frame. + call_stack_elt tmp (elt); + tmp.prev = curr_frame; + + curr_frame = cs.size (); + + cs.push_back (tmp); + + symbol_table::set_scope_and_context (tmp.scope, tmp.context); + + break; + } + } + } +} + +void +octave_call_stack::do_goto_base_frame (void) +{ + call_stack_elt tmp (cs[0]); + tmp.prev = curr_frame; + + curr_frame = cs.size (); + + cs.push_back (tmp); + + symbol_table::set_scope_and_context (tmp.scope, tmp.context); +} + +void recover_from_exception (void) { can_interrupt = true;
--- a/src/toplev.h +++ b/src/toplev.h @@ -77,13 +77,18 @@ struct call_stack_elt { call_stack_elt (octave_function *f, symbol_table::scope_id s, - symbol_table::context_id c) - : fcn (f), stmt (0), scope (s), context (c) { } + symbol_table::context_id c, size_t p = 0) + : fcn (f), stmt (0), scope (s), context (c), prev (p) { } + + call_stack_elt (const call_stack_elt& elt) + : fcn (elt.fcn), stmt (elt.stmt), scope (elt.scope), + context (elt.context), prev (elt.prev) { } octave_function *fcn; tree_statement *stmt; symbol_table::scope_id scope; symbol_table::context_id context; + size_t prev; }; protected: @@ -94,6 +99,10 @@ typedef std::deque<call_stack_elt>::iterator iterator; typedef std::deque<call_stack_elt>::const_iterator const_iterator; + + typedef std::deque<call_stack_elt>::reverse_iterator reverse_iterator; + typedef std::deque<call_stack_elt>::const_reverse_iterator const_reverse_iterator; + typedef std::deque<call_stack_elt>::difference_type difference_type; static bool instance_ok (void) @@ -159,6 +168,22 @@ return instance_ok () ? instance->do_size () : 0; } + static size_t num_user_code_frames (octave_idx_type& curr_user_frame) + { + return instance_ok () + ? instance->do_num_user_code_frames (curr_user_frame) : 0; + } + + static symbol_table::scope_id current_scope (void) + { + return instance_ok () ? instance->do_current_scope () : 0; + } + + static symbol_table::context_id current_context (void) + { + return instance_ok () ? instance->do_current_context () : 0; + } + // Function at location N on the call stack (N == 0 is current), may // be built-in. static octave_function *element (size_t n) @@ -187,7 +212,7 @@ static void push (octave_function *f, symbol_table::scope_id scope = symbol_table::current_scope (), - symbol_table::context_id context = 0) + symbol_table::context_id context = symbol_table::current_context ()) { if (instance_ok ()) instance->do_push (f, scope, context); @@ -220,9 +245,22 @@ ? instance->do_goto_frame_relative (n, verbose) : false; } - static Octave_map backtrace (int n = 0) + static void goto_caller_frame (void) + { + if (instance_ok ()) + instance->do_goto_caller_frame (); + } + + static void goto_base_frame (void) { - return instance_ok () ? instance->do_backtrace (n) : Octave_map (); + if (instance_ok ()) + instance->do_goto_base_frame (); + } + + static Octave_map backtrace (size_t nskip, octave_idx_type& curr_user_frame) + { + return instance_ok () + ? instance->do_backtrace (nskip, curr_user_frame) : Octave_map (); } static void pop (void) @@ -262,6 +300,20 @@ size_t do_size (void) { return cs.size (); } + size_t do_num_user_code_frames (octave_idx_type& curr_user_frame) const; + + symbol_table::scope_id do_current_scope (void) const + { + return curr_frame > 0 && curr_frame < cs.size () + ? cs[curr_frame].scope : 0; + } + + symbol_table::context_id do_current_context (void) const + { + return curr_frame > 0 && curr_frame < cs.size () + ? cs[curr_frame].context : 0; + } + octave_function *do_element (size_t n) { octave_function *retval = 0; @@ -284,9 +336,10 @@ void do_push (octave_function *f, symbol_table::scope_id scope, symbol_table::context_id context) { - curr_frame++; - - cs.push_back (call_stack_elt (f, scope, context)); + size_t prev_frame = curr_frame; + curr_frame = cs.size (); + cs.push_back (call_stack_elt (f, scope, context, prev_frame)); + symbol_table::set_scope_and_context (scope, context); } octave_function *do_top (void) const @@ -320,24 +373,30 @@ if (! cs.empty ()) { call_stack_elt& elt = cs.back (); - elt.stmt = s; } } - Octave_map do_backtrace (int n) const; + Octave_map do_backtrace (size_t nskip, + octave_idx_type& curr_user_frame) const; bool do_goto_frame (size_t n, bool verbose); bool do_goto_frame_relative (int n, bool verbose); + void do_goto_caller_frame (void); + + void do_goto_base_frame (void); + void do_pop (void) { - if (! cs.empty ()) + if (cs.size () > 1) { - curr_frame--; - + const call_stack_elt& elt = cs.back (); + curr_frame = elt.prev; cs.pop_back (); + const call_stack_elt& new_elt = cs[curr_frame]; + symbol_table::set_scope_and_context (new_elt.scope, new_elt.context); } }