[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