mercredi 4 décembre 2019

std::mutex::lock() produces weird (and unnecessary) asm code

I was checking generated asm for some of my code and my eye caught some interesting stuff:

#include <mutex>

std::mutex m;

void foo()
{
    m.lock();
}

generated asm code (x86-64 gcc 9.2, -std=c++11 -O2):

foo():
        mov     eax, OFFSET FLAT:_ZL28__gthrw___pthread_key_createPjPFvPvE
        test    rax, rax
        je      .L10                  // (1) we can simply bypass lock() call?
        sub     rsp, 8
        mov     edi, OFFSET FLAT:m
        call    __gthrw_pthread_mutex_lock(pthread_mutex_t*)
        test    eax, eax
        jne     .L14                  // (2) waste of space that will never be executed
        add     rsp, 8
        ret
.L10:
        ret
.L14:
        mov     edi, eax
        call    std::__throw_system_error(int)
m:
        .zero   40

Questions:

  • part (1) -- gcc specific:
    • what it is doing? (allocating TLS entry?)
    • how failing that operation allows us to silently bypass lock() call?
  • part (2) -- looks like each compiler is affected:
    • std::mutex::lock() can throw according to standard
    • ... but it never does in correct code (as discussed in related SO posts), for all intents and purposes std::mutex::lock() is always noexcept in correct code
    • is it possible to let compiler know so that it stops emitting unnecessary tests and instruction blocks (like .L14 above)?

Note: I can't see how throwing from std::mutex::lock() is better than simply abort()ing. In both cases your program is screwed (no one expects it to fail), but at least in latter case you end up with considerably smaller asm code ("pay only for something you use", remember?).

Aucun commentaire:

Enregistrer un commentaire