From e0fe23461cc94a80e02a9542ab2182f62badd5de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 31 Mar 2011 07:31:14 +0200 Subject: Don't build stacktrace until erlang:get_stacktrace() is called Currently, dbg_istk:exception_stacktrace/2 does not do a very good job imitating BEAM's stacktrace. The reason is that it need to be relatively fast since a simulated stacktrace is constructed not only when an exception oocurs, but also before every call to non-interpreted code. To prepare for a future more thorough (and slower) stacktrace construction, refactor the building of the stacktrace so that it only is done when erlang:get_stacktrace/0 is called. --- lib/debugger/src/dbg_debugged.erl | 13 +++++++------ lib/debugger/src/dbg_ieval.erl | 38 +++++++++++++++++++++++++++++--------- lib/debugger/src/dbg_istk.erl | 34 +++++++++++++++++++++------------- 3 files changed, 57 insertions(+), 28 deletions(-) (limited to 'lib/debugger/src') diff --git a/lib/debugger/src/dbg_debugged.erl b/lib/debugger/src/dbg_debugged.erl index 3732c40c73..76ed49fa93 100644 --- a/lib/debugger/src/dbg_debugged.erl +++ b/lib/debugger/src/dbg_debugged.erl @@ -76,8 +76,8 @@ msg_loop(Meta, Mref, SaveStacktrace) -> msg_loop(Meta, Mref, SaveStacktrace); %% Meta needs something evaluated within context of real process - {sys, Meta, {command, Command, Stacktrace}} -> - Reply = handle_command(Command, Stacktrace), + {sys, Meta, {command,Command}} -> + Reply = handle_command(Command), Meta ! {sys, self(), Reply}, msg_loop(Meta, Mref, SaveStacktrace); @@ -93,11 +93,12 @@ msg_loop(Meta, Mref, SaveStacktrace) -> end end. -handle_command(Command, Stacktrace) -> - try reply(Command) +handle_command(Command) -> + try + reply(Command) catch Class:Reason -> - Stacktrace2 = stacktrace_f(erlang:get_stacktrace()), - {exception, {Class,Reason,Stacktrace2++Stacktrace}} + Stacktrace = stacktrace_f(erlang:get_stacktrace()), + {exception,{Class,Reason,Stacktrace}} end. reply({apply,M,F,As}) -> diff --git a/lib/debugger/src/dbg_ieval.erl b/lib/debugger/src/dbg_ieval.erl index 445eba3346..fe7f9af1a9 100644 --- a/lib/debugger/src/dbg_ieval.erl +++ b/lib/debugger/src/dbg_ieval.erl @@ -168,7 +168,7 @@ check_exit_msg(_Msg, _Bs, _Ieval) -> %% and then raise the exception. %%-------------------------------------------------------------------- exception(Class, Reason, Bs, Ieval) -> - exception(Class, Reason, dbg_istk:exception_stacktrace(complete, Ieval), + exception(Class, Reason, dbg_istk:delayed_stacktrace(Ieval), Bs, Ieval). exception(Class, Reason, Stacktrace, Bs, #ieval{module=M, line=Line}) -> @@ -226,8 +226,7 @@ meta(Int, Debugged, M, F, As) -> debugged_cmd(Cmd, Bs, Ieval) -> Debugged = get(self), - Stacktrace = dbg_istk:exception_stacktrace(no_current, Ieval), - Debugged ! {sys, self(), {command,Cmd,Stacktrace}}, + Debugged ! {sys, self(), {command,Cmd}}, meta_loop(Debugged, Bs, Ieval). meta_loop(Debugged, Bs, #ieval{level=Le} = Ieval) -> @@ -240,12 +239,17 @@ meta_loop(Debugged, Bs, #ieval{level=Le} = Ieval) -> {value, Val, Bs}; {sys, Debugged, {value,Val,Bs2}} -> {value, Val, Bs2}; - {sys, Debugged, {exception,{Class,Reason,Stacktrace}}} -> + {sys, Debugged, {exception,{Class,Reason,Stk}}} -> case get(exit_info) of - %% Error occured outside interpreted code + %% Error occurred outside of interpreted code. undefined -> - exception(Class,Reason,Stacktrace,Bs,Ieval); + MakeStk0 = dbg_istk:delayed_stacktrace(), + MakeStk = fun(Depth0) -> + Depth = max(0, Depth0 - length(Stk)), + Stk ++ MakeStk0(Depth) + end, + exception(Class, Reason, MakeStk, Bs, Ieval); %% Error must have occured within a re-entry to %% interpreted code, simply raise the exception @@ -370,7 +374,7 @@ format_args1([]) -> %% Mimic catch behaviour catch_value(error, Reason) -> - {'EXIT',{Reason,get(stacktrace)}}; + {'EXIT',{Reason,get_stacktrace()}}; catch_value(exit, Reason) -> {'EXIT',Reason}; catch_value(throw, Reason) -> @@ -395,7 +399,7 @@ eval_mfa(Debugged, M, F, As, #ieval{level=Le}=Ieval0) -> exit:{Int, Reason} -> exit(Reason); Class:Reason -> - {exception, {Class, Reason, get(stacktrace)}} + {exception, {Class, Reason, get_stacktrace()}} end. eval_function(Mod, Name, As, Bs, Called, Ieval0) -> @@ -782,7 +786,7 @@ expr({dbg,Line,self,[]}, Bs, #ieval{level=Le}) -> {value,Self,Bs}; expr({dbg,Line,get_stacktrace,[]}, Bs, #ieval{level=Le}) -> trace(bif, {Le,Line,erlang,get_stacktrace,[]}), - Stacktrace = get(stacktrace), + Stacktrace = get_stacktrace(), trace(return, {Le,Stacktrace}), {value,Stacktrace,Bs}; expr({dbg,Line,throw,As0}, Bs0, #ieval{level=Le}=Ieval0) -> @@ -1501,3 +1505,19 @@ add_binding(N,Val,[B1|Bs]) -> [B1|add_binding(N,Val,Bs)]; add_binding(N,Val,[]) -> [{N,Val}]. + +%% get_stacktrace() -> Stacktrace +%% Return the latest stacktrace for the process. +get_stacktrace() -> + case get(stacktrace) of + MakeStk when is_function(MakeStk, 1) -> + %% The stacktrace has not been constructed before. + %% Construct it and remember the result. + Depth = erlang:system_flag(backtrace_depth, 8), + erlang:system_flag(backtrace_depth, Depth), + Stk = MakeStk(Depth), + put(stacktrace, Stk), + Stk; + Stk when is_list(Stk) -> + Stk + end. diff --git a/lib/debugger/src/dbg_istk.erl b/lib/debugger/src/dbg_istk.erl index 2e7b114fab..2c4c2a3518 100644 --- a/lib/debugger/src/dbg_istk.erl +++ b/lib/debugger/src/dbg_istk.erl @@ -19,7 +19,7 @@ -module(dbg_istk). -export([init/0,to_external/0,from_external/1, push/2,pop/0,pop/1,stack_level/0, - exception_stacktrace/2, + delayed_stacktrace/0,delayed_stacktrace/1, bindings/1,stack_frame/2,backtrace/2, in_use_p/2]). @@ -106,25 +106,33 @@ stack_level() -> stack_level([]) -> 1; stack_level([#e{level=Le}|_]) -> Le. -%% exception_stacktrace(HowMuch, #ieval{}) -> Stacktrace -%% HowMuch = complete | no_current -%% Stacktrace = [{M,F,Args|Arity} | {Fun,Args}] -%% Convert internal stack format to an imitation of the -%% regular stacktrace. +%% delayed_stacktrace() -> CreateStacktraceFun +%% delayed_stacktrace(#ieval{}) -> CreateStacktraceFun +%% CreateStacktraceFun = fun(NumberOfEntries) +%% +%% Return a fun that can convert the internal stack format to +%% an imitation of the regular stacktrace. %% %% Max three elements, no repeated (recursive) calls to the same %% function and convert argument lists to arity for all but the topmost %% entry (and funs). -exception_stacktrace(complete, #ieval{}=Ieval) -> +delayed_stacktrace() -> + Stack = get(?STACK), + do_delayed_stacktrace(Stack). + +delayed_stacktrace(Ieval) -> #ieval{module=Mod,function=Name,arguments=As} = Ieval, - Stk = [#e{mfa={Mod,Name,As}}|get(?STACK)], - fix_stacktrace(Stk); -exception_stacktrace(no_current, #ieval{}) -> - fix_stacktrace(get(?STACK)). + Stack = [#e{mfa={Mod,Name,As}}|get(?STACK)], + do_delayed_stacktrace(Stack). + +do_delayed_stacktrace(Stack) -> + fun(_NumEntries) -> + fix_stacktrace(Stack) + end. -fix_stacktrace(Stk) -> - case fix_stacktrace2(sublist(Stk, 1, 3)) of +fix_stacktrace(Stack) -> + case fix_stacktrace2(sublist(Stack, 1, 3)) of [] -> []; [H|T] -> -- cgit v1.2.3