aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2011-03-31 07:31:14 +0200
committerBjörn Gustavsson <[email protected]>2011-08-16 08:58:47 +0200
commite0fe23461cc94a80e02a9542ab2182f62badd5de (patch)
tree2ec0499d0b23c64d88880eb1c8e8c8830dfce8ea /lib
parent3ccc4730e54f0f9e86bf96360b7600ab8c9e1d47 (diff)
downloadotp-e0fe23461cc94a80e02a9542ab2182f62badd5de.tar.gz
otp-e0fe23461cc94a80e02a9542ab2182f62badd5de.tar.bz2
otp-e0fe23461cc94a80e02a9542ab2182f62badd5de.zip
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.
Diffstat (limited to 'lib')
-rw-r--r--lib/debugger/src/dbg_debugged.erl13
-rw-r--r--lib/debugger/src/dbg_ieval.erl38
-rw-r--r--lib/debugger/src/dbg_istk.erl34
3 files changed, 57 insertions, 28 deletions
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] ->