[Development] User-defined literals for QString (and QByteArray)

Thiago Macieira thiago.macieira at intel.com
Wed Mar 3 20:56:43 CET 2021


On Wednesday, 3 March 2021 08:57:03 PST Giuseppe D'Angelo via Development 
wrote:
> > There's of course QStringLiteral:
> > QString hello = QStringLiteral("Hello"); // yay, it works
> > ... and, actually, QStringLiteral in Qt 6 is great, because it doesn't
> > allocate the memory* to store that literal.
> 
> Wasn't it the same in Qt 5 as well?

It's different.

In Qt 5, a QStringLiteral(x) allocated a block of 24 + sizeof(x) bytes rounded 
up to 8 bytes in read-only memory for your binary. Moreover, two 
QStringLiterals, even if identical, would expand to two different blocks. 
That's why we had things like:

https://code.woboq.org/qt5/qtbase/src/corelib/io/qurl.cpp.html#_ZL9ftpSchemev
https://code.woboq.org/qt5/qtbase/src/corelib/io/
qurl.cpp.html#_ZL10fileSchemev

In Qt 6, the macro is MUCH simpler because QString has changed. Now, we really 
refer to a plain UTF-16 string literal with no overhead. Whether two string 
literals are the same pointer or not is completely compiler-dependent.

For example, compiling the following code:
bool f() { return QStringLiteral("a") == QStringLiteral("a"); }

with GCC 10 at -O3 results in (comments mine):
.LC0:
        .string "a"
        .string ""
        .string ""
_Z1fv:
        leaq    .LC0(%rip), %rsi	; lhs.m_data = u"a"
        subq    $8, %rsp		; required for stack alignment
        movl    $1, %r8d		; cs = Qt::CaseSensitive
        movl    $1, %edx		; rhs.m_size = 1
        movq    %rsi, %rcx		; rhs.m_data = lhs.m_data
        movl    $1, %edi		; lhs.m_size = 1
        call    
_ZN9QtPrivate14compareStringsE11QStringViewS0_N2Qt15CaseSensitivityE at PLT
        testl   %eax, %eax
        sete    %al
        addq    $8, %rsp
        ret

Similar for Clang 11 at -O2. GCC at -O2 fails to constant-propagate the null 
pointers and keeps out-of-line calls to the QArrayDataPointer destructor.

Qt 5 version attached for reference if anyone wants to see it.
-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel DPG Cloud Engineering
-------------- next part --------------
f():
        pushq   %r12
        leaq    f()::{lambda()#2}::operator()() const::qstring_literal(%rip), %rax
        subq    $16, %rsp
        movq    %rax, 8(%rsp)
        movq    %rsp, %rdi
        leaq    f()::{lambda()#1}::operator()() const::qstring_literal(%rip), %rax
        leaq    8(%rsp), %rsi
        movq    %rax, (%rsp)
        call    operator==(QString const&, QString const&)@PLT
        movq    (%rsp), %rdi
        xorl    $1, %eax
        movl    %eax, %r12d
        movl    (%rdi), %eax
        testl   %eax, %eax
        je      .L6
        cmpl    $-1, %eax
        je      .L3
        lock decl       (%rdi)
        movq    (%rsp), %rdi
        je      .L6
.L3:
        movq    8(%rsp), %rdi
        movl    (%rdi), %eax
        testl   %eax, %eax
        je      .L11
.L7:
        cmpl    $-1, %eax
        je      .L1
        lock decl       (%rdi)
        movq    8(%rsp), %rdi
        je      .L11
.L1:
        addq    $16, %rsp
        movl    %r12d, %eax
        popq    %r12
        ret
.L6:
        movl    $8, %edx
        movl    $2, %esi
        call    QArrayData::deallocate(QArrayData*, unsigned long, unsigned long)@PLT
        movq    8(%rsp), %rdi
        movl    (%rdi), %eax
        testl   %eax, %eax
        jne     .L7
.L11:
        movl    $8, %edx
        movl    $2, %esi
        call    QArrayData::deallocate(QArrayData*, unsigned long, unsigned long)@PLT
        addq    $16, %rsp
        movl    %r12d, %eax
        popq    %r12
        ret
        .section        .rodata
        .align 32
        .type   f()::{lambda()#2}::operator()() const::qstring_literal, @object
        .size   f()::{lambda()#2}::operator()() const::qstring_literal, 32
f()::{lambda()#2}::operator()() const::qstring_literal:
        .long   -1
        .long   1
        .byte   0
        .byte   0
        .byte   0
        .byte   0
        .zero   4
        .quad   24
        .string "a"
        .string ""
        .string ""
        .zero   4
        .align 32
f()::{lambda()#1}::operator()() const::qstring_literal:
        .long   -1
        .long   1
        .byte   0
        .byte   0
        .byte   0
        .byte   0
        .zero   4
        .quad   24
        .string "a"
        .string ""
        .string ""
        .zero   4


More information about the Development mailing list