Mark, I know that you keep saying this. I remember you told me this even when I was sitting on a RELEASE_ASSERT that had gotten rage-coalesced.
Your reasoning sounds great, but this just isn't what happens in clang. __builtin_trap gets coalesced, as does inline asm. -Filip > On Feb 22, 2017, at 12:38 PM, Mark Lam <mark....@apple.com> wrote: > > For some context, we used to see aggregation of the CRASH() for > RELEASE_ASSERT() in the old days before we switched to using the int3 trap. > Back then we called a crash() function that never returns. As a result, the > C++ compiler was able to coalesce all the calls. With the int3 trap emitted > by inline asm, the C++ compiler has less ability to determine that the crash > sites have the same code (probably because it doesn’t bother comparing what’s > in the inline asm blobs). > > Mark > > >> On Feb 22, 2017, at 12:33 PM, Mark Lam <mark....@apple.com >> <mailto:mark....@apple.com>> wrote: >> >>> >>> On Feb 22, 2017, at 12:16 PM, Filip Pizlo <fpi...@apple.com >>> <mailto:fpi...@apple.com>> wrote: >>> >>> >>>> On Feb 22, 2017, at 11:58 AM, Geoffrey Garen <gga...@apple.com >>>> <mailto:gga...@apple.com>> wrote: >>>> >>>> I’ve lost countless hours to investigating CrashTracers that would have >>>> been easy to solve if I had access to register state. >>> >>> The current RELEASE_ASSERT means that every assertion in what the compiler >>> thinks is a function (i.e. some function and everything inlined into it) is >>> coalesced into a single trap site. I’d like to understand how you use the >>> register state if you don’t even know which assertion you are at. >> >> Correction: they are not coalesced. I was mistaken about that. The fact >> that we turn them into inline asm (for emitting the int3) means the compiler >> cannot optimize it away or coalesce it. The compiler does move it to the >> end of the emitted code for the function though because we end the CRASH() >> macro with __builtin_unreachable(). >> >> Hence, each int3 can be correlated back to the RELEASE_ASSERT that triggered >> it (with some extended disassembly work). >> >>> I believe that if you do want to analyze register state, then switching >>> back to calling some function that prints out diagnostic information is >>> strictly better. Sure, you get less register state, but at least you know >>> where you crashed. Knowing where you crashed is much more important than >>> knowing the register state, since the register state is not useful if you >>> don’t know where you crashed. >>> >> >> I would like to point out that we might be able to get the best of both >> worlds. Here’s how we can do it: >> >> define RELEASE_ASSERT(assertion) do { \ >> if (UNLIKELY(!(assertion))) { \ >> preserveRegisterState(); \ >> WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, >> #assertion); \ >> restoreRegisterState(); \ >> CRASH(); \ >> } \ >> >> preserveRegisterState() and restoreRegisterState() will carefully push and >> pop registers onto / off the stack (like how the JIT probe works). >> This allows us to get a log message on the terminal when we’re running >> manually. >> >> In addition, we can capture some additional information about the assertion >> site by forcing the compiler to emit code to capture the code location info >> after the trapping instruction. This is redundant but provides an easy >> place to find this info (i.e. after the int3 instruction). >> >> #define WTFBreakpointTrap() do { \ >> __asm__ volatile ("int3"); \ >> __asm__ volatile( "" : : "r"(__FILE__), "r"(__LINE__), >> "r"(WTF_PRETTY_FUNCTION)); \ >> } while (false) >> >> We can easily get the line number this way. However, the line number is not >> very useful by itself when we have inlining. Hence, I also capture the >> __FILE__ and WTF_PRETTY_FUNCTION. However, I haven’t been able to figure >> out how to decode those from the otool disassembler yet. >> >> The only downside of doing this extra work is that it increases the code >> size for each RELEASE_ASSERT site. This is probably insignificant in total. >> >> Performance-wise, it should be neutral-ish because the >> __builtin_unreachable() in the CRASH() macro + the UNLIKELY() macro would >> tell the compiler to put this in a slow path away from the main code path. >> >> Any thoughts on this alternative? >> >> Mark >> >> >>>> >>>> I also want the freedom to add RELEASE_ASSERT without ruining performance >>>> due to bad register allocation or making the code too large to inline. For >>>> example, hot paths in WTF::Vector use RELEASE_ASSERT. >>> >>> Do we have data about the performance benefits of the current >>> RELEASE_ASSERT implementation? >>> >>>> >>>> Is some compromise solution possible? >>>> >>>> Some options: >>>> >>>> (1) Add a variant of RELEASE_ASSERT that takes a string and logs. >>> >>> The point of C++ assert macros is that I don’t have to add a custom string. >>> I want a RELEASE_ASSERT macro that automatically stringifies the >>> expression and uses that as the string. >>> >>> If I had a choice between a RELEASE_ASSERT that can accurate report where >>> it crashed but sometimes trashes the register state, and a RELEASE_ASSERT >>> that always gives me the register state but cannot tell me which assert in >>> the function it’s coming from, then I would always choose the one that can >>> tell me where it crashed. That’s much more important, and the register >>> state is not useful without that information. >>> >>>> >>>> (2) Change RELEASE_ASSERT to do the normal debug ASSERT thing in Debug >>>> builds. (There’s not much need to preserve register state in debug builds.) >>> >>> That would be nice, but doesn’t make RELEASE_ASSERT useful for debugging >>> issues where timing is important. I no longer use RELEASE_ASSERTS for >>> those kinds of assertions, because if I do it then I will never know where >>> I crashed. So, I use the explicit: >>> >>> if (!thing) { >>> dataLog(“…”); >>> RELEASE_ASSERT_NOT_REACHED(); >>> } >>> >>> -Filip >>> >>> >>>> >>>> Geoff >>>> >>>>> On Feb 22, 2017, at 11:09 AM, Filip Pizlo <fpi...@apple.com >>>>> <mailto:fpi...@apple.com>> wrote: >>>>> >>>>> I disagree actually. I've lost countless hours to converting this: >>>>> >>>>> RELEASE_ASSERT(blah) >>>>> >>>>> into this: >>>>> >>>>> if (!blah) { >>>>> dataLog("Reason why I crashed"); >>>>> RELEASE_ASSERT_NOT_REACHED(); >>>>> } >>>>> >>>>> Look in the code - you'll find lots of stuff like this. >>>>> >>>>> I don't think analyzing register state at crashes is more important than >>>>> keeping our code sane. >>>>> >>>>> -Filip >>>>> >>>>> >>>>>> On Feb 21, 2017, at 5:56 PM, Mark Lam <mark....@apple.com >>>>>> <mailto:mark....@apple.com>> wrote: >>>>>> >>>>>> Oh yeah, I forgot about that. I think the register state is more >>>>>> important for crash analysis, especially if we can make sure that the >>>>>> compiler does not aggregate the int3s. I’ll explore alternatives. >>>>>> >>>>>>> On Feb 21, 2017, at 5:54 PM, Saam barati <sbar...@apple.com >>>>>>> <mailto:sbar...@apple.com>> wrote: >>>>>>> >>>>>>> I thought the main point of moving to SIGTRAP was to preserve register >>>>>>> state? >>>>>>> >>>>>>> That said, there are probably places where we care more about the >>>>>>> message than the registers. >>>>>>> >>>>>>> - Saam >>>>>>> >>>>>>>> On Feb 21, 2017, at 5:43 PM, Mark Lam <mark....@apple.com >>>>>>>> <mailto:mark....@apple.com>> wrote: >>>>>>>> >>>>>>>> Is there a reason why RELEASE_ASSERT (and friends) does not call >>>>>>>> WTFReportAssertionFailure() to report where the assertion occur? Is >>>>>>>> this purely to save memory? svn blame tells me that it has been this >>>>>>>> way since the introduction of RELEASE_ASSERT in r140577 many years ago. >>>>>>>> >>>>>>>> Would anyone object to adding a call to WTFReportAssertionFailure() in >>>>>>>> RELEASE_ASSERT() like we do for ASSERT()? One of the upside >>>>>>>> (side-effect) of adding this call is that it appears to stop the >>>>>>>> compiler from aggregating all the RELEASE_ASSERTS into a single code >>>>>>>> location, and this will help with post-mortem crash debugging. >>>>>>>> >>>>>>>> Any thoughts? >>>>>>>> >>>>>>>> Mark >>>>>>>> >>>>>>>> _______________________________________________ >>>>>>>> webkit-dev mailing list >>>>>>>> webkit-dev@lists.webkit.org <mailto:webkit-dev@lists.webkit.org> >>>>>>>> https://lists.webkit.org/mailman/listinfo/webkit-dev >>>>>>>> <https://lists.webkit.org/mailman/listinfo/webkit-dev> >>>>>>> >>>>>> >>>>>> _______________________________________________ >>>>>> webkit-dev mailing list >>>>>> webkit-dev@lists.webkit.org <mailto:webkit-dev@lists.webkit.org> >>>>>> https://lists.webkit.org/mailman/listinfo/webkit-dev >>>>>> <https://lists.webkit.org/mailman/listinfo/webkit-dev> >>>>> >>>>> _______________________________________________ >>>>> webkit-dev mailing list >>>>> webkit-dev@lists.webkit.org <mailto:webkit-dev@lists.webkit.org> >>>>> https://lists.webkit.org/mailman/listinfo/webkit-dev >>>>> <https://lists.webkit.org/mailman/listinfo/webkit-dev> >>>> >>> >> >> _______________________________________________ >> webkit-dev mailing list >> webkit-dev@lists.webkit.org <mailto:webkit-dev@lists.webkit.org> >> https://lists.webkit.org/mailman/listinfo/webkit-dev >> <https://lists.webkit.org/mailman/listinfo/webkit-dev>
_______________________________________________ webkit-dev mailing list webkit-dev@lists.webkit.org https://lists.webkit.org/mailman/listinfo/webkit-dev