Skip to content

Improve consistency of backtraces between flambda and non-flambda modes#739

Closed
mshinwell wants to merge 5 commits intoocaml:4.04from
mshinwell:tail_call_backtraces
Closed

Improve consistency of backtraces between flambda and non-flambda modes#739
mshinwell wants to merge 5 commits intoocaml:4.04from
mshinwell:tail_call_backtraces

Conversation

@mshinwell
Copy link
Copy Markdown
Contributor

Backtraces on 4.04 are currently rather inconsistent between flambda and non-flambda modes. This causes a significant amount of trouble when using expect-tests or similar to check the output of programs.

It is proposed (after discussion with @let-def who wrote the inlined frames support) in this pull request to do the following:

  1. Remove the "(inlined)" annotations on printed backtraces. This should remove a significant source of inconsistency. The annotations don't seem that useful: in particular, if people want to debug the inliner, they should use the inlining reports instead.
  2. Stop adding inlined frames for function calls that are syntactically in tail-position during the middle end. This subtlety is probably the cause of rather a lot of inconsistency (of a particularly problematic nature since it actually changes the number of frames in the backtrace): flambda is far more likely to inline such calls. Not having frames for tail calls should match up with general expectations about backtraces.

This probably won't remove all of the inconsistencies, but should bring things significantly closer together than they are now.

This is work in progress, although should be finished soon. @let-def is going to contribute the equivalent code for Closure.

@mshinwell mshinwell added this to the 4.04 milestone Aug 3, 2016
@chambart
Copy link
Copy Markdown
Contributor

chambart commented Aug 3, 2016

I found that having the whole life of an expression is quite an useful tool when looking at -dflambda (and probably for gdb too). Would you consider it right to always call set_inline_debuginfo , but mark whether it was in tail position to avoid adding it to the stack trace ?

@mshinwell
Copy link
Copy Markdown
Contributor Author

@chambart Seems like a good idea, I tried to implement it. Please have another look.

else (item_from_location loc) :: t

let mark_as_tail_call t =
List.map (fun item -> { item with dinfo_is_tail_call = true; }) t
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this mark only the top location (which is the original location of the apply expression) as tail rather than all ?

@chambart
Copy link
Copy Markdown
Contributor

The tail field of the environment should be set to true inside the body of an inline expression, otherwise, if a function is inlined in non tail position containing a tail call to another one which is also inlined when the first one is, then that tail call will be considered not tail.

This is probably clearer with an example:

let tail_called b =
  if b then (big expression wich prevent inlining)
  raise Exit

let non_tail_called b =
  tail_called b

let () =
  try non_tail_called false with e -> raise e

If inlining non_tail_called trigger the inlining of tail_called then the call to tail_called will be considered non-tail.

For some more complex situations, non_tail_called could be inlined at the first round while tail_called would be during the second. In that case we wouldn't have any information left telling that the application was in tail position. This probably means that the only way to remember that is to annotate the Apply expression with the original tail information. This annotation should be added by closure_conversion.

@mshinwell
Copy link
Copy Markdown
Contributor Author

@chambart Thanks for spending time on this. I spoke to @let-def this morning having considered your comments. I'm concerned that we're not actually going to be able to pin down a reasonable semantics for this and that in fact it may, on balance, not be worth adding this extra code to the compiler at all. (Factors such as optimisations within Flambda turning non-tail calls into tail calls, the various tricky things about inlining as @chambart mentions, the fact that we don't know until well into the backend whether a particular call will actually be tail or not, etc.) I don't think we should add this code if it's going to be fragile and/or hard to understand, which I am now suspecting it might be. Instead, we should discourage the matching in tests on explicit backtraces in almost all cases, on the basis of it being a quality of implementation feature rather than a prescribed language semantics.

@mshinwell mshinwell removed this from the 4.04 milestone Sep 7, 2016
@damiendoligez damiendoligez added this to the 4.05-or-later milestone Sep 29, 2016
@mshinwell
Copy link
Copy Markdown
Contributor Author

I think we decided not to proceed with this.

@mshinwell mshinwell closed this Dec 9, 2016
EduardoRFS pushed a commit to esy-ocaml/ocaml that referenced this pull request Dec 17, 2021
stedolan pushed a commit to stedolan/ocaml that referenced this pull request Sep 21, 2022
EmileTrotignon pushed a commit to EmileTrotignon/ocaml that referenced this pull request Jan 12, 2024
Co-authored-by: Cuihtlauac ALVARADO <cuihtmlauac@tarides.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants