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 <qv4runtime_p.h>
41 #include <qv4propertykey_p.h>
42 #include <qv4string_p.h>
43 #include <qv4symbol_p.h>
44 #include <qv4object_p.h>
45 #include <qv4objectproto_p.h>
46 #include <private/qv4mm_p.h>
47 
48 #include <wtf/MathExtras.h>
49 
50 using namespace QV4;
51 
toUInt16() const52 int Value::toUInt16() const
53 {
54     if (integerCompatible())
55         return (ushort)(uint)integerValue();
56 
57     double number = toNumber();
58 
59     double D16 = 65536.0;
60     if ((number >= 0 && number < D16))
61         return static_cast<ushort>(number);
62 
63     if (!std::isfinite(number))
64         return +0;
65 
66     double d = ::floor(::fabs(number));
67     if (std::signbit(number))
68         d = -d;
69 
70     number = ::fmod(d , D16);
71 
72     if (number < 0)
73         number += D16;
74 
75     return (unsigned short)number;
76 }
77 
toBooleanImpl(Value val)78 bool Value::toBooleanImpl(Value val)
79 {
80     if (val.isManagedOrUndefined()) {
81         Heap::Base *b = val.m();
82         if (!b)
83             return false;
84         if (b->internalClass->vtable->isString)
85             return static_cast<Heap::String *>(b)->length() > 0;
86         return true;
87     }
88 
89     // double
90     double d = val.doubleValue();
91     return d && !std::isnan(d);
92 }
93 
toNumberImpl(Value val)94 double Value::toNumberImpl(Value val)
95 {
96     switch (val.type()) {
97     case QV4::Value::Undefined_Type:
98         return std::numeric_limits<double>::quiet_NaN();
99     case QV4::Value::Managed_Type:
100         if (String *s = val.stringValue())
101             return RuntimeHelpers::stringToNumber(s->toQString());
102         if (val.isSymbol()) {
103             Managed &m = static_cast<Managed &>(val);
104             m.engine()->throwTypeError();
105             return 0;
106         }
107         {
108             Q_ASSERT(val.isObject());
109             Scope scope(val.objectValue()->engine());
110             ScopedValue protectThis(scope, val);
111             ScopedValue prim(scope, RuntimeHelpers::toPrimitive(val, NUMBER_HINT));
112             if (scope.engine->hasException)
113                 return 0;
114             return prim->toNumber();
115         }
116     case QV4::Value::Null_Type:
117     case QV4::Value::Boolean_Type:
118     case QV4::Value::Integer_Type:
119         return val.int_32();
120     default: // double
121         Q_UNREACHABLE();
122     }
123 }
124 
toQStringNoThrow() const125 QString Value::toQStringNoThrow() const
126 {
127     switch (type()) {
128     case Value::Empty_Type:
129         Q_ASSERT(!"empty Value encountered");
130         Q_UNREACHABLE();
131     case Value::Undefined_Type:
132         return QStringLiteral("undefined");
133     case Value::Null_Type:
134         return QStringLiteral("null");
135     case Value::Boolean_Type:
136         if (booleanValue())
137             return QStringLiteral("true");
138         else
139             return QStringLiteral("false");
140     case Value::Managed_Type:
141         if (String *s = stringValue())
142             return s->toQString();
143         if (Symbol *s = symbolValue())
144             return s->descriptiveString();
145         {
146             Q_ASSERT(isObject());
147             Scope scope(objectValue()->engine());
148             ScopedValue ex(scope);
149             bool caughtException = false;
150             ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
151             if (scope.hasException()) {
152                 ex = scope.engine->catchException();
153                 caughtException = true;
154             } else if (prim->isPrimitive()) {
155                     return prim->toQStringNoThrow();
156             }
157             // Can't nest try/catch due to CXX ABI limitations for foreign exception nesting.
158             if (caughtException) {
159                 ScopedValue prim(scope, RuntimeHelpers::toPrimitive(ex, STRING_HINT));
160                 if (scope.hasException()) {
161                     ex = scope.engine->catchException();
162                 } else if (prim->isPrimitive()) {
163                     return prim->toQStringNoThrow();
164                 }
165             }
166             return QString();
167         }
168     case Value::Integer_Type: {
169         QString str;
170         RuntimeHelpers::numberToString(&str, (double)int_32(), 10);
171         return str;
172     }
173     default: { // double
174         QString str;
175         RuntimeHelpers::numberToString(&str, doubleValue(), 10);
176         return str;
177     }
178     } // switch
179 }
180 
toQString() const181 QString Value::toQString() const
182 {
183     switch (type()) {
184     case Value::Empty_Type:
185         Q_ASSERT(!"empty Value encountered");
186         Q_UNREACHABLE();
187     case Value::Undefined_Type:
188         return QStringLiteral("undefined");
189     case Value::Null_Type:
190         return QStringLiteral("null");
191     case Value::Boolean_Type:
192         if (booleanValue())
193             return QStringLiteral("true");
194         else
195             return QStringLiteral("false");
196     case Value::Managed_Type:
197         if (String *s = stringValue()) {
198             return s->toQString();
199         } else if (isSymbol()) {
200             static_cast<const Managed *>(this)->engine()->throwTypeError();
201             return QString();
202         } else {
203             Q_ASSERT(isObject());
204             Scope scope(objectValue()->engine());
205             ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
206             return prim->toQString();
207         }
208     case Value::Integer_Type: {
209         QString str;
210         RuntimeHelpers::numberToString(&str, (double)int_32(), 10);
211         return str;
212     }
213     default: { // double
214         QString str;
215         RuntimeHelpers::numberToString(&str, doubleValue(), 10);
216         return str;
217     }
218     } // switch
219 }
220 
toPropertyKey(ExecutionEngine * e) const221 QV4::PropertyKey Value::toPropertyKey(ExecutionEngine *e) const
222 {
223     if (isInteger() && int_32() >= 0)
224         return PropertyKey::fromArrayIndex(static_cast<uint>(int_32()));
225     if (isStringOrSymbol()) {
226         Scope scope(e);
227         ScopedStringOrSymbol s(scope, this);
228         return s->toPropertyKey();
229     }
230     Scope scope(e);
231     ScopedValue v(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
232     if (!v->isStringOrSymbol())
233         v = v->toString(e);
234     if (e->hasException)
235         return PropertyKey::invalid();
236     ScopedStringOrSymbol s(scope, v);
237     return s->toPropertyKey();
238 }
239 
sameValue(Value other) const240 bool Value::sameValue(Value other) const {
241     if (_val == other._val)
242         return true;
243     String *s = stringValue();
244     String *os = other.stringValue();
245     if (s && os)
246         return s->isEqualTo(os);
247     if (isInteger() && other.isDouble())
248         return int_32() ? (double(int_32()) == other.doubleValue())
249                         : (other.doubleValue() == 0 && !std::signbit(other.doubleValue()));
250     if (isDouble() && other.isInteger())
251         return other.int_32() ? (doubleValue() == double(other.int_32()))
252                               : (doubleValue() == 0 && !std::signbit(doubleValue()));
253     if (isManaged())
254         return other.isManaged() && cast<Managed>()->isEqualTo(other.cast<Managed>());
255     return false;
256 }
257 
sameValueZero(Value other) const258 bool Value::sameValueZero(Value other) const {
259     if (_val == other._val)
260         return true;
261     String *s = stringValue();
262     String *os = other.stringValue();
263     if (s && os)
264         return s->isEqualTo(os);
265     if (isInteger() && other.isDouble())
266         return double(int_32()) == other.doubleValue();
267     if (isDouble() && other.isInteger())
268         return other.int_32() == doubleValue();
269     if (isDouble() && other.isDouble()) {
270         if (doubleValue() == 0 && other.doubleValue() == 0) {
271             return true;
272         }
273     }
274     if (isManaged())
275         return other.isManaged() && cast<Managed>()->isEqualTo(other.cast<Managed>());
276     return false;
277 }
278 
toString(ExecutionEngine * e,Value val)279 Heap::String *Value::toString(ExecutionEngine *e, Value val)
280 {
281     return RuntimeHelpers::convertToString(e, val);
282 }
283 
toObject(ExecutionEngine * e,Value val)284 Heap::Object *Value::toObject(ExecutionEngine *e, Value val)
285 {
286     return RuntimeHelpers::convertToObject(e, val);
287 }
288 
asArrayLength(bool * ok) const289 uint Value::asArrayLength(bool *ok) const
290 {
291     *ok = true;
292     if (isInteger()) {
293         if (int_32() >= 0) {
294             return (uint)int_32();
295         } else {
296             *ok = false;
297             return UINT_MAX;
298         }
299     }
300     if (isNumber()) {
301         double d = doubleValue();
302         uint idx = (uint)d;
303         if (idx != d) {
304             *ok = false;
305             return UINT_MAX;
306         }
307         return idx;
308     }
309     if (String *s = stringValue())
310         return s->toUInt(ok);
311 
312     uint idx = toUInt32();
313     double d = toNumber();
314     if (d != idx) {
315         *ok = false;
316         return UINT_MAX;
317     }
318     return idx;
319 }
320