1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qv4string_p.h"
41 #include "qv4value_p.h"
42 #include "qv4identifiertable_p.h"
43 #include "qv4runtime_p.h"
44 #include "qv4objectproto_p.h"
45 #include "qv4stringobject_p.h"
46 #include <QtCore/QHash>
47 #include <QtCore/private/qnumeric_p.h>
48
49 using namespace QV4;
50
markObjects(Heap::Base * that,MarkStack * markStack)51 void Heap::StringOrSymbol::markObjects(Heap::Base *that, MarkStack *markStack)
52 {
53 StringOrSymbol *s = static_cast<StringOrSymbol *>(that);
54 Heap::StringOrSymbol *id = s->identifier.asStringOrSymbol();
55 if (id)
56 id->mark(markStack);
57 }
58
markObjects(Heap::Base * that,MarkStack * markStack)59 void Heap::String::markObjects(Heap::Base *that, MarkStack *markStack)
60 {
61 StringOrSymbol::markObjects(that, markStack);
62 String *s = static_cast<String *>(that);
63 if (s->subtype < StringType_Complex)
64 return;
65
66 ComplexString *cs = static_cast<ComplexString *>(s);
67 if (cs->subtype == StringType_AddedString) {
68 cs->left->mark(markStack);
69 cs->right->mark(markStack);
70 } else {
71 Q_ASSERT(cs->subtype == StringType_SubString);
72 cs->left->mark(markStack);
73 }
74 }
75
76 DEFINE_MANAGED_VTABLE(StringOrSymbol);
77 DEFINE_MANAGED_VTABLE(String);
78
79
virtualIsEqualTo(Managed * t,Managed * o)80 bool String::virtualIsEqualTo(Managed *t, Managed *o)
81 {
82 if (t == o)
83 return true;
84
85 if (!o->vtable()->isString)
86 return false;
87
88 return static_cast<String *>(t)->isEqualTo(static_cast<String *>(o));
89 }
90
91
init(const QString & t)92 void Heap::String::init(const QString &t)
93 {
94 Base::init();
95
96 subtype = String::StringType_Unknown;
97
98 text = const_cast<QString &>(t).data_ptr();
99 text->ref.ref();
100 }
101
init(String * l,String * r)102 void Heap::ComplexString::init(String *l, String *r)
103 {
104 Base::init();
105
106 subtype = String::StringType_AddedString;
107
108 left = l;
109 right = r;
110 len = left->length() + right->length();
111 if (left->subtype >= StringType_Complex)
112 largestSubLength = static_cast<ComplexString *>(left)->largestSubLength;
113 else
114 largestSubLength = left->length();
115 if (right->subtype >= StringType_Complex)
116 largestSubLength = qMax(largestSubLength, static_cast<ComplexString *>(right)->largestSubLength);
117 else
118 largestSubLength = qMax(largestSubLength, right->length());
119
120 // make sure we don't get excessive depth in our strings
121 if (len > 256 && len >= 2*largestSubLength)
122 simplifyString();
123 }
124
init(Heap::String * ref,int from,int len)125 void Heap::ComplexString::init(Heap::String *ref, int from, int len)
126 {
127 Q_ASSERT(ref->length() >= from + len);
128 Base::init();
129
130 subtype = String::StringType_SubString;
131
132 left = ref;
133 this->from = from;
134 this->len = len;
135 }
136
destroy()137 void Heap::StringOrSymbol::destroy()
138 {
139 if (text) {
140 internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(-text->size) * (int)sizeof(QChar));
141 if (!text->ref.deref())
142 QStringData::deallocate(text);
143 }
144 Base::destroy();
145 }
146
toUInt(bool * ok) const147 uint String::toUInt(bool *ok) const
148 {
149 *ok = true;
150
151 if (subtype() >= Heap::String::StringType_Unknown)
152 d()->createHashValue();
153 if (subtype() == Heap::String::StringType_ArrayIndex)
154 return d()->stringHash;
155
156 // required for UINT_MAX or numbers starting with a leading 0
157 double d = RuntimeHelpers::stringToNumber(toQString());
158 uint l = (uint)d;
159 if (d == l)
160 return l;
161 *ok = false;
162 return UINT_MAX;
163 }
164
createPropertyKeyImpl() const165 void String::createPropertyKeyImpl() const
166 {
167 if (!d()->text)
168 d()->simplifyString();
169 Q_ASSERT(d()->text);
170 engine()->identifierTable->asPropertyKey(this);
171 }
172
simplifyString() const173 void Heap::String::simplifyString() const
174 {
175 Q_ASSERT(!text);
176
177 int l = length();
178 QString result(l, Qt::Uninitialized);
179 QChar *ch = const_cast<QChar *>(result.constData());
180 append(this, ch);
181 text = result.data_ptr();
182 text->ref.ref();
183 const ComplexString *cs = static_cast<const ComplexString *>(this);
184 identifier = PropertyKey::invalid();
185 cs->left = cs->right = nullptr;
186
187 internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(text->size) * (qptrdiff)sizeof(QChar));
188 subtype = StringType_Unknown;
189 }
190
startsWithUpper() const191 bool Heap::String::startsWithUpper() const
192 {
193 if (subtype == StringType_AddedString)
194 return static_cast<const Heap::ComplexString *>(this)->left->startsWithUpper();
195
196 const Heap::String *str = this;
197 int offset = 0;
198 if (subtype == StringType_SubString) {
199 const ComplexString *cs = static_cast<const Heap::ComplexString *>(this);
200 if (!cs->len)
201 return false;
202 // simplification here is not ideal, but hopefully not a common case.
203 if (cs->left->subtype >= Heap::String::StringType_Complex)
204 cs->left->simplifyString();
205 str = cs->left;
206 offset = cs->from;
207 }
208 Q_ASSERT(str->subtype < Heap::String::StringType_Complex);
209 return str->text->size > offset && QChar::isUpper(str->text->data()[offset]);
210 }
211
append(const String * data,QChar * ch)212 void Heap::String::append(const String *data, QChar *ch)
213 {
214 std::vector<const String *> worklist;
215 worklist.reserve(32);
216 worklist.push_back(data);
217
218 while (!worklist.empty()) {
219 const String *item = worklist.back();
220 worklist.pop_back();
221
222 if (item->subtype == StringType_AddedString) {
223 const ComplexString *cs = static_cast<const ComplexString *>(item);
224 worklist.push_back(cs->right);
225 worklist.push_back(cs->left);
226 } else if (item->subtype == StringType_SubString) {
227 const ComplexString *cs = static_cast<const ComplexString *>(item);
228 memcpy(ch, cs->left->toQString().constData() + cs->from, cs->len*sizeof(QChar));
229 ch += cs->len;
230 } else {
231 memcpy(static_cast<void *>(ch), static_cast<const void *>(item->text->data()), item->text->size * sizeof(QChar));
232 ch += item->text->size;
233 }
234 }
235 }
236
createHashValue() const237 void Heap::StringOrSymbol::createHashValue() const
238 {
239 if (!text) {
240 Q_ASSERT(internalClass->vtable->isString);
241 static_cast<const Heap::String *>(this)->simplifyString();
242 }
243 Q_ASSERT(text);
244 const QChar *ch = reinterpret_cast<const QChar *>(text->data());
245 const QChar *end = ch + text->size;
246 stringHash = QV4::String::calculateHashValue(ch, end, &subtype);
247 }
248
virtualGetLength(const Managed * m)249 qint64 String::virtualGetLength(const Managed *m)
250 {
251 return static_cast<const String *>(m)->d()->length();
252 }
253