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