<div dir="ltr">Currently a number of functions in phobos have a syntax such as:<div>'T enforce(T, Dg, string file = __FILE__, size_t line = __LINE__)'<br></div><div>so as to show informative messages when an exception is raised, etc.</div>
<div><br></div><div>There's a number of issues with this:</div><div><br></div><div>1) impossible to have variadic arguments with an extra file/line parameters at the end (unless one makes those file/line as compile time parameters but that makes template code bloat), which would be very useful for debugging</div>
<div><br></div><div>2) the context is limited to the calling function (ie top-most stack frame only)</div><div><br></div><div>3) the code is more complex than needs to be, especially when we need to forward those arguments (again, due to the stack trace being limited to top-most frame), as every intermediate function is involved in passing around those arguments, whereas ideally these should only occur in 1 location (eg, at the place responsible to handle an assert failure). Furthermore, if we later want to add more information to the context (eg __MODULE__,__FUNCTION__, __COLUMN__ or __ARGUMENTS__), we would have to refactor a lot of code. </div>
<div><br></div><div>4) this is possibly inefficient, as we're passing around potentially more parameters than needed.</div><div><br></div><div>----------------------------</div><div>What about the following instead:</div>
<div><br></div><div>A) implicit context parameters (eg: string file = __FILE__, size_t line = __LINE__) are no longer needed</div><div><br></div><div>B) whenever a stack trace is requested (eg upon an assertion failure, program crash or signal handler), call a unique getStackTrace function (that doesn't use the GC). This allows to show full stack trace (more depth), with potentially more info (eg showing module, function name, stringified arguments, etc). </div>
<div><br></div><div>C) when an exception is thrown (which may be caught later), we need to save the stack-trace as efficiently as possible (ie saving the stringified stack trace would be wasteful). On possibility would be to store an array of return addresses (given by C backtrace function), memoized using std.function.memoize. Another would be using a trie data structure, with the assumption that there's only a limited number of such execution paths whose stacktrace will be requested; this should be very efficient</div>
<div><br></div><div>D) For a simple implementation, getStackTrace can be based on C functions backtrace/backtrace_symbols but these are not very reliable depending on compiler/operating system/compile options: inlining, off-by-1, missing debug symbols, file base name but no full name, etc. There's also __builtin_return_address and 'llvm.returnaddress' Intrinsics that could be used.</div>
<div><br></div><div>So this could be improved with compiler support, introducing backtraceD / backtrace_symbolsD (D's equivalent of the existing backtrace / backtrace_symbols) that should work irrespective of OS/D compiler/inlining/compiler flags. In particular, when the compiler inlines:</div>
<div>'main > funInlined> fun' to 'main > fun', </div><div>it should still be possible to keep track of the intermediate source level function calls with proper book-keeping in the object file.</div>
<div><br></div></div>