Encapsulate and protect all accesses to the vtable of Heap objects
[platform/upstream/qtdeclarative.git] / src / qml / jsruntime / qv4string.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL21$
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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://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 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** $QT_END_LICENSE$
31 **
32 ****************************************************************************/
33
34 #include "qv4string_p.h"
35 #include "qv4value_p.h"
36 #ifndef V4_BOOTSTRAP
37 #include "qv4identifiertable_p.h"
38 #include "qv4runtime_p.h"
39 #include "qv4objectproto_p.h"
40 #include "qv4stringobject_p.h"
41 #endif
42 #include <QtCore/QHash>
43
44 using namespace QV4;
45
46 static uint toArrayIndex(const QChar *ch, const QChar *end)
47 {
48     uint i = ch->unicode() - '0';
49     if (i > 9)
50         return UINT_MAX;
51     ++ch;
52     // reject "01", "001", ...
53     if (i == 0 && ch != end)
54         return UINT_MAX;
55
56     while (ch < end) {
57         uint x = ch->unicode() - '0';
58         if (x > 9)
59             return UINT_MAX;
60         uint n = i*10 + x;
61         if (n < i)
62             // overflow
63             return UINT_MAX;
64         i = n;
65         ++ch;
66     }
67     return i;
68 }
69
70 #ifndef V4_BOOTSTRAP
71
72 static uint toArrayIndex(const char *ch, const char *end)
73 {
74     uint i = *ch - '0';
75     if (i > 9)
76         return UINT_MAX;
77     ++ch;
78     // reject "01", "001", ...
79     if (i == 0 && ch != end)
80         return UINT_MAX;
81
82     while (ch < end) {
83         uint x = *ch - '0';
84         if (x > 9)
85             return UINT_MAX;
86         uint n = i*10 + x;
87         if (n < i)
88             // overflow
89             return UINT_MAX;
90         i = n;
91         ++ch;
92     }
93     return i;
94 }
95
96
97 DEFINE_MANAGED_VTABLE(String);
98
99 void String::markObjects(Heap::Base *that, ExecutionEngine *e)
100 {
101     String::Data *s = static_cast<String::Data *>(that);
102     if (s->largestSubLength) {
103         s->left->mark(e);
104         s->right->mark(e);
105     }
106 }
107
108 bool String::isEqualTo(Managed *t, Managed *o)
109 {
110     if (t == o)
111         return true;
112
113     if (!o->d()->vtable()->isString)
114         return false;
115
116     return static_cast<String *>(t)->isEqualTo(static_cast<String *>(o));
117 }
118
119
120 Heap::String::String(const QString &t)
121 {
122     subtype = String::StringType_Unknown;
123
124     text = const_cast<QString &>(t).data_ptr();
125     text->ref.ref();
126     identifier = 0;
127     stringHash = UINT_MAX;
128     largestSubLength = 0;
129     len = text->size;
130 }
131
132 Heap::String::String(String *l, String *r)
133 {
134     subtype = String::StringType_Unknown;
135
136     left = l;
137     right = r;
138     stringHash = UINT_MAX;
139     largestSubLength = qMax(l->largestSubLength, r->largestSubLength);
140     len = l->len + r->len;
141
142     if (!l->largestSubLength && l->len > largestSubLength)
143         largestSubLength = l->len;
144     if (!r->largestSubLength && r->len > largestSubLength)
145         largestSubLength = r->len;
146
147     // make sure we don't get excessive depth in our strings
148     if (len > 256 && len >= 2*largestSubLength)
149         simplifyString();
150 }
151
152 uint String::toUInt(bool *ok) const
153 {
154     *ok = true;
155
156     if (subtype() == Heap::String::StringType_Unknown)
157         d()->createHashValue();
158     if (subtype() == Heap::String::StringType_ArrayIndex)
159         return d()->stringHash;
160
161     // required for UINT_MAX or numbers starting with a leading 0
162     double d = RuntimeHelpers::stringToNumber(toQString());
163     uint l = (uint)d;
164     if (d == l)
165         return l;
166     *ok = false;
167     return UINT_MAX;
168 }
169
170 void String::makeIdentifierImpl(ExecutionEngine *e) const
171 {
172     if (d()->largestSubLength)
173         d()->simplifyString();
174     Q_ASSERT(!d()->largestSubLength);
175     e->identifierTable->identifier(this);
176 }
177
178 void Heap::String::simplifyString() const
179 {
180     Q_ASSERT(largestSubLength);
181
182     int l = length();
183     QString result(l, Qt::Uninitialized);
184     QChar *ch = const_cast<QChar *>(result.constData());
185     append(this, ch);
186     text = result.data_ptr();
187     text->ref.ref();
188     identifier = 0;
189     largestSubLength = 0;
190 }
191
192 void Heap::String::createHashValue() const
193 {
194     if (largestSubLength)
195         simplifyString();
196     Q_ASSERT(!largestSubLength);
197     const QChar *ch = reinterpret_cast<const QChar *>(text->data());
198     const QChar *end = ch + text->size;
199
200     // array indices get their number as hash value
201     stringHash = ::toArrayIndex(ch, end);
202     if (stringHash != UINT_MAX) {
203         subtype = Heap::String::StringType_ArrayIndex;
204         return;
205     }
206
207     uint h = 0xffffffff;
208     while (ch < end) {
209         h = 31 * h + ch->unicode();
210         ++ch;
211     }
212
213     stringHash = h;
214     subtype = Heap::String::StringType_Regular;
215 }
216
217 void Heap::String::append(const String *data, QChar *ch)
218 {
219     std::vector<const String *> worklist;
220     worklist.reserve(32);
221     worklist.push_back(data);
222
223     while (!worklist.empty()) {
224         const String *item = worklist.back();
225         worklist.pop_back();
226
227         if (item->largestSubLength) {
228             worklist.push_back(item->right);
229             worklist.push_back(item->left);
230         } else {
231             memcpy(ch, item->text->data(), item->text->size * sizeof(QChar));
232             ch += item->text->size;
233         }
234     }
235 }
236
237
238
239
240 uint String::createHashValue(const QChar *ch, int length)
241 {
242     const QChar *end = ch + length;
243
244     // array indices get their number as hash value
245     uint stringHash = ::toArrayIndex(ch, end);
246     if (stringHash != UINT_MAX)
247         return stringHash;
248
249     uint h = 0xffffffff;
250     while (ch < end) {
251         h = 31 * h + ch->unicode();
252         ++ch;
253     }
254
255     return h;
256 }
257
258 uint String::createHashValue(const char *ch, int length)
259 {
260     const char *end = ch + length;
261
262     // array indices get their number as hash value
263     uint stringHash = ::toArrayIndex(ch, end);
264     if (stringHash != UINT_MAX)
265         return stringHash;
266
267     uint h = 0xffffffff;
268     while (ch < end) {
269         if ((uchar)(*ch) >= 0x80)
270             return UINT_MAX;
271         h = 31 * h + *ch;
272         ++ch;
273     }
274
275     return h;
276 }
277
278 uint String::getLength(const Managed *m)
279 {
280     return static_cast<const String *>(m)->d()->length();
281 }
282
283 #endif // V4_BOOTSTRAP
284
285 uint String::toArrayIndex(const QString &str)
286 {
287     return ::toArrayIndex(str.constData(), str.constData() + str.length());
288 }
289