> On Feb 22, 2017, at 12:41 PM, Mark Lam <[email protected]> wrote:
>
>>
>> On Feb 22, 2017, at 12:35 PM, Filip Pizlo <[email protected]
>> <mailto:[email protected]>> wrote:
>>
>>>
>>> On Feb 22, 2017, at 12:33 PM, Mark Lam <[email protected]
>>> <mailto:[email protected]>> wrote:
>>>
>>>
>>>> On Feb 22, 2017, at 12:16 PM, Filip Pizlo <[email protected]
>>>> <mailto:[email protected]>> wrote:
>>>>
>>>>
>>>>> On Feb 22, 2017, at 11:58 AM, Geoffrey Garen <[email protected]
>>>>> <mailto:[email protected]>> 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).
>>
>> This never works for me. I tested it locally. LLVM will even coalesce
>> similar inline assembly.
>
> With my proposal, I’m emitting different inline asm now after the int3 trap
> because I’m embedding line number and file strings. Hence, even if the
> compiler is smart enough to compare inline asm code blobs, it will find them
> to be different, and hence, it doesn’t make sense to coalesce.
Are you claiming that LLVM does not currently now coalesce RELEASE_ASSERTS, or
that it will not coalesce them anymore after you make some change?
>
>>
>>>
>>>> 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).
>>
>> Why not do the preserve/restore inside the WTFReport call?
>
> Because I would like to preserve the register values that were used in the
> comparison that failed the assertion.
That doesn't change anything. You can create a WTFFail that is written in
assembly and first saves all registers, and restores them prior to trapping.
-Filip
>
> Mark
>
>>
>>> 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 <[email protected]
>>>>>> <mailto:[email protected]>> 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 <[email protected]
>>>>>>> <mailto:[email protected]>> 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 <[email protected]
>>>>>>>> <mailto:[email protected]>> 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 <[email protected]
>>>>>>>>> <mailto:[email protected]>> 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
>>>>>>>>> [email protected] <mailto:[email protected]>
>>>>>>>>> https://lists.webkit.org/mailman/listinfo/webkit-dev
>>>>>>>>> <https://lists.webkit.org/mailman/listinfo/webkit-dev>
>>>>>>>>
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> webkit-dev mailing list
>>>>>>> [email protected] <mailto:[email protected]>
>>>>>>> https://lists.webkit.org/mailman/listinfo/webkit-dev
>>>>>>> <https://lists.webkit.org/mailman/listinfo/webkit-dev>
>>>>>>
>>>>>> _______________________________________________
>>>>>> webkit-dev mailing list
>>>>>> [email protected] <mailto:[email protected]>
>>>>>> https://lists.webkit.org/mailman/listinfo/webkit-dev
>>>>>> <https://lists.webkit.org/mailman/listinfo/webkit-dev>
_______________________________________________
webkit-dev mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-dev