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