Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qv4string.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant
4
5#include "qv4string_p.h"
6#include "qv4value_p.h"
8#include "qv4runtime_p.h"
9#include <QtQml/private/qv4mm_p.h>
10#include <QtCore/QHash>
11#include <QtCore/private/qnumeric_p.h>
12
13using namespace QV4;
14
15void Heap::StringOrSymbol::markObjects(Heap::Base *that, MarkStack *markStack)
16{
17 StringOrSymbol *s = static_cast<StringOrSymbol *>(that);
18 Heap::StringOrSymbol *id = s->identifier.asStringOrSymbol();
19 if (id)
20 id->mark(markStack);
21}
22
23void Heap::String::markObjects(Heap::Base *that, MarkStack *markStack)
24{
25 StringOrSymbol::markObjects(that, markStack);
26 String *s = static_cast<String *>(that);
27 if (s->subtype < StringType_Complex)
28 return;
29
30 ComplexString *cs = static_cast<ComplexString *>(s);
31 if (cs->subtype == StringType_AddedString) {
32 cs->left->mark(markStack);
33 cs->right->mark(markStack);
34 } else {
35 Q_ASSERT(cs->subtype == StringType_SubString);
36 cs->left->mark(markStack);
37 }
38}
39
42
43
44bool String::virtualIsEqualTo(Managed *t, Managed *o)
45{
46 if (t == o)
47 return true;
48
49 if (!o->vtable()->isString)
50 return false;
51
52 return static_cast<String *>(t)->isEqualTo(static_cast<String *>(o));
53}
54
55
56void Heap::String::init(const QString &t)
57{
58 QString mutableText(t);
59 StringOrSymbol::init(mutableText.data_ptr());
60 subtype = String::StringType_Unknown;
61}
62
63void Heap::ComplexString::init(String *l, String *r)
64{
65 StringOrSymbol::init();
66 subtype = String::StringType_AddedString;
67
68 left = l;
69 right = r;
70 len = left->length() + right->length();
71 if (left->subtype >= StringType_Complex)
72 largestSubLength = static_cast<ComplexString *>(left)->largestSubLength;
73 else
74 largestSubLength = left->length();
75 if (right->subtype >= StringType_Complex)
76 largestSubLength = qMax(largestSubLength, static_cast<ComplexString *>(right)->largestSubLength);
77 else
78 largestSubLength = qMax(largestSubLength, right->length());
79
80 // make sure we don't get excessive depth in our strings
81 if (len > 256 && len >= 2*largestSubLength)
82 simplifyString();
83}
84
85void Heap::ComplexString::init(Heap::String *ref, int from, int len)
86{
87 Q_ASSERT(ref->length() >= from + len);
88 StringOrSymbol::init();
89
90 subtype = String::StringType_SubString;
91
92 left = ref;
93 this->from = from;
94 this->len = len;
95}
96
97void Heap::StringOrSymbol::destroy()
98{
99 if (subtype < Heap::String::StringType_AddedString) {
100 internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(
101 qptrdiff(-text()->size) * qptrdiff(sizeof(QChar)));
102 }
103 text().~QStringPrivate();
104 Base::destroy();
105}
106
107uint String::toUInt(bool *ok) const
108{
109 *ok = true;
110
111 if (subtype() >= Heap::String::StringType_Unknown)
112 d()->createHashValue();
113 if (subtype() == Heap::String::StringType_ArrayIndex)
114 return d()->stringHash;
115
116 // required for UINT_MAX or numbers starting with a leading 0
117 double d = RuntimeHelpers::stringToNumber(toQString());
118 uint l = (uint)d;
119 if (d == l)
120 return l;
121 *ok = false;
122 return UINT_MAX;
123}
124
125void String::createPropertyKeyImpl() const
126{
127 if (d()->subtype >= Heap::String::StringType_AddedString)
128 d()->simplifyString();
129 Q_ASSERT(d()->subtype < Heap::String::StringType_AddedString);
130 engine()->identifierTable->asPropertyKey(this);
131}
132
133void Heap::String::simplifyString() const
134{
135 Q_ASSERT(subtype >= StringType_AddedString);
136
137 int l = length();
138 QString result(l, Qt::Uninitialized);
139 QChar *ch = const_cast<QChar *>(result.constData());
140 append(this, ch);
141 text() = result.data_ptr();
142 const ComplexString *cs = static_cast<const ComplexString *>(this);
143 identifier = PropertyKey::invalid();
144 cs->left = cs->right = nullptr;
145
146 internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(
147 qptrdiff(text().size) * qptrdiff(sizeof(QChar)));
148 subtype = StringType_Unknown;
149}
150
151bool Heap::String::startsWithUpper() const
152{
153 if (subtype == StringType_AddedString)
154 return static_cast<const Heap::ComplexString *>(this)->left->startsWithUpper();
155
156 const Heap::String *str = this;
157 int offset = 0;
158 if (subtype == StringType_SubString) {
159 const ComplexString *cs = static_cast<const Heap::ComplexString *>(this);
160 if (!cs->len)
161 return false;
162 // simplification here is not ideal, but hopefully not a common case.
163 if (cs->left->subtype >= Heap::String::StringType_Complex)
164 cs->left->simplifyString();
165 str = cs->left;
166 offset = cs->from;
167 }
168 Q_ASSERT(str->subtype < Heap::String::StringType_Complex);
169 return str->text().size > offset && QChar::isUpper(str->text().data()[offset]);
170}
171
172void Heap::String::append(const String *data, QChar *ch)
173{
174 // in-order visitation with explicit stack
175 // where leaf nodes are "real" strings that get appended to ch
176
177 enum StatusTag : bool { NotVisited, Visited };
178 using Pointer = QTaggedPointer<const String, StatusTag>;
179
180 std::vector<Pointer> worklist;
181 worklist.reserve(32);
182 worklist.push_back(Pointer(data));
183
184 while (!worklist.empty()) {
185 Pointer item = worklist.back();
186 if (item.tag() == Visited) {
187 Q_ASSERT(item->subtype == StringType_AddedString);
188 const ComplexString *cs = static_cast<const ComplexString *>(item.data());
189 worklist.pop_back();
190 worklist.push_back(Pointer(cs->right));
191 continue;
192 }
193
194 if (item->subtype == StringType_AddedString) {
195 // we need to keep the node in the worklist, as we still need to handle "right"
196 worklist.back().setTag(Visited);
197 const ComplexString *cs = static_cast<const ComplexString *>(item.data());
198 worklist.push_back(Pointer(cs->left));
199 } else if (item->subtype == StringType_SubString) {
200 worklist.pop_back();
201 const ComplexString *cs = static_cast<const ComplexString *>(item.data());
202 memcpy(ch, cs->left->toQString().constData() + cs->from, cs->len*sizeof(QChar));
203 ch += cs->len;
204 } else {
205 worklist.pop_back();
206 memcpy(static_cast<void *>(ch), item->text().data(), item->text().size * sizeof(QChar));
207 ch += item->text().size;
208 }
209 }
210}
211
212void Heap::StringOrSymbol::createHashValue() const
213{
214 if (subtype >= StringType_AddedString) {
215 Q_ASSERT(internalClass->vtable->isString);
216 static_cast<const Heap::String *>(this)->simplifyString();
217 }
218 Q_ASSERT(subtype < StringType_AddedString);
219 const QChar *ch = reinterpret_cast<const QChar *>(text().data());
220 const QChar *end = ch + text().size;
221 stringHash = QV4::String::calculateHashValue(ch, end, &subtype);
222}
223
224qint64 String::virtualGetLength(const Managed *m)
225{
226 return static_cast<const String *>(m)->d()->length();
227}
DEFINE_MANAGED_VTABLE(String)
DEFINE_MANAGED_VTABLE(StringOrSymbol)