Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/qtdeclarative/src/qtdeclarative/src/qml/jsruntime/qv4runtime.cpp |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
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 "qv4global_p.h" | - | ||||||||||||
41 | #include "qv4engine_p.h" | - | ||||||||||||
42 | #include "qv4runtime_p.h" | - | ||||||||||||
43 | #ifndef V4_BOOTSTRAP | - | ||||||||||||
44 | #include "qv4object_p.h" | - | ||||||||||||
45 | #include "qv4objectproto_p.h" | - | ||||||||||||
46 | #include "qv4globalobject_p.h" | - | ||||||||||||
47 | #include "qv4stringobject_p.h" | - | ||||||||||||
48 | #include "qv4argumentsobject_p.h" | - | ||||||||||||
49 | #include "qv4objectiterator_p.h" | - | ||||||||||||
50 | #include "qv4dateobject_p.h" | - | ||||||||||||
51 | #include "qv4lookup_p.h" | - | ||||||||||||
52 | #include "qv4function_p.h" | - | ||||||||||||
53 | #include "qv4numberobject_p.h" | - | ||||||||||||
54 | #include "qv4regexp_p.h" | - | ||||||||||||
55 | #include "qv4regexpobject_p.h" | - | ||||||||||||
56 | #include "private/qlocale_tools_p.h" | - | ||||||||||||
57 | #include "qv4scopedvalue_p.h" | - | ||||||||||||
58 | #include "qv4jscall_p.h" | - | ||||||||||||
59 | #include <private/qv4qmlcontext_p.h> | - | ||||||||||||
60 | #include <private/qqmltypewrapper_p.h> | - | ||||||||||||
61 | #include <private/qqmlengine_p.h> | - | ||||||||||||
62 | #include <private/qqmljavascriptexpression_p.h> | - | ||||||||||||
63 | #include "qv4qobjectwrapper_p.h" | - | ||||||||||||
64 | #include "qv4symbol_p.h" | - | ||||||||||||
65 | #include "qv4generatorobject_p.h" | - | ||||||||||||
66 | #include <private/qv8engine_p.h> | - | ||||||||||||
67 | #endif | - | ||||||||||||
68 | - | |||||||||||||
69 | #include <QtCore/QDebug> | - | ||||||||||||
70 | #include <cassert> | - | ||||||||||||
71 | #include <cstdio> | - | ||||||||||||
72 | #include <stdlib.h> | - | ||||||||||||
73 | - | |||||||||||||
74 | #include <wtf/MathExtras.h> | - | ||||||||||||
75 | - | |||||||||||||
76 | #ifdef QV4_COUNT_RUNTIME_FUNCTIONS | - | ||||||||||||
77 | # include <QtCore/QBuffer> | - | ||||||||||||
78 | # include <QtCore/QDebug> | - | ||||||||||||
79 | #endif // QV4_COUNT_RUNTIME_FUNCTIONS | - | ||||||||||||
80 | - | |||||||||||||
81 | QT_BEGIN_NAMESPACE | - | ||||||||||||
82 | - | |||||||||||||
83 | namespace QV4 { | - | ||||||||||||
84 | - | |||||||||||||
85 | #ifdef QV4_COUNT_RUNTIME_FUNCTIONS | - | ||||||||||||
86 | struct RuntimeCounters::Data { | - | ||||||||||||
87 | enum Type { | - | ||||||||||||
88 | None = 0, | - | ||||||||||||
89 | Undefined = 1, | - | ||||||||||||
90 | Null = 2, | - | ||||||||||||
91 | Boolean = 3, | - | ||||||||||||
92 | Integer = 4, | - | ||||||||||||
93 | Managed = 5, | - | ||||||||||||
94 | Double = 7 | - | ||||||||||||
95 | }; | - | ||||||||||||
96 | - | |||||||||||||
97 | static const char *pretty(Type t) { | - | ||||||||||||
98 | switch (t) { | - | ||||||||||||
99 | case None: return ""; | - | ||||||||||||
100 | case Undefined: return "Undefined"; | - | ||||||||||||
101 | case Null: return "Null"; | - | ||||||||||||
102 | case Boolean: return "Boolean"; | - | ||||||||||||
103 | case Integer: return "Integer"; | - | ||||||||||||
104 | case Managed: return "Managed"; | - | ||||||||||||
105 | case Double: return "Double"; | - | ||||||||||||
106 | default: return "Unknown"; | - | ||||||||||||
107 | } | - | ||||||||||||
108 | } | - | ||||||||||||
109 | - | |||||||||||||
110 | static unsigned mangle(unsigned tag) { | - | ||||||||||||
111 | switch (tag) { | - | ||||||||||||
112 | case Value::Undefined_Type: return Undefined; | - | ||||||||||||
113 | case Value::Null_Type: return Null; | - | ||||||||||||
114 | case Value::Boolean_Type: return Boolean; | - | ||||||||||||
115 | case Value::Integer_Type: return Integer; | - | ||||||||||||
116 | case Value::Managed_Type: return Managed; | - | ||||||||||||
117 | default: return Double; | - | ||||||||||||
118 | } | - | ||||||||||||
119 | } | - | ||||||||||||
120 | - | |||||||||||||
121 | static unsigned mangle(unsigned tag1, unsigned tag2) { | - | ||||||||||||
122 | return (mangle(tag1) << 3) | mangle(tag2); | - | ||||||||||||
123 | } | - | ||||||||||||
124 | - | |||||||||||||
125 | static void unmangle(unsigned signature, Type &tag1, Type &tag2) { | - | ||||||||||||
126 | tag1 = Type((signature >> 3) & 7); | - | ||||||||||||
127 | tag2 = Type(signature & 7); | - | ||||||||||||
128 | } | - | ||||||||||||
129 | - | |||||||||||||
130 | typedef QVector<quint64> Counters; | - | ||||||||||||
131 | QHash<const char *, Counters> counters; | - | ||||||||||||
132 | - | |||||||||||||
133 | inline void count(const char *func) { | - | ||||||||||||
134 | QVector<quint64> &cnt = counters[func]; | - | ||||||||||||
135 | if (cnt.isEmpty()) | - | ||||||||||||
136 | cnt.resize(64); | - | ||||||||||||
137 | cnt[0] += 1; | - | ||||||||||||
138 | } | - | ||||||||||||
139 | - | |||||||||||||
140 | inline void count(const char *func, unsigned tag) { | - | ||||||||||||
141 | QVector<quint64> &cnt = counters[func]; | - | ||||||||||||
142 | if (cnt.isEmpty()) | - | ||||||||||||
143 | cnt.resize(64); | - | ||||||||||||
144 | cnt[mangle(tag)] += 1; | - | ||||||||||||
145 | } | - | ||||||||||||
146 | - | |||||||||||||
147 | inline void count(const char *func, unsigned tag1, unsigned tag2) { | - | ||||||||||||
148 | QVector<quint64> &cnt = counters[func]; | - | ||||||||||||
149 | if (cnt.isEmpty()) | - | ||||||||||||
150 | cnt.resize(64); | - | ||||||||||||
151 | cnt[mangle(tag1, tag2)] += 1; | - | ||||||||||||
152 | } | - | ||||||||||||
153 | - | |||||||||||||
154 | struct Line { | - | ||||||||||||
155 | const char *func; | - | ||||||||||||
156 | Type tag1, tag2; | - | ||||||||||||
157 | quint64 count; | - | ||||||||||||
158 | - | |||||||||||||
159 | static bool less(const Line &line1, const Line &line2) { | - | ||||||||||||
160 | return line1.count > line2.count; | - | ||||||||||||
161 | } | - | ||||||||||||
162 | }; | - | ||||||||||||
163 | - | |||||||||||||
164 | void dump() const { | - | ||||||||||||
165 | QBuffer buf; | - | ||||||||||||
166 | buf.open(QIODevice::WriteOnly); | - | ||||||||||||
167 | QTextStream outs(&buf); | - | ||||||||||||
168 | QList<Line> lines; | - | ||||||||||||
169 | for (auto it = counters.cbegin(), end = counters.cend(); it != end; ++it) { | - | ||||||||||||
170 | const Counters &fCount = it.value(); | - | ||||||||||||
171 | for (int i = 0, ei = fCount.size(); i != ei; ++i) { | - | ||||||||||||
172 | quint64 count = fCount[i]; | - | ||||||||||||
173 | if (!count) | - | ||||||||||||
174 | continue; | - | ||||||||||||
175 | Line line; | - | ||||||||||||
176 | line.func = it.key(); | - | ||||||||||||
177 | unmangle(i, line.tag1, line.tag2); | - | ||||||||||||
178 | line.count = count; | - | ||||||||||||
179 | lines.append(line); | - | ||||||||||||
180 | } | - | ||||||||||||
181 | } | - | ||||||||||||
182 | std::sort(lines.begin(), lines.end(), Line::less); | - | ||||||||||||
183 | outs << lines.size() << " counters:" << endl; | - | ||||||||||||
184 | for (const Line &line : qAsConst(lines)) | - | ||||||||||||
185 | outs << qSetFieldWidth(10) << line.count << qSetFieldWidth(0) | - | ||||||||||||
186 | << " | " << line.func | - | ||||||||||||
187 | << " | " << pretty(line.tag1) | - | ||||||||||||
188 | << " | " << pretty(line.tag2) | - | ||||||||||||
189 | << endl; | - | ||||||||||||
190 | qDebug("%s", buf.data().constData()); | - | ||||||||||||
191 | } | - | ||||||||||||
192 | }; | - | ||||||||||||
193 | - | |||||||||||||
194 | RuntimeCounters *RuntimeCounters::instance = 0; | - | ||||||||||||
195 | static RuntimeCounters runtimeCountersInstance; | - | ||||||||||||
196 | RuntimeCounters::RuntimeCounters() | - | ||||||||||||
197 | : d(new Data) | - | ||||||||||||
198 | { | - | ||||||||||||
199 | if (!instance) | - | ||||||||||||
200 | instance = this; | - | ||||||||||||
201 | } | - | ||||||||||||
202 | - | |||||||||||||
203 | RuntimeCounters::~RuntimeCounters() | - | ||||||||||||
204 | { | - | ||||||||||||
205 | d->dump(); | - | ||||||||||||
206 | delete d; | - | ||||||||||||
207 | } | - | ||||||||||||
208 | - | |||||||||||||
209 | void RuntimeCounters::count(const char *func) | - | ||||||||||||
210 | { | - | ||||||||||||
211 | d->count(func); | - | ||||||||||||
212 | } | - | ||||||||||||
213 | - | |||||||||||||
214 | void RuntimeCounters::count(const char *func, uint tag) | - | ||||||||||||
215 | { | - | ||||||||||||
216 | d->count(func, tag); | - | ||||||||||||
217 | } | - | ||||||||||||
218 | - | |||||||||||||
219 | void RuntimeCounters::count(const char *func, uint tag1, uint tag2) | - | ||||||||||||
220 | { | - | ||||||||||||
221 | d->count(func, tag1, tag2); | - | ||||||||||||
222 | } | - | ||||||||||||
223 | - | |||||||||||||
224 | #endif // QV4_COUNT_RUNTIME_FUNCTIONS | - | ||||||||||||
225 | - | |||||||||||||
226 | #ifndef V4_BOOTSTRAP | - | ||||||||||||
227 | - | |||||||||||||
228 | Runtime::Runtime() | - | ||||||||||||
229 | { | - | ||||||||||||
230 | #define INIT_METHOD(returnvalue, name, args) runtimeMethods[name] = reinterpret_cast<void*>(&method_##name); | - | ||||||||||||
231 | FOR_EACH_RUNTIME_METHOD(INIT_METHOD) | - | ||||||||||||
232 | #undef INIT_METHOD | - | ||||||||||||
233 | } | - | ||||||||||||
234 | - | |||||||||||||
235 | void RuntimeHelpers::numberToString(QString *result, double num, int radix) | - | ||||||||||||
236 | { | - | ||||||||||||
237 | Q_ASSERT(result); | - | ||||||||||||
238 | - | |||||||||||||
239 | if (std::isnan(num)) { | - | ||||||||||||
240 | *result = QStringLiteral("NaN"); | - | ||||||||||||
241 | return; | - | ||||||||||||
242 | } else if (qt_is_inf(num)) { | - | ||||||||||||
243 | *result = num < 0 ? QStringLiteral("-Infinity") : QStringLiteral("Infinity"); | - | ||||||||||||
244 | return; | - | ||||||||||||
245 | } | - | ||||||||||||
246 | - | |||||||||||||
247 | if (radix == 10) { | - | ||||||||||||
248 | // We cannot use our usual locale->toString(...) here, because EcmaScript has special rules | - | ||||||||||||
249 | // about the longest permissible number, depending on if it's <0 or >0. | - | ||||||||||||
250 | const int ecma_shortest_low = -6; | - | ||||||||||||
251 | const int ecma_shortest_high = 21; | - | ||||||||||||
252 | - | |||||||||||||
253 | const QLatin1Char zero('0'); | - | ||||||||||||
254 | const QLatin1Char dot('.'); | - | ||||||||||||
255 | - | |||||||||||||
256 | int decpt = 0; | - | ||||||||||||
257 | int sign = 0; | - | ||||||||||||
258 | *result = qdtoa(num, &decpt, &sign); | - | ||||||||||||
259 | - | |||||||||||||
260 | if (decpt <= ecma_shortest_low || decpt > ecma_shortest_high) { | - | ||||||||||||
261 | if (result->length() > 1) | - | ||||||||||||
262 | result->insert(1, dot); | - | ||||||||||||
263 | result->append(QLatin1Char('e')); | - | ||||||||||||
264 | if (decpt > 0) | - | ||||||||||||
265 | result->append(QLatin1Char('+')); | - | ||||||||||||
266 | result->append(QString::number(decpt - 1)); | - | ||||||||||||
267 | } else if (decpt <= 0) { | - | ||||||||||||
268 | result->prepend(QLatin1String("0.") + QString(-decpt, zero)); | - | ||||||||||||
269 | } else if (decpt < result->length()) { | - | ||||||||||||
270 | result->insert(decpt, dot); | - | ||||||||||||
271 | } else { | - | ||||||||||||
272 | result->append(QString(decpt - result->length(), zero)); | - | ||||||||||||
273 | } | - | ||||||||||||
274 | - | |||||||||||||
275 | if (sign && num) | - | ||||||||||||
276 | result->prepend(QLatin1Char('-')); | - | ||||||||||||
277 | - | |||||||||||||
278 | return; | - | ||||||||||||
279 | } | - | ||||||||||||
280 | - | |||||||||||||
281 | result->clear(); | - | ||||||||||||
282 | bool negative = false; | - | ||||||||||||
283 | - | |||||||||||||
284 | if (num < 0) { | - | ||||||||||||
285 | negative = true; | - | ||||||||||||
286 | num = -num; | - | ||||||||||||
287 | } | - | ||||||||||||
288 | - | |||||||||||||
289 | double frac = num - ::floor(num); | - | ||||||||||||
290 | num = Primitive::toInteger(num); | - | ||||||||||||
291 | - | |||||||||||||
292 | do { | - | ||||||||||||
293 | char c = (char)::fmod(num, radix); | - | ||||||||||||
294 | c = (c < 10) ? (c + '0') : (c - 10 + 'a'); | - | ||||||||||||
295 | result->prepend(QLatin1Char(c)); | - | ||||||||||||
296 | num = ::floor(num / radix); | - | ||||||||||||
297 | } while (num != 0); | - | ||||||||||||
298 | - | |||||||||||||
299 | if (frac != 0) { | - | ||||||||||||
300 | result->append(QLatin1Char('.')); | - | ||||||||||||
301 | do { | - | ||||||||||||
302 | frac = frac * radix; | - | ||||||||||||
303 | char c = (char)::floor(frac); | - | ||||||||||||
304 | c = (c < 10) ? (c + '0') : (c - 10 + 'a'); | - | ||||||||||||
305 | result->append(QLatin1Char(c)); | - | ||||||||||||
306 | frac = frac - ::floor(frac); | - | ||||||||||||
307 | } while (frac != 0); | - | ||||||||||||
308 | } | - | ||||||||||||
309 | - | |||||||||||||
310 | if (negative) | - | ||||||||||||
311 | result->prepend(QLatin1Char('-')); | - | ||||||||||||
312 | } | - | ||||||||||||
313 | - | |||||||||||||
314 | ReturnedValue Runtime::method_closure(ExecutionEngine *engine, int functionId) | - | ||||||||||||
315 | { | - | ||||||||||||
316 | QV4::Function *clos = static_cast<CompiledData::CompilationUnit*>(engine->currentStackFrame->v4Function->compilationUnit)->runtimeFunctions[functionId]; | - | ||||||||||||
317 | Q_ASSERT(clos); | - | ||||||||||||
318 | ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context); | - | ||||||||||||
319 | if (clos->isGenerator()) | - | ||||||||||||
320 | return GeneratorFunction::create(current, clos)->asReturnedValue(); | - | ||||||||||||
321 | return FunctionObject::createScriptFunction(current, clos)->asReturnedValue(); | - | ||||||||||||
322 | } | - | ||||||||||||
323 | - | |||||||||||||
324 | bool Runtime::method_deleteProperty(ExecutionEngine *engine, const Value &base, const Value &index) | - | ||||||||||||
325 | { | - | ||||||||||||
326 | Scope scope(engine); | - | ||||||||||||
327 | ScopedObject o(scope, base.toObject(engine)); | - | ||||||||||||
328 | if (scope.engine->hasException) | - | ||||||||||||
329 | return Encode::undefined(); | - | ||||||||||||
330 | Q_ASSERT(o); | - | ||||||||||||
331 | - | |||||||||||||
332 | ScopedPropertyKey key(scope, index.toPropertyKey(engine)); | - | ||||||||||||
333 | if (engine->hasException) | - | ||||||||||||
334 | return false; | - | ||||||||||||
335 | return o->deleteProperty(key); | - | ||||||||||||
336 | } | - | ||||||||||||
337 | - | |||||||||||||
338 | bool Runtime::method_deleteName(ExecutionEngine *engine, int nameIndex) | - | ||||||||||||
339 | { | - | ||||||||||||
340 | Scope scope(engine); | - | ||||||||||||
341 | ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); | - | ||||||||||||
342 | return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).deleteProperty(name); | - | ||||||||||||
343 | } | - | ||||||||||||
344 | - | |||||||||||||
345 | QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &lval, const Value &rval) | - | ||||||||||||
346 | { | - | ||||||||||||
347 | // 11.8.6, 5: rval must be an Object | - | ||||||||||||
348 | const Object *rhs = rval.as<Object>(); | - | ||||||||||||
349 | if (!rhs) | - | ||||||||||||
350 | return engine->throwTypeError(); | - | ||||||||||||
351 | - | |||||||||||||
352 | Scope scope(engine); | - | ||||||||||||
353 | ScopedValue hasInstance(scope, rhs->get(engine->symbol_hasInstance())); | - | ||||||||||||
354 | if (hasInstance->isUndefined()) | - | ||||||||||||
355 | return rhs->instanceOf(lval); | - | ||||||||||||
356 | FunctionObject *f = hasInstance->as<FunctionObject>(); | - | ||||||||||||
357 | if (!f) | - | ||||||||||||
358 | return engine->throwTypeError(); | - | ||||||||||||
359 | - | |||||||||||||
360 | ScopedValue result(scope, f->call(&rval, &lval, 1)); | - | ||||||||||||
361 | return Encode(result->toBoolean()); | - | ||||||||||||
362 | } | - | ||||||||||||
363 | - | |||||||||||||
364 | QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left, const Value &right) | - | ||||||||||||
365 | { | - | ||||||||||||
366 | Object *ro = right.objectValue(); | - | ||||||||||||
367 | if (!ro) | - | ||||||||||||
368 | return engine->throwTypeError(); | - | ||||||||||||
369 | Scope scope(engine); | - | ||||||||||||
370 | ScopedPropertyKey s(scope, left.toPropertyKey(engine)); | - | ||||||||||||
371 | if (scope.hasException()) | - | ||||||||||||
372 | return Encode::undefined(); | - | ||||||||||||
373 | bool r = ro->hasProperty(s); | - | ||||||||||||
374 | return Encode(r); | - | ||||||||||||
375 | } | - | ||||||||||||
376 | - | |||||||||||||
377 | double RuntimeHelpers::stringToNumber(const QString &string) | - | ||||||||||||
378 | { | - | ||||||||||||
379 | const QStringRef s = QStringRef(&string).trimmed(); | - | ||||||||||||
380 | if (s.startsWith(QLatin1String("0x")) || s.startsWith(QLatin1String("0X"))) | - | ||||||||||||
381 | return s.toLong(nullptr, 16); | - | ||||||||||||
382 | bool ok; | - | ||||||||||||
383 | QByteArray ba = s.toLatin1(); | - | ||||||||||||
384 | const char *begin = ba.constData(); | - | ||||||||||||
385 | const char *end = nullptr; | - | ||||||||||||
386 | double d = qstrtod(begin, &end, &ok); | - | ||||||||||||
387 | if (end - begin != ba.size()) { | - | ||||||||||||
388 | if (ba == "Infinity" || ba == "+Infinity") | - | ||||||||||||
389 | d = Q_INFINITY; | - | ||||||||||||
390 | else if (ba == "-Infinity") | - | ||||||||||||
391 | d = -Q_INFINITY; | - | ||||||||||||
392 | else | - | ||||||||||||
393 | d = std::numeric_limits<double>::quiet_NaN(); | - | ||||||||||||
394 | } | - | ||||||||||||
395 | return d; | - | ||||||||||||
396 | } | - | ||||||||||||
397 | - | |||||||||||||
398 | Heap::String *RuntimeHelpers::stringFromNumber(ExecutionEngine *engine, double number) | - | ||||||||||||
399 | { | - | ||||||||||||
400 | QString qstr; | - | ||||||||||||
401 | RuntimeHelpers::numberToString(&qstr, number, 10); | - | ||||||||||||
402 | return engine->newString(qstr); | - | ||||||||||||
403 | } | - | ||||||||||||
404 | - | |||||||||||||
405 | ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeHint) | - | ||||||||||||
406 | { | - | ||||||||||||
407 | ExecutionEngine *engine = object->internalClass()->engine; | - | ||||||||||||
408 | if (engine->hasException) | - | ||||||||||||
409 | return Encode::undefined(); | - | ||||||||||||
410 | - | |||||||||||||
411 | String *hint; | - | ||||||||||||
412 | switch (typeHint) { | - | ||||||||||||
413 | case STRING_HINT: | - | ||||||||||||
414 | hint = engine->id_string(); | - | ||||||||||||
415 | break; | - | ||||||||||||
416 | case NUMBER_HINT: | - | ||||||||||||
417 | hint = engine->id_number(); | - | ||||||||||||
418 | break; | - | ||||||||||||
419 | default: | - | ||||||||||||
420 | hint = engine->id_default(); | - | ||||||||||||
421 | break; | - | ||||||||||||
422 | } | - | ||||||||||||
423 | - | |||||||||||||
424 | Scope scope(engine); | - | ||||||||||||
425 | ScopedFunctionObject toPrimitive(scope, object->get(engine->symbol_toPrimitive())); | - | ||||||||||||
426 | if (engine->hasException) | - | ||||||||||||
427 | return Encode::undefined(); | - | ||||||||||||
428 | if (toPrimitive) { | - | ||||||||||||
429 | ScopedValue result(scope, toPrimitive->call(object, hint, 1)); | - | ||||||||||||
430 | if (engine->hasException) | - | ||||||||||||
431 | return Encode::undefined(); | - | ||||||||||||
432 | if (!result->isPrimitive()) | - | ||||||||||||
433 | return engine->throwTypeError(); | - | ||||||||||||
434 | return result->asReturnedValue(); | - | ||||||||||||
435 | } | - | ||||||||||||
436 | - | |||||||||||||
437 | if (hint == engine->id_default()) | - | ||||||||||||
438 | hint = engine->id_number(); | - | ||||||||||||
439 | return ordinaryToPrimitive(engine, object, hint); | - | ||||||||||||
440 | } | - | ||||||||||||
441 | - | |||||||||||||
442 | - | |||||||||||||
443 | ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const Object *object, String *typeHint) | - | ||||||||||||
444 | { | - | ||||||||||||
445 | Q_ASSERT(!engine->hasException); | - | ||||||||||||
446 | - | |||||||||||||
447 | String *meth1 = engine->id_toString(); | - | ||||||||||||
448 | String *meth2 = engine->id_valueOf(); | - | ||||||||||||
449 | - | |||||||||||||
450 | if (typeHint->propertyKey() == engine->id_number()->propertyKey()) { | - | ||||||||||||
451 | qSwap(meth1, meth2); | - | ||||||||||||
452 | } else { | - | ||||||||||||
453 | Q_ASSERT(typeHint->propertyKey() == engine->id_string()->propertyKey()); | - | ||||||||||||
454 | } | - | ||||||||||||
455 | - | |||||||||||||
456 | Scope scope(engine); | - | ||||||||||||
457 | ScopedValue result(scope); | - | ||||||||||||
458 | - | |||||||||||||
459 | ScopedValue conv(scope, object->get(meth1)); | - | ||||||||||||
460 | if (FunctionObject *o = conv->as<FunctionObject>()) { | - | ||||||||||||
461 | result = o->call(object, nullptr, 0); | - | ||||||||||||
462 | if (result->isPrimitive()) | - | ||||||||||||
463 | return result->asReturnedValue(); | - | ||||||||||||
464 | } | - | ||||||||||||
465 | - | |||||||||||||
466 | if (engine->hasException) | - | ||||||||||||
467 | return Encode::undefined(); | - | ||||||||||||
468 | - | |||||||||||||
469 | conv = object->get(meth2); | - | ||||||||||||
470 | if (FunctionObject *o = conv->as<FunctionObject>()) { | - | ||||||||||||
471 | result = o->call(object, nullptr, 0); | - | ||||||||||||
472 | if (result->isPrimitive()) | - | ||||||||||||
473 | return result->asReturnedValue(); | - | ||||||||||||
474 | } | - | ||||||||||||
475 | - | |||||||||||||
476 | return engine->throwTypeError(); | - | ||||||||||||
477 | } | - | ||||||||||||
478 | - | |||||||||||||
479 | - | |||||||||||||
480 | Heap::Object *RuntimeHelpers::convertToObject(ExecutionEngine *engine, const Value &value) | - | ||||||||||||
481 | { | - | ||||||||||||
482 | Q_ASSERT(!value.isObject()); | - | ||||||||||||
483 | switch (value.type()) { | - | ||||||||||||
484 | case Value::Undefined_Type: | - | ||||||||||||
485 | engine->throwTypeError(QLatin1String("Value is undefined and could not be converted to an object")); | - | ||||||||||||
486 | return nullptr; | - | ||||||||||||
487 | case Value::Null_Type: | - | ||||||||||||
488 | engine->throwTypeError(QLatin1String("Value is null and could not be converted to an object")); | - | ||||||||||||
489 | return nullptr; | - | ||||||||||||
490 | case Value::Boolean_Type: | - | ||||||||||||
491 | return engine->newBooleanObject(value.booleanValue()); | - | ||||||||||||
492 | case Value::Managed_Type: | - | ||||||||||||
493 | Q_ASSERT(value.isStringOrSymbol()); | - | ||||||||||||
494 | if (!value.isString()) | - | ||||||||||||
495 | return engine->newSymbolObject(value.symbolValue()); | - | ||||||||||||
496 | return engine->newStringObject(value.stringValue()); | - | ||||||||||||
497 | case Value::Integer_Type: | - | ||||||||||||
498 | default: // double | - | ||||||||||||
499 | return engine->newNumberObject(value.asDouble()); | - | ||||||||||||
500 | } | - | ||||||||||||
501 | } | - | ||||||||||||
502 | - | |||||||||||||
503 | Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, Value value, TypeHint hint) | - | ||||||||||||
504 | { | - | ||||||||||||
505 | redo: | - | ||||||||||||
506 | switch (value.type()) { | - | ||||||||||||
507 | case Value::Empty_Type: | - | ||||||||||||
508 | Q_ASSERT(!"empty Value encountered"); | - | ||||||||||||
509 | Q_UNREACHABLE(); | - | ||||||||||||
510 | case Value::Undefined_Type: | - | ||||||||||||
511 | return engine->id_undefined()->d(); | - | ||||||||||||
512 | case Value::Null_Type: | - | ||||||||||||
513 | return engine->id_null()->d(); | - | ||||||||||||
514 | case Value::Boolean_Type: | - | ||||||||||||
515 | if (value.booleanValue()) | - | ||||||||||||
516 | return engine->id_true()->d(); | - | ||||||||||||
517 | else | - | ||||||||||||
518 | return engine->id_false()->d(); | - | ||||||||||||
519 | case Value::Managed_Type: { | - | ||||||||||||
520 | if (value.isString()) | - | ||||||||||||
521 | return static_cast<const String &>(value).d(); | - | ||||||||||||
522 | if (value.isSymbol()) { | - | ||||||||||||
523 | engine->throwTypeError(QLatin1String("Cannot convert a symbol to a string.")); | - | ||||||||||||
524 | return nullptr; | - | ||||||||||||
525 | } | - | ||||||||||||
526 | value = Primitive::fromReturnedValue(RuntimeHelpers::toPrimitive(value, hint)); | - | ||||||||||||
527 | Q_ASSERT(value.isPrimitive()); | - | ||||||||||||
528 | if (value.isString()) | - | ||||||||||||
529 | return static_cast<const String &>(value).d(); | - | ||||||||||||
530 | goto redo; | - | ||||||||||||
531 | } | - | ||||||||||||
532 | case Value::Integer_Type: | - | ||||||||||||
533 | return RuntimeHelpers::stringFromNumber(engine, value.int_32()); | - | ||||||||||||
534 | default: // double | - | ||||||||||||
535 | return RuntimeHelpers::stringFromNumber(engine, value.doubleValue()); | - | ||||||||||||
536 | } // switch | - | ||||||||||||
537 | } | - | ||||||||||||
538 | - | |||||||||||||
539 | // This is slightly different from the method above, as | - | ||||||||||||
540 | // the + operator requires a slightly different conversion | - | ||||||||||||
541 | static Heap::String *convert_to_string_add(ExecutionEngine *engine, Value value) | - | ||||||||||||
542 | { | - | ||||||||||||
543 | return RuntimeHelpers::convertToString(engine, value, PREFERREDTYPE_HINT); | - | ||||||||||||
544 | } | - | ||||||||||||
545 | - | |||||||||||||
546 | QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Value &left, const Value &right) | - | ||||||||||||
547 | { | - | ||||||||||||
548 | Scope scope(engine); | - | ||||||||||||
549 | - | |||||||||||||
550 | ScopedValue pleft(scope, RuntimeHelpers::toPrimitive(left, PREFERREDTYPE_HINT)); | - | ||||||||||||
551 | ScopedValue pright(scope, RuntimeHelpers::toPrimitive(right, PREFERREDTYPE_HINT)); | - | ||||||||||||
552 | String *sleft = pleft->stringValue(); | - | ||||||||||||
553 | String *sright = pright->stringValue(); | - | ||||||||||||
554 | if (sleft || sright) { | - | ||||||||||||
555 | if (!sleft) { | - | ||||||||||||
556 | pleft = convert_to_string_add(engine, pleft); | - | ||||||||||||
557 | sleft = static_cast<String *>(pleft.ptr); | - | ||||||||||||
558 | } | - | ||||||||||||
559 | if (!sright) { | - | ||||||||||||
560 | pright = convert_to_string_add(engine, pright); | - | ||||||||||||
561 | sright = static_cast<String *>(pright.ptr); | - | ||||||||||||
562 | } | - | ||||||||||||
563 | if (engine->hasException) | - | ||||||||||||
564 | return Encode::undefined(); | - | ||||||||||||
565 | if (!sleft->d()->length()) | - | ||||||||||||
566 | return sright->asReturnedValue(); | - | ||||||||||||
567 | if (!sright->d()->length()) | - | ||||||||||||
568 | return sleft->asReturnedValue(); | - | ||||||||||||
569 | MemoryManager *mm = engine->memoryManager; | - | ||||||||||||
570 | return (mm->alloc<ComplexString>(sleft->d(), sright->d()))->asReturnedValue(); | - | ||||||||||||
571 | } | - | ||||||||||||
572 | double x = RuntimeHelpers::toNumber(pleft); | - | ||||||||||||
573 | double y = RuntimeHelpers::toNumber(pright); | - | ||||||||||||
574 | return Encode(x + y); | - | ||||||||||||
575 | } | - | ||||||||||||
576 | - | |||||||||||||
577 | void Runtime::method_storeProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value) | - | ||||||||||||
578 | { | - | ||||||||||||
579 | Scope scope(engine); | - | ||||||||||||
580 | QV4::Function *v4Function = engine->currentStackFrame->v4Function; | - | ||||||||||||
581 | ScopedString name(scope, v4Function->compilationUnit->runtimeStrings[nameIndex]); | - | ||||||||||||
582 | ScopedObject o(scope, object.toObject(engine)); | - | ||||||||||||
583 | if ((!o || !o->put(name, value)) && v4Function->isStrict()) | - | ||||||||||||
584 | engine->throwTypeError(); | - | ||||||||||||
585 | } | - | ||||||||||||
586 | - | |||||||||||||
587 | static Q_NEVER_INLINE ReturnedValue getElementIntFallback(ExecutionEngine *engine, const Value &object, uint idx) | - | ||||||||||||
588 | { | - | ||||||||||||
589 | Q_ASSERT(idx < UINT_MAX); | - | ||||||||||||
590 | Scope scope(engine); | - | ||||||||||||
591 | - | |||||||||||||
592 | ScopedObject o(scope, object); | - | ||||||||||||
593 | if (!o) { | - | ||||||||||||
594 | if (const String *str = object.as<String>()) { | - | ||||||||||||
595 | if (idx >= (uint)str->toQString().length()) { | - | ||||||||||||
596 | return Encode::undefined(); | - | ||||||||||||
597 | } | - | ||||||||||||
598 | const QString s = str->toQString().mid(idx, 1); | - | ||||||||||||
599 | return scope.engine->newString(s)->asReturnedValue(); | - | ||||||||||||
600 | } | - | ||||||||||||
601 | - | |||||||||||||
602 | if (object.isNullOrUndefined()) { | - | ||||||||||||
603 | QString message = QStringLiteral("Cannot read property '%1' of %2").arg(idx).arg(object.toQStringNoThrow()); | - | ||||||||||||
604 | return engine->throwTypeError(message); | - | ||||||||||||
605 | } | - | ||||||||||||
606 | - | |||||||||||||
607 | o = RuntimeHelpers::convertToObject(scope.engine, object); | - | ||||||||||||
608 | Q_ASSERT(!!o); // can't fail as null/undefined is covered above | - | ||||||||||||
609 | } | - | ||||||||||||
610 | - | |||||||||||||
611 | if (o->arrayData() && !o->arrayData()->attrs) { | - | ||||||||||||
612 | ScopedValue v(scope, o->arrayData()->get(idx)); | - | ||||||||||||
613 | if (!v->isEmpty()) | - | ||||||||||||
614 | return v->asReturnedValue(); | - | ||||||||||||
615 | } | - | ||||||||||||
616 | - | |||||||||||||
617 | return o->get(idx); | - | ||||||||||||
618 | } | - | ||||||||||||
619 | - | |||||||||||||
620 | static Q_NEVER_INLINE ReturnedValue getElementFallback(ExecutionEngine *engine, const Value &object, const Value &index) | - | ||||||||||||
621 | { | - | ||||||||||||
622 | Q_ASSERT(!index.isPositiveInt()); | - | ||||||||||||
623 | - | |||||||||||||
624 | Scope scope(engine); | - | ||||||||||||
625 | - | |||||||||||||
626 | ScopedObject o(scope, object); | - | ||||||||||||
627 | if (!o) { | - | ||||||||||||
628 | if (object.isNullOrUndefined()) { | - | ||||||||||||
629 | QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index.toQStringNoThrow()).arg(object.toQStringNoThrow()); | - | ||||||||||||
630 | return engine->throwTypeError(message); | - | ||||||||||||
631 | } | - | ||||||||||||
632 | - | |||||||||||||
633 | o = RuntimeHelpers::convertToObject(scope.engine, object); | - | ||||||||||||
634 | Q_ASSERT(!!o); // can't fail as null/undefined is covered above | - | ||||||||||||
635 | } | - | ||||||||||||
636 | - | |||||||||||||
637 | ScopedPropertyKey name(scope, index.toPropertyKey(engine)); | - | ||||||||||||
638 | if (scope.hasException()) | - | ||||||||||||
639 | return Encode::undefined(); | - | ||||||||||||
640 | return o->get(name); | - | ||||||||||||
641 | } | - | ||||||||||||
642 | - | |||||||||||||
643 | ReturnedValue Runtime::method_loadElement(ExecutionEngine *engine, const Value &object, const Value &index) | - | ||||||||||||
644 | { | - | ||||||||||||
645 | if (index.isPositiveInt()) { | - | ||||||||||||
646 | uint idx = static_cast<uint>(index.int_32()); | - | ||||||||||||
647 | if (Heap::Base *b = object.heapObject()) { | - | ||||||||||||
648 | if (b->internalClass->vtable->isObject) { | - | ||||||||||||
649 | Heap::Object *o = static_cast<Heap::Object *>(b); | - | ||||||||||||
650 | if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) { | - | ||||||||||||
651 | Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>(); | - | ||||||||||||
652 | if (idx < s->values.size) | - | ||||||||||||
653 | if (!s->data(idx).isEmpty()) | - | ||||||||||||
654 | return s->data(idx).asReturnedValue(); | - | ||||||||||||
655 | } | - | ||||||||||||
656 | } | - | ||||||||||||
657 | } | - | ||||||||||||
658 | return getElementIntFallback(engine, object, idx); | - | ||||||||||||
659 | } | - | ||||||||||||
660 | - | |||||||||||||
661 | return getElementFallback(engine, object, index); | - | ||||||||||||
662 | } | - | ||||||||||||
663 | - | |||||||||||||
664 | static Q_NEVER_INLINE bool setElementFallback(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value) | - | ||||||||||||
665 | { | - | ||||||||||||
666 | Scope scope(engine); | - | ||||||||||||
667 | ScopedObject o(scope, object.toObject(engine)); | - | ||||||||||||
668 | if (engine->hasException) | - | ||||||||||||
669 | return false; | - | ||||||||||||
670 | - | |||||||||||||
671 | if (index.isPositiveInt()) { | - | ||||||||||||
672 | uint idx = static_cast<uint>(index.int_32()); | - | ||||||||||||
673 | if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { | - | ||||||||||||
674 | Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); | - | ||||||||||||
675 | if (idx < s->values.size) { | - | ||||||||||||
676 | s->setData(engine, idx, value); | - | ||||||||||||
677 | return true; | - | ||||||||||||
678 | } | - | ||||||||||||
679 | } | - | ||||||||||||
680 | return o->put(idx, value); | - | ||||||||||||
681 | } | - | ||||||||||||
682 | - | |||||||||||||
683 | ScopedPropertyKey name(scope, index.toPropertyKey(engine)); | - | ||||||||||||
684 | if (engine->hasException) | - | ||||||||||||
685 | return false; | - | ||||||||||||
686 | return o->put(name, value); | - | ||||||||||||
687 | } | - | ||||||||||||
688 | - | |||||||||||||
689 | void Runtime::method_storeElement(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value) | - | ||||||||||||
690 | { | - | ||||||||||||
691 | if (index.isPositiveInt()) { | - | ||||||||||||
692 | uint idx = static_cast<uint>(index.int_32()); | - | ||||||||||||
693 | if (Heap::Base *b = object.heapObject()) { | - | ||||||||||||
694 | if (b->internalClass->vtable->isObject) { | - | ||||||||||||
695 | Heap::Object *o = static_cast<Heap::Object *>(b); | - | ||||||||||||
696 | if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) { | - | ||||||||||||
697 | Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>(); | - | ||||||||||||
698 | if (idx < s->values.size) { | - | ||||||||||||
699 | s->setData(engine, idx, value); | - | ||||||||||||
700 | return; | - | ||||||||||||
701 | } | - | ||||||||||||
702 | } | - | ||||||||||||
703 | } | - | ||||||||||||
704 | } | - | ||||||||||||
705 | } | - | ||||||||||||
706 | - | |||||||||||||
707 | if (!setElementFallback(engine, object, index, value) && engine->currentStackFrame->v4Function->isStrict()) | - | ||||||||||||
708 | engine->throwTypeError(); | - | ||||||||||||
709 | } | - | ||||||||||||
710 | - | |||||||||||||
711 | ReturnedValue Runtime::method_getIterator(ExecutionEngine *engine, const Value &in, int iterator) | - | ||||||||||||
712 | { | - | ||||||||||||
713 | Scope scope(engine); | - | ||||||||||||
714 | ScopedObject o(scope, (Object *)nullptr); | - | ||||||||||||
715 | if (!in.isNullOrUndefined()) | - | ||||||||||||
716 | o = in.toObject(engine); | - | ||||||||||||
717 | if (engine->hasException) | - | ||||||||||||
718 | return Encode::undefined(); | - | ||||||||||||
719 | if (iterator) { | - | ||||||||||||
720 | if (!o) | - | ||||||||||||
721 | return engine->throwTypeError(); | - | ||||||||||||
722 | ScopedFunctionObject f(scope, o->get(engine->symbol_iterator())); | - | ||||||||||||
723 | if (!f) | - | ||||||||||||
724 | return engine->throwTypeError(); | - | ||||||||||||
725 | JSCallData cData(scope, 0, nullptr, o); | - | ||||||||||||
726 | ScopedObject it(scope, f->call(cData)); | - | ||||||||||||
727 | if (!it) | - | ||||||||||||
728 | return engine->throwTypeError(); | - | ||||||||||||
729 | return it->asReturnedValue(); | - | ||||||||||||
730 | } | - | ||||||||||||
731 | return engine->newForInIteratorObject(o)->asReturnedValue(); | - | ||||||||||||
732 | } | - | ||||||||||||
733 | - | |||||||||||||
734 | ReturnedValue Runtime::method_iteratorNext(ExecutionEngine *engine, const Value &iterator, Value *value) | - | ||||||||||||
735 | { | - | ||||||||||||
736 | Q_ASSERT(iterator.isObject()); | - | ||||||||||||
737 | - | |||||||||||||
738 | Scope scope(engine); | - | ||||||||||||
739 | ScopedFunctionObject f(scope, static_cast<const Object &>(iterator).get(engine->id_next())); | - | ||||||||||||
740 | if (!f) | - | ||||||||||||
741 | return engine->throwTypeError(); | - | ||||||||||||
742 | JSCallData cData(scope, 0, nullptr, &iterator); | - | ||||||||||||
743 | ScopedObject o(scope, f->call(cData)); | - | ||||||||||||
744 | if (!o) | - | ||||||||||||
745 | return engine->throwTypeError(); | - | ||||||||||||
746 | ScopedValue d(scope, o->get(engine->id_done())); | - | ||||||||||||
747 | bool done = d->toBoolean(); | - | ||||||||||||
748 | if (done) { | - | ||||||||||||
749 | *value = Encode::undefined(); | - | ||||||||||||
750 | } else { | - | ||||||||||||
751 | *value = o->get(engine->id_value()); | - | ||||||||||||
752 | } | - | ||||||||||||
753 | return Encode(done); | - | ||||||||||||
754 | } | - | ||||||||||||
755 | - | |||||||||||||
756 | ReturnedValue Runtime::method_iteratorClose(ExecutionEngine *engine, const Value &iterator, const Value &done) | - | ||||||||||||
757 | { | - | ||||||||||||
758 | Q_ASSERT(iterator.isObject()); | - | ||||||||||||
759 | Q_ASSERT(done.isBoolean()); | - | ||||||||||||
760 | if (done.booleanValue()) | - | ||||||||||||
761 | return Encode::undefined(); | - | ||||||||||||
762 | - | |||||||||||||
763 | Scope scope(engine); | - | ||||||||||||
764 | bool hadException = engine->hasException; | - | ||||||||||||
765 | ScopedValue e(scope); | - | ||||||||||||
766 | if (hadException) { | - | ||||||||||||
767 | e = *engine->exceptionValue; | - | ||||||||||||
768 | engine->hasException = false; | - | ||||||||||||
769 | } | - | ||||||||||||
770 | ScopedFunctionObject f(scope, static_cast<const Object &>(iterator).get(engine->id_return())); | - | ||||||||||||
771 | ScopedObject o(scope); | - | ||||||||||||
772 | if (f) { | - | ||||||||||||
773 | JSCallData cData(scope, 0, nullptr, &iterator); | - | ||||||||||||
774 | o = f->call(cData); | - | ||||||||||||
775 | } | - | ||||||||||||
776 | if (hadException || !f) { | - | ||||||||||||
777 | *engine->exceptionValue = e; | - | ||||||||||||
778 | engine->hasException = hadException; | - | ||||||||||||
779 | return Encode::undefined(); | - | ||||||||||||
780 | } | - | ||||||||||||
781 | if (engine->hasException) | - | ||||||||||||
782 | return Encode::undefined(); | - | ||||||||||||
783 | - | |||||||||||||
784 | if (!o) | - | ||||||||||||
785 | return engine->throwTypeError(); | - | ||||||||||||
786 | return Encode::undefined(); | - | ||||||||||||
787 | } | - | ||||||||||||
788 | - | |||||||||||||
789 | ReturnedValue Runtime::method_destructureRestElement(ExecutionEngine *engine, const Value &iterator) | - | ||||||||||||
790 | { | - | ||||||||||||
791 | Q_ASSERT(iterator.isObject()); | - | ||||||||||||
792 | - | |||||||||||||
793 | Scope scope(engine); | - | ||||||||||||
794 | ScopedArrayObject array(scope, engine->newArrayObject()); | - | ||||||||||||
795 | array->arrayCreate(); | - | ||||||||||||
796 | uint index = 0; | - | ||||||||||||
797 | while (1) { | - | ||||||||||||
798 | ScopedValue n(scope); | - | ||||||||||||
799 | ScopedValue done(scope, method_iteratorNext(engine, iterator, n)); | - | ||||||||||||
800 | if (engine->hasException) | - | ||||||||||||
801 | return Encode::undefined(); | - | ||||||||||||
802 | Q_ASSERT(done->isBoolean()); | - | ||||||||||||
803 | if (done->booleanValue()) | - | ||||||||||||
804 | break; | - | ||||||||||||
805 | array->arraySet(index, n); | - | ||||||||||||
806 | ++index; | - | ||||||||||||
807 | } | - | ||||||||||||
808 | return array->asReturnedValue(); | - | ||||||||||||
809 | } | - | ||||||||||||
810 | - | |||||||||||||
811 | void Runtime::method_storeNameSloppy(ExecutionEngine *engine, int nameIndex, const Value &value) | - | ||||||||||||
812 | { | - | ||||||||||||
813 | Scope scope(engine); | - | ||||||||||||
814 | ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); | - | ||||||||||||
815 | ExecutionContext::Error e = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).setProperty(name, value); | - | ||||||||||||
816 | - | |||||||||||||
817 | if (e == ExecutionContext::RangeError) | - | ||||||||||||
818 | engine->globalObject->put(name, value); | - | ||||||||||||
819 | } | - | ||||||||||||
820 | - | |||||||||||||
821 | void Runtime::method_storeNameStrict(ExecutionEngine *engine, int nameIndex, const Value &value) | - | ||||||||||||
822 | { | - | ||||||||||||
823 | Scope scope(engine); | - | ||||||||||||
824 | ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); | - | ||||||||||||
825 | ExecutionContext::Error e = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).setProperty(name, value); | - | ||||||||||||
826 | if (e == ExecutionContext::TypeError) | - | ||||||||||||
827 | engine->throwTypeError(); | - | ||||||||||||
828 | else if (e == ExecutionContext::RangeError) | - | ||||||||||||
829 | engine->throwReferenceError(name); | - | ||||||||||||
830 | } | - | ||||||||||||
831 | - | |||||||||||||
832 | ReturnedValue Runtime::method_loadProperty(ExecutionEngine *engine, const Value &object, int nameIndex) | - | ||||||||||||
833 | { | - | ||||||||||||
834 | Scope scope(engine); | - | ||||||||||||
835 | ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); | - | ||||||||||||
836 | - | |||||||||||||
837 | ScopedObject o(scope, object); | - | ||||||||||||
838 | if (o) | - | ||||||||||||
839 | return o->get(name); | - | ||||||||||||
840 | - | |||||||||||||
841 | if (object.isNullOrUndefined()) { | - | ||||||||||||
842 | QString message = QStringLiteral("Cannot read property '%1' of %2").arg(name->toQString()).arg(object.toQStringNoThrow()); | - | ||||||||||||
843 | return engine->throwTypeError(message); | - | ||||||||||||
844 | } | - | ||||||||||||
845 | - | |||||||||||||
846 | o = RuntimeHelpers::convertToObject(scope.engine, object); | - | ||||||||||||
847 | if (!o) // type error | - | ||||||||||||
848 | return Encode::undefined(); | - | ||||||||||||
849 | return o->get(name); | - | ||||||||||||
850 | } | - | ||||||||||||
851 | - | |||||||||||||
852 | ReturnedValue Runtime::method_loadName(ExecutionEngine *engine, int nameIndex) | - | ||||||||||||
853 | { | - | ||||||||||||
854 | Scope scope(engine); | - | ||||||||||||
855 | ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); | - | ||||||||||||
856 | return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name); | - | ||||||||||||
857 | } | - | ||||||||||||
858 | - | |||||||||||||
859 | ReturnedValue Runtime::method_loadSuperProperty(ExecutionEngine *engine, const Value &property) | - | ||||||||||||
860 | { | - | ||||||||||||
861 | Scope scope(engine); | - | ||||||||||||
862 | ScopedObject base(scope, engine->currentStackFrame->thisObject()); | - | ||||||||||||
863 | if (!base) | - | ||||||||||||
864 | return engine->throwTypeError(); | - | ||||||||||||
865 | ScopedObject proto(scope, base->getPrototypeOf()); | - | ||||||||||||
866 | if (!proto) | - | ||||||||||||
867 | return engine->throwTypeError(); | - | ||||||||||||
868 | ScopedPropertyKey key(scope, property.toPropertyKey(engine)); | - | ||||||||||||
869 | if (engine->hasException) | - | ||||||||||||
870 | return Encode::undefined(); | - | ||||||||||||
871 | return proto->get(key, base); | - | ||||||||||||
872 | } | - | ||||||||||||
873 | - | |||||||||||||
874 | void Runtime::method_storeSuperProperty(ExecutionEngine *engine, const Value &property, const Value &value) | - | ||||||||||||
875 | { | - | ||||||||||||
876 | Scope scope(engine); | - | ||||||||||||
877 | ScopedObject base(scope, engine->currentStackFrame->thisObject()); | - | ||||||||||||
878 | if (!base) { | - | ||||||||||||
879 | engine->throwTypeError(); | - | ||||||||||||
880 | return; | - | ||||||||||||
881 | } | - | ||||||||||||
882 | ScopedObject proto(scope, base->getPrototypeOf()); | - | ||||||||||||
883 | if (!proto) { | - | ||||||||||||
884 | engine->throwTypeError(); | - | ||||||||||||
885 | return; | - | ||||||||||||
886 | } | - | ||||||||||||
887 | ScopedPropertyKey key(scope, property.toPropertyKey(engine)); | - | ||||||||||||
888 | if (engine->hasException) | - | ||||||||||||
889 | return; | - | ||||||||||||
890 | bool result = proto->put(key, value, base); | - | ||||||||||||
891 | if (!result && engine->currentStackFrame->v4Function->isStrict()) | - | ||||||||||||
892 | engine->throwTypeError(); | - | ||||||||||||
893 | } | - | ||||||||||||
894 | - | |||||||||||||
895 | #endif // V4_BOOTSTRAP | - | ||||||||||||
896 | - | |||||||||||||
897 | uint RuntimeHelpers::equalHelper(const Value &x, const Value &y) | - | ||||||||||||
898 | { | - | ||||||||||||
899 | Q_ASSERT(x.type() != y.type() || (x.isManaged() && (x.isString() != y.isString()))); | - | ||||||||||||
900 | - | |||||||||||||
901 | if (x.isNumber() && y.isNumber())
| 0 | ||||||||||||
902 | return x.asDouble() == y.asDouble(); never executed: return x.asDouble() == y.asDouble(); | 0 | ||||||||||||
903 | if (x.isNull() && y.isUndefined()) {
| 0 | ||||||||||||
904 | return true; never executed: return true; | 0 | ||||||||||||
905 | } else if (x.isUndefined() && y.isNull()) {
| 0 | ||||||||||||
906 | return true; never executed: return true; | 0 | ||||||||||||
907 | } else if (x.isNumber() && y.isString()) {
| 0 | ||||||||||||
908 | double dy = RuntimeHelpers::toNumber(y); | - | ||||||||||||
909 | return x.asDouble() == dy; never executed: return x.asDouble() == dy; | 0 | ||||||||||||
910 | } else if (x.isString() && y.isNumber()) {
| 0 | ||||||||||||
911 | double dx = RuntimeHelpers::toNumber(x); | - | ||||||||||||
912 | return dx == y.asDouble(); never executed: return dx == y.asDouble(); | 0 | ||||||||||||
913 | } else if (x.isBoolean()) {
| 0 | ||||||||||||
914 | return Runtime::method_compareEqual(Primitive::fromDouble((double) x.booleanValue()), y); never executed: return Runtime::method_compareEqual(Primitive::fromDouble((double) x.booleanValue()), y); | 0 | ||||||||||||
915 | } else if (y.isBoolean()) {
| 0 | ||||||||||||
916 | return Runtime::method_compareEqual(x, Primitive::fromDouble((double) y.booleanValue())); never executed: return Runtime::method_compareEqual(x, Primitive::fromDouble((double) y.booleanValue())); | 0 | ||||||||||||
917 | } else { | - | ||||||||||||
918 | #ifdef V4_BOOTSTRAP | - | ||||||||||||
919 | Q_UNIMPLEMENTED(); | - | ||||||||||||
920 | #else | - | ||||||||||||
921 | Object *xo = x.objectValue(); | - | ||||||||||||
922 | Object *yo = y.objectValue(); | - | ||||||||||||
923 | if (yo && (x.isNumber() || x.isString())) { | - | ||||||||||||
924 | Scope scope(yo->engine()); | - | ||||||||||||
925 | ScopedValue py(scope, RuntimeHelpers::objectDefaultValue(yo, PREFERREDTYPE_HINT)); | - | ||||||||||||
926 | return Runtime::method_compareEqual(x, py); | - | ||||||||||||
927 | } else if (xo && (y.isNumber() || y.isString())) { | - | ||||||||||||
928 | Scope scope(xo->engine()); | - | ||||||||||||
929 | ScopedValue px(scope, RuntimeHelpers::objectDefaultValue(xo, PREFERREDTYPE_HINT)); | - | ||||||||||||
930 | return Runtime::method_compareEqual(px, y); | - | ||||||||||||
931 | } | - | ||||||||||||
932 | #endif | - | ||||||||||||
933 | } never executed: end of block | 0 | ||||||||||||
934 | - | |||||||||||||
935 | return false; never executed: return false; | 0 | ||||||||||||
936 | } | - | ||||||||||||
937 | - | |||||||||||||
938 | Bool RuntimeHelpers::strictEqual(const Value &x, const Value &y) | - | ||||||||||||
939 | { | - | ||||||||||||
940 | TRACE2(x, y); | - | ||||||||||||
941 | - | |||||||||||||
942 | if (x.rawValue() == y.rawValue())
| 16337-31668862 | ||||||||||||
943 | // NaN != NaN | - | ||||||||||||
944 | return !x.isNaN(); executed 16337 times by 10 tests: return !x.isNaN(); Executed by:
| 16337 | ||||||||||||
945 | - | |||||||||||||
946 | if (x.isNumber())
| 13114268-18551307 | ||||||||||||
947 | return y.isNumber() && x.asDouble() == y.asDouble(); executed 18551304 times by 15 tests: return y.isNumber() && x.asDouble() == y.asDouble(); Executed by:
| 18551304 | ||||||||||||
948 | if (x.isManaged())
| 297603-12838325 | ||||||||||||
949 | return y.isManaged() && x.cast<Managed>()->isEqualTo(y.cast<Managed>()); executed 12839433 times by 15 tests: return y.isManaged() && x.cast<Managed>()->isEqualTo(y.cast<Managed>()); Executed by:
| 12839433 | ||||||||||||
950 | return false; executed 297615 times by 9 tests: return false; Executed by:
| 297615 | ||||||||||||
951 | } | - | ||||||||||||
952 | - | |||||||||||||
953 | QV4::Bool Runtime::method_compareGreaterThan(const Value &l, const Value &r) | - | ||||||||||||
954 | { | - | ||||||||||||
955 | TRACE2(l, r); | - | ||||||||||||
956 | if (l.isInteger() && r.isInteger())
| 39-3684 | ||||||||||||
957 | return l.integerValue() > r.integerValue(); executed 38 times by 1 test: return l.integerValue() > r.integerValue(); Executed by:
| 38 | ||||||||||||
958 | if (l.isNumber() && r.isNumber())
| 87-2730 | ||||||||||||
959 | return l.asDouble() > r.asDouble(); executed 2642 times by 9 tests: return l.asDouble() > r.asDouble(); Executed by:
| 2642 | ||||||||||||
960 | String *sl = l.stringValue(); | - | ||||||||||||
961 | String *sr = r.stringValue(); | - | ||||||||||||
962 | if (sl && sr) {
| 64-703 | ||||||||||||
963 | #ifdef V4_BOOTSTRAP | - | ||||||||||||
964 | Q_UNIMPLEMENTED(); | - | ||||||||||||
965 | return false; never executed: return false; | 0 | ||||||||||||
966 | #else | - | ||||||||||||
967 | return sr->compare(sl); | - | ||||||||||||
968 | #endif | - | ||||||||||||
969 | } | - | ||||||||||||
970 | - | |||||||||||||
971 | Object *ro = r.objectValue(); | - | ||||||||||||
972 | Object *lo = l.objectValue(); | - | ||||||||||||
973 | if (ro || lo) {
| 76-323 | ||||||||||||
974 | #ifdef V4_BOOTSTRAP | - | ||||||||||||
975 | Q_UNIMPLEMENTED(); | - | ||||||||||||
976 | #else | - | ||||||||||||
977 | QV4::ExecutionEngine *e = (lo ? lo : ro)->engine(); | - | ||||||||||||
978 | QV4::Scope scope(e); | - | ||||||||||||
979 | QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); | - | ||||||||||||
980 | QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); | - | ||||||||||||
981 | return Runtime::method_compareGreaterThan(pl, pr); | - | ||||||||||||
982 | #endif | - | ||||||||||||
983 | } never executed: end of block | 0 | ||||||||||||
984 | - | |||||||||||||
985 | double dl = RuntimeHelpers::toNumber(l); | - | ||||||||||||
986 | double dr = RuntimeHelpers::toNumber(r); | - | ||||||||||||
987 | return dl > dr; executed 248 times by 1 test: return dl > dr; Executed by:
| 248 | ||||||||||||
988 | } | - | ||||||||||||
989 | - | |||||||||||||
990 | QV4::Bool Runtime::method_compareLessThan(const Value &l, const Value &r) | - | ||||||||||||
991 | { | - | ||||||||||||
992 | TRACE2(l, r); | - | ||||||||||||
993 | if (l.isInteger() && r.isInteger())
| 24-3229 | ||||||||||||
994 | return l.integerValue() < r.integerValue(); executed 24 times by 1 test: return l.integerValue() < r.integerValue(); Executed by:
| 24 | ||||||||||||
995 | if (l.isNumber() && r.isNumber())
| 88-3139 | ||||||||||||
996 | return l.asDouble() < r.asDouble(); executed 320 times by 6 tests: return l.asDouble() < r.asDouble(); Executed by:
| 320 | ||||||||||||
997 | String *sl = l.stringValue(); | - | ||||||||||||
998 | String *sr = r.stringValue(); | - | ||||||||||||
999 | if (sl && sr) {
| 216-2834 | ||||||||||||
1000 | #ifdef V4_BOOTSTRAP | - | ||||||||||||
1001 | Q_UNIMPLEMENTED(); | - | ||||||||||||
1002 | return false; never executed: return false; | 0 | ||||||||||||
1003 | #else | - | ||||||||||||
1004 | return sl->compare(sr); | - | ||||||||||||
1005 | #endif | - | ||||||||||||
1006 | } | - | ||||||||||||
1007 | - | |||||||||||||
1008 | Object *ro = r.objectValue(); | - | ||||||||||||
1009 | Object *lo = l.objectValue(); | - | ||||||||||||
1010 | if (ro || lo) {
| 80-472 | ||||||||||||
1011 | #ifdef V4_BOOTSTRAP | - | ||||||||||||
1012 | Q_UNIMPLEMENTED(); | - | ||||||||||||
1013 | #else | - | ||||||||||||
1014 | QV4::ExecutionEngine *e = (lo ? lo : ro)->engine(); | - | ||||||||||||
1015 | QV4::Scope scope(e); | - | ||||||||||||
1016 | QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); | - | ||||||||||||
1017 | QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); | - | ||||||||||||
1018 | return Runtime::method_compareLessThan(pl, pr); | - | ||||||||||||
1019 | #endif | - | ||||||||||||
1020 | } never executed: end of block | 0 | ||||||||||||
1021 | - | |||||||||||||
1022 | double dl = RuntimeHelpers::toNumber(l); | - | ||||||||||||
1023 | double dr = RuntimeHelpers::toNumber(r); | - | ||||||||||||
1024 | return dl < dr; executed 392 times by 2 tests: return dl < dr; Executed by:
| 392 | ||||||||||||
1025 | } | - | ||||||||||||
1026 | - | |||||||||||||
1027 | QV4::Bool Runtime::method_compareGreaterEqual(const Value &l, const Value &r) | - | ||||||||||||
1028 | { | - | ||||||||||||
1029 | TRACE2(l, r); | - | ||||||||||||
1030 | if (l.isInteger() && r.isInteger())
| 24-891 | ||||||||||||
1031 | return l.integerValue() >= r.integerValue(); executed 24 times by 1 test: return l.integerValue() >= r.integerValue(); Executed by:
| 24 | ||||||||||||
1032 | if (l.isNumber() && r.isNumber())
| 88-534 | ||||||||||||
1033 | return l.asDouble() >= r.asDouble(); executed 338 times by 4 tests: return l.asDouble() >= r.asDouble(); Executed by:
| 338 | ||||||||||||
1034 | String *sl = l.stringValue(); | - | ||||||||||||
1035 | String *sr = r.stringValue(); | - | ||||||||||||
1036 | if (sl && sr) {
| 64-392 | ||||||||||||
1037 | #ifdef V4_BOOTSTRAP | - | ||||||||||||
1038 | Q_UNIMPLEMENTED(); | - | ||||||||||||
1039 | return false; never executed: return false; | 0 | ||||||||||||
1040 | #else | - | ||||||||||||
1041 | return !sl->compare(sr); | - | ||||||||||||
1042 | #endif | - | ||||||||||||
1043 | } | - | ||||||||||||
1044 | - | |||||||||||||
1045 | Object *ro = r.objectValue(); | - | ||||||||||||
1046 | Object *lo = l.objectValue(); | - | ||||||||||||
1047 | if (ro || lo) {
| 75-324 | ||||||||||||
1048 | #ifdef V4_BOOTSTRAP | - | ||||||||||||
1049 | Q_UNIMPLEMENTED(); | - | ||||||||||||
1050 | #else | - | ||||||||||||
1051 | QV4::ExecutionEngine *e = (lo ? lo : ro)->engine(); | - | ||||||||||||
1052 | QV4::Scope scope(e); | - | ||||||||||||
1053 | QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); | - | ||||||||||||
1054 | QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); | - | ||||||||||||
1055 | return Runtime::method_compareGreaterEqual(pl, pr); | - | ||||||||||||
1056 | #endif | - | ||||||||||||
1057 | } never executed: end of block | 0 | ||||||||||||
1058 | - | |||||||||||||
1059 | double dl = RuntimeHelpers::toNumber(l); | - | ||||||||||||
1060 | double dr = RuntimeHelpers::toNumber(r); | - | ||||||||||||
1061 | return dl >= dr; executed 247 times by 1 test: return dl >= dr; Executed by:
| 247 | ||||||||||||
1062 | } | - | ||||||||||||
1063 | - | |||||||||||||
1064 | QV4::Bool Runtime::method_compareLessEqual(const Value &l, const Value &r) | - | ||||||||||||
1065 | { | - | ||||||||||||
1066 | TRACE2(l, r); | - | ||||||||||||
1067 | if (l.isInteger() && r.isInteger())
| 44-7457 | ||||||||||||
1068 | return l.integerValue() <= r.integerValue(); executed 44 times by 1 test: return l.integerValue() <= r.integerValue(); Executed by:
| 44 | ||||||||||||
1069 | if (l.isNumber() && r.isNumber())
| 88-7234 | ||||||||||||
1070 | return l.asDouble() <= r.asDouble(); executed 202 times by 6 tests: return l.asDouble() <= r.asDouble(); Executed by:
| 202 | ||||||||||||
1071 | String *sl = l.stringValue(); | - | ||||||||||||
1072 | String *sr = r.stringValue(); | - | ||||||||||||
1073 | if (sl && sr) {
| 64-6913 | ||||||||||||
1074 | #ifdef V4_BOOTSTRAP | - | ||||||||||||
1075 | Q_UNIMPLEMENTED(); | - | ||||||||||||
1076 | return false; never executed: return false; | 0 | ||||||||||||
1077 | #else | - | ||||||||||||
1078 | return !sr->compare(sl); | - | ||||||||||||
1079 | #endif | - | ||||||||||||
1080 | } | - | ||||||||||||
1081 | - | |||||||||||||
1082 | Object *ro = r.objectValue(); | - | ||||||||||||
1083 | Object *lo = l.objectValue(); | - | ||||||||||||
1084 | if (ro || lo) {
| 76-324 | ||||||||||||
1085 | #ifdef V4_BOOTSTRAP | - | ||||||||||||
1086 | Q_UNIMPLEMENTED(); | - | ||||||||||||
1087 | #else | - | ||||||||||||
1088 | QV4::ExecutionEngine *e = (lo ? lo : ro)->engine(); | - | ||||||||||||
1089 | QV4::Scope scope(e); | - | ||||||||||||
1090 | QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); | - | ||||||||||||
1091 | QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); | - | ||||||||||||
1092 | return Runtime::method_compareLessEqual(pl, pr); | - | ||||||||||||
1093 | #endif | - | ||||||||||||
1094 | } never executed: end of block | 0 | ||||||||||||
1095 | - | |||||||||||||
1096 | double dl = RuntimeHelpers::toNumber(l); | - | ||||||||||||
1097 | double dr = RuntimeHelpers::toNumber(r); | - | ||||||||||||
1098 | return dl <= dr; executed 245 times by 1 test: return dl <= dr; Executed by:
| 245 | ||||||||||||
1099 | } | - | ||||||||||||
1100 | - | |||||||||||||
1101 | #ifndef V4_BOOTSTRAP | - | ||||||||||||
1102 | Bool Runtime::method_compareInstanceof(ExecutionEngine *engine, const Value &left, const Value &right) | - | ||||||||||||
1103 | { | - | ||||||||||||
1104 | TRACE2(left, right); | - | ||||||||||||
1105 | - | |||||||||||||
1106 | Scope scope(engine); | - | ||||||||||||
1107 | ScopedValue v(scope, method_instanceof(engine, left, right)); | - | ||||||||||||
1108 | return v->booleanValue(); | - | ||||||||||||
1109 | } | - | ||||||||||||
1110 | - | |||||||||||||
1111 | uint Runtime::method_compareIn(ExecutionEngine *engine, const Value &left, const Value &right) | - | ||||||||||||
1112 | { | - | ||||||||||||
1113 | TRACE2(left, right); | - | ||||||||||||
1114 | - | |||||||||||||
1115 | Scope scope(engine); | - | ||||||||||||
1116 | ScopedValue v(scope, method_in(engine, left, right)); | - | ||||||||||||
1117 | return v->booleanValue(); | - | ||||||||||||
1118 | } | - | ||||||||||||
1119 | - | |||||||||||||
1120 | - | |||||||||||||
1121 | ReturnedValue Runtime::method_callGlobalLookup(ExecutionEngine *engine, uint index, Value *argv, int argc) | - | ||||||||||||
1122 | { | - | ||||||||||||
1123 | Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index; | - | ||||||||||||
1124 | Value function = Value::fromReturnedValue(l->globalGetter(l, engine)); | - | ||||||||||||
1125 | if (!function.isFunctionObject()) | - | ||||||||||||
1126 | return engine->throwTypeError(); | - | ||||||||||||
1127 | - | |||||||||||||
1128 | Value thisObject = Primitive::undefinedValue(); | - | ||||||||||||
1129 | return static_cast<FunctionObject &>(function).call(&thisObject, argv, argc); | - | ||||||||||||
1130 | } | - | ||||||||||||
1131 | - | |||||||||||||
1132 | ReturnedValue Runtime::method_callPossiblyDirectEval(ExecutionEngine *engine, Value *argv, int argc) | - | ||||||||||||
1133 | { | - | ||||||||||||
1134 | Scope scope(engine); | - | ||||||||||||
1135 | ScopedValue thisObject(scope); | - | ||||||||||||
1136 | - | |||||||||||||
1137 | ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context); | - | ||||||||||||
1138 | ScopedFunctionObject function(scope, ctx.getPropertyAndBase(engine->id_eval(), thisObject)); | - | ||||||||||||
1139 | if (engine->hasException) | - | ||||||||||||
1140 | return Encode::undefined(); | - | ||||||||||||
1141 | - | |||||||||||||
1142 | if (!function) { | - | ||||||||||||
1143 | QString objectAsString = QStringLiteral("[null]"); | - | ||||||||||||
1144 | if (!thisObject->isUndefined()) | - | ||||||||||||
1145 | objectAsString = thisObject->toQStringNoThrow(); | - | ||||||||||||
1146 | QString msg = QStringLiteral("Property 'eval' of object %2 is not a function").arg(objectAsString); | - | ||||||||||||
1147 | return engine->throwTypeError(msg); | - | ||||||||||||
1148 | } | - | ||||||||||||
1149 | - | |||||||||||||
1150 | if (function->d() == engine->evalFunction()->d()) | - | ||||||||||||
1151 | return static_cast<EvalFunction *>(function.getPointer())->evalCall(thisObject, argv, argc, true); | - | ||||||||||||
1152 | - | |||||||||||||
1153 | return function->call(thisObject, argv, argc); | - | ||||||||||||
1154 | } | - | ||||||||||||
1155 | - | |||||||||||||
1156 | ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, Value *argv, int argc) | - | ||||||||||||
1157 | { | - | ||||||||||||
1158 | Scope scope(engine); | - | ||||||||||||
1159 | ScopedValue thisObject(scope); | - | ||||||||||||
1160 | ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); | - | ||||||||||||
1161 | - | |||||||||||||
1162 | ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context); | - | ||||||||||||
1163 | ScopedFunctionObject f(scope, ctx.getPropertyAndBase(name, thisObject)); | - | ||||||||||||
1164 | if (engine->hasException) | - | ||||||||||||
1165 | return Encode::undefined(); | - | ||||||||||||
1166 | - | |||||||||||||
1167 | if (!f) { | - | ||||||||||||
1168 | QString objectAsString = QStringLiteral("[null]"); | - | ||||||||||||
1169 | if (!thisObject->isUndefined()) | - | ||||||||||||
1170 | objectAsString = thisObject->toQStringNoThrow(); | - | ||||||||||||
1171 | QString msg = QStringLiteral("Property '%1' of object %2 is not a function") | - | ||||||||||||
1172 | .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString(), | - | ||||||||||||
1173 | objectAsString); | - | ||||||||||||
1174 | return engine->throwTypeError(msg); | - | ||||||||||||
1175 | } | - | ||||||||||||
1176 | - | |||||||||||||
1177 | return f->call(thisObject, argv, argc); | - | ||||||||||||
1178 | } | - | ||||||||||||
1179 | - | |||||||||||||
1180 | ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, Value *base, int nameIndex, Value *argv, int argc) | - | ||||||||||||
1181 | { | - | ||||||||||||
1182 | Scope scope(engine); | - | ||||||||||||
1183 | ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); | - | ||||||||||||
1184 | ScopedObject lookupObject(scope, base); | - | ||||||||||||
1185 | - | |||||||||||||
1186 | if (!lookupObject) { | - | ||||||||||||
1187 | Q_ASSERT(!base->isEmpty()); | - | ||||||||||||
1188 | if (base->isNullOrUndefined()) { | - | ||||||||||||
1189 | QString message = QStringLiteral("Cannot call method '%1' of %2") | - | ||||||||||||
1190 | .arg(name->toQString(), base->toQStringNoThrow()); | - | ||||||||||||
1191 | return engine->throwTypeError(message); | - | ||||||||||||
1192 | } | - | ||||||||||||
1193 | - | |||||||||||||
1194 | if (base->isManaged()) { | - | ||||||||||||
1195 | Managed *m = static_cast<Managed *>(base); | - | ||||||||||||
1196 | lookupObject = m->internalClass()->prototype; | - | ||||||||||||
1197 | Q_ASSERT(m->internalClass()->prototype); | - | ||||||||||||
1198 | } else { | - | ||||||||||||
1199 | lookupObject = RuntimeHelpers::convertToObject(engine, *base); | - | ||||||||||||
1200 | if (engine->hasException) // type error | - | ||||||||||||
1201 | return Encode::undefined(); | - | ||||||||||||
1202 | if (!engine->currentStackFrame->v4Function->isStrict()) | - | ||||||||||||
1203 | base = lookupObject; | - | ||||||||||||
1204 | } | - | ||||||||||||
1205 | } | - | ||||||||||||
1206 | - | |||||||||||||
1207 | ScopedFunctionObject f(scope, static_cast<Object *>(lookupObject)->get(name)); | - | ||||||||||||
1208 | - | |||||||||||||
1209 | if (!f) { | - | ||||||||||||
1210 | QString error = QStringLiteral("Property '%1' of object %2 is not a function") | - | ||||||||||||
1211 | .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString(), | - | ||||||||||||
1212 | base->toQStringNoThrow()); | - | ||||||||||||
1213 | return engine->throwTypeError(error); | - | ||||||||||||
1214 | } | - | ||||||||||||
1215 | - | |||||||||||||
1216 | return f->call(base, argv, argc); | - | ||||||||||||
1217 | } | - | ||||||||||||
1218 | - | |||||||||||||
1219 | ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, Value *base, uint index, Value *argv, int argc) | - | ||||||||||||
1220 | { | - | ||||||||||||
1221 | Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index; | - | ||||||||||||
1222 | // ok to have the value on the stack here | - | ||||||||||||
1223 | Value f = Value::fromReturnedValue(l->getter(l, engine, *base)); | - | ||||||||||||
1224 | - | |||||||||||||
1225 | if (!f.isFunctionObject()) | - | ||||||||||||
1226 | return engine->throwTypeError(); | - | ||||||||||||
1227 | - | |||||||||||||
1228 | return static_cast<FunctionObject &>(f).call(base, argv, argc); | - | ||||||||||||
1229 | } | - | ||||||||||||
1230 | - | |||||||||||||
1231 | ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, Value *base, const Value &index, Value *argv, int argc) | - | ||||||||||||
1232 | { | - | ||||||||||||
1233 | Scope scope(engine); | - | ||||||||||||
1234 | ScopedValue thisObject(scope, base->toObject(engine)); | - | ||||||||||||
1235 | base = thisObject; | - | ||||||||||||
1236 | - | |||||||||||||
1237 | ScopedPropertyKey str(scope, index.toPropertyKey(engine)); | - | ||||||||||||
1238 | if (engine->hasException) | - | ||||||||||||
1239 | return Encode::undefined(); | - | ||||||||||||
1240 | - | |||||||||||||
1241 | ScopedFunctionObject f(scope, static_cast<Object *>(base)->get(str)); | - | ||||||||||||
1242 | if (!f) | - | ||||||||||||
1243 | return engine->throwTypeError(); | - | ||||||||||||
1244 | - | |||||||||||||
1245 | return f->call(base, argv, argc); | - | ||||||||||||
1246 | } | - | ||||||||||||
1247 | - | |||||||||||||
1248 | ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &func, Value *argv, int argc) | - | ||||||||||||
1249 | { | - | ||||||||||||
1250 | if (!func.isFunctionObject()) | - | ||||||||||||
1251 | return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow())); | - | ||||||||||||
1252 | return static_cast<const FunctionObject &>(func).call(nullptr, argv, argc); | - | ||||||||||||
1253 | } | - | ||||||||||||
1254 | - | |||||||||||||
1255 | ReturnedValue Runtime::method_callQmlScopeObjectProperty(ExecutionEngine *engine, Value *base, | - | ||||||||||||
1256 | int propertyIndex, Value *argv, int argc) | - | ||||||||||||
1257 | { | - | ||||||||||||
1258 | Scope scope(engine); | - | ||||||||||||
1259 | ScopedFunctionObject fo(scope, method_loadQmlScopeObjectProperty(engine, *base, propertyIndex, | - | ||||||||||||
1260 | /*captureRequired*/true)); | - | ||||||||||||
1261 | if (!fo) { | - | ||||||||||||
1262 | QString error = QStringLiteral("Property '%1' of scope object is not a function").arg(propertyIndex); | - | ||||||||||||
1263 | return engine->throwTypeError(error); | - | ||||||||||||
1264 | } | - | ||||||||||||
1265 | - | |||||||||||||
1266 | QObject *qmlScopeObj = static_cast<QmlContext *>(base)->d()->qml()->scopeObject; | - | ||||||||||||
1267 | ScopedValue qmlScopeValue(scope, QObjectWrapper::wrap(engine, qmlScopeObj)); | - | ||||||||||||
1268 | return fo->call(qmlScopeValue, argv, argc); | - | ||||||||||||
1269 | } | - | ||||||||||||
1270 | - | |||||||||||||
1271 | ReturnedValue Runtime::method_callQmlContextObjectProperty(ExecutionEngine *engine, Value *base, | - | ||||||||||||
1272 | int propertyIndex, Value *argv, int argc) | - | ||||||||||||
1273 | { | - | ||||||||||||
1274 | Scope scope(engine); | - | ||||||||||||
1275 | ScopedFunctionObject fo(scope, method_loadQmlContextObjectProperty(engine, *base, propertyIndex, | - | ||||||||||||
1276 | /*captureRequired*/true)); | - | ||||||||||||
1277 | if (!fo) { | - | ||||||||||||
1278 | QString error = QStringLiteral("Property '%1' of context object is not a function").arg(propertyIndex); | - | ||||||||||||
1279 | return engine->throwTypeError(error); | - | ||||||||||||
1280 | } | - | ||||||||||||
1281 | - | |||||||||||||
1282 | QObject *qmlContextObj = static_cast<QmlContext *>(base)->d()->qml()->context->contextData()->contextObject; | - | ||||||||||||
1283 | ScopedValue qmlContextValue(scope, QObjectWrapper::wrap(engine, qmlContextObj)); | - | ||||||||||||
1284 | return fo->call(qmlContextValue, argv, argc); | - | ||||||||||||
1285 | } | - | ||||||||||||
1286 | - | |||||||||||||
1287 | struct CallArgs { | - | ||||||||||||
1288 | Value *argv; | - | ||||||||||||
1289 | int argc; | - | ||||||||||||
1290 | }; | - | ||||||||||||
1291 | - | |||||||||||||
1292 | static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc) | - | ||||||||||||
1293 | { | - | ||||||||||||
1294 | ScopedValue it(scope); | - | ||||||||||||
1295 | ScopedValue done(scope); | - | ||||||||||||
1296 | - | |||||||||||||
1297 | int argCount = 0; | - | ||||||||||||
1298 | - | |||||||||||||
1299 | Value *v = scope.alloc<Scope::Uninitialized>(); | - | ||||||||||||
1300 | Value *arguments = v; | - | ||||||||||||
1301 | for (int i = 0; i < argc; ++i) { | - | ||||||||||||
1302 | if (!argv[i].isEmpty()) { | - | ||||||||||||
1303 | *v = argv[i]; | - | ||||||||||||
1304 | ++argCount; | - | ||||||||||||
1305 | v = scope.alloc<Scope::Uninitialized>(); | - | ||||||||||||
1306 | continue; | - | ||||||||||||
1307 | } | - | ||||||||||||
1308 | // spread element | - | ||||||||||||
1309 | ++i; | - | ||||||||||||
1310 | it = Runtime::method_getIterator(scope.engine, argv[i], /* ForInIterator */ 1); | - | ||||||||||||
1311 | if (scope.engine->hasException) | - | ||||||||||||
1312 | return { nullptr, 0 }; | - | ||||||||||||
1313 | while (1) { | - | ||||||||||||
1314 | done = Runtime::method_iteratorNext(scope.engine, it, v); | - | ||||||||||||
1315 | if (scope.engine->hasException) | - | ||||||||||||
1316 | return { nullptr, 0 }; | - | ||||||||||||
1317 | Q_ASSERT(done->isBoolean()); | - | ||||||||||||
1318 | if (done->booleanValue()) | - | ||||||||||||
1319 | break; | - | ||||||||||||
1320 | ++argCount; | - | ||||||||||||
1321 | v = scope.alloc<Scope::Uninitialized>(); | - | ||||||||||||
1322 | } | - | ||||||||||||
1323 | } | - | ||||||||||||
1324 | return { arguments, argCount }; | - | ||||||||||||
1325 | } | - | ||||||||||||
1326 | - | |||||||||||||
1327 | ReturnedValue Runtime::method_callWithSpread(ExecutionEngine *engine, const Value &function, const Value &thisObject, Value *argv, int argc) | - | ||||||||||||
1328 | { | - | ||||||||||||
1329 | Q_ASSERT(argc >= 1); | - | ||||||||||||
1330 | if (!function.isFunctionObject()) | - | ||||||||||||
1331 | return engine->throwTypeError(); | - | ||||||||||||
1332 | - | |||||||||||||
1333 | Scope scope(engine); | - | ||||||||||||
1334 | CallArgs arguments = createSpreadArguments(scope, argv, argc); | - | ||||||||||||
1335 | if (engine->hasException) | - | ||||||||||||
1336 | return Encode::undefined(); | - | ||||||||||||
1337 | - | |||||||||||||
1338 | return static_cast<const FunctionObject &>(function).call(&thisObject, arguments.argv, arguments.argc); | - | ||||||||||||
1339 | } | - | ||||||||||||
1340 | - | |||||||||||||
1341 | ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc) | - | ||||||||||||
1342 | { | - | ||||||||||||
1343 | if (!function.isFunctionObject()) | - | ||||||||||||
1344 | return engine->throwTypeError(); | - | ||||||||||||
1345 | - | |||||||||||||
1346 | return static_cast<const FunctionObject &>(function).callAsConstructor(argv, argc, &newTarget); | - | ||||||||||||
1347 | } | - | ||||||||||||
1348 | - | |||||||||||||
1349 | ReturnedValue Runtime::method_constructWithSpread(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc) | - | ||||||||||||
1350 | { | - | ||||||||||||
1351 | Q_UNIMPLEMENTED(); | - | ||||||||||||
1352 | if (!function.isFunctionObject()) | - | ||||||||||||
1353 | return engine->throwTypeError(); | - | ||||||||||||
1354 | - | |||||||||||||
1355 | Scope scope(engine); | - | ||||||||||||
1356 | CallArgs arguments = createSpreadArguments(scope, argv, argc); | - | ||||||||||||
1357 | if (engine->hasException) | - | ||||||||||||
1358 | return Encode::undefined(); | - | ||||||||||||
1359 | - | |||||||||||||
1360 | return static_cast<const FunctionObject &>(function).callAsConstructor(arguments.argv, arguments.argc, &newTarget); | - | ||||||||||||
1361 | } | - | ||||||||||||
1362 | - | |||||||||||||
1363 | void Runtime::method_throwException(ExecutionEngine *engine, const Value &value) | - | ||||||||||||
1364 | { | - | ||||||||||||
1365 | if (!value.isEmpty()) | - | ||||||||||||
1366 | engine->throwError(value); | - | ||||||||||||
1367 | } | - | ||||||||||||
1368 | - | |||||||||||||
1369 | ReturnedValue Runtime::method_typeofValue(ExecutionEngine *engine, const Value &value) | - | ||||||||||||
1370 | { | - | ||||||||||||
1371 | Scope scope(engine); | - | ||||||||||||
1372 | ScopedString res(scope); | - | ||||||||||||
1373 | switch (value.type()) { | - | ||||||||||||
1374 | case Value::Undefined_Type: | - | ||||||||||||
1375 | res = engine->id_undefined(); | - | ||||||||||||
1376 | break; | - | ||||||||||||
1377 | case Value::Null_Type: | - | ||||||||||||
1378 | res = engine->id_object(); | - | ||||||||||||
1379 | break; | - | ||||||||||||
1380 | case Value::Boolean_Type: | - | ||||||||||||
1381 | res = engine->id_boolean(); | - | ||||||||||||
1382 | break; | - | ||||||||||||
1383 | case Value::Managed_Type: | - | ||||||||||||
1384 | if (value.isString()) | - | ||||||||||||
1385 | res = engine->id_string(); | - | ||||||||||||
1386 | else if (value.isSymbol()) | - | ||||||||||||
1387 | res = engine->id_symbol(); | - | ||||||||||||
1388 | else if (value.objectValue()->as<FunctionObject>()) | - | ||||||||||||
1389 | res = engine->id_function(); | - | ||||||||||||
1390 | else | - | ||||||||||||
1391 | res = engine->id_object(); // ### implementation-defined | - | ||||||||||||
1392 | break; | - | ||||||||||||
1393 | default: | - | ||||||||||||
1394 | res = engine->id_number(); | - | ||||||||||||
1395 | break; | - | ||||||||||||
1396 | } | - | ||||||||||||
1397 | return res.asReturnedValue(); | - | ||||||||||||
1398 | } | - | ||||||||||||
1399 | - | |||||||||||||
1400 | QV4::ReturnedValue Runtime::method_typeofName(ExecutionEngine *engine, int nameIndex) | - | ||||||||||||
1401 | { | - | ||||||||||||
1402 | Scope scope(engine); | - | ||||||||||||
1403 | ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); | - | ||||||||||||
1404 | ScopedValue prop(scope, static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name)); | - | ||||||||||||
1405 | // typeof doesn't throw. clear any possible exception | - | ||||||||||||
1406 | scope.engine->hasException = false; | - | ||||||||||||
1407 | return method_typeofValue(engine, prop); | - | ||||||||||||
1408 | } | - | ||||||||||||
1409 | - | |||||||||||||
1410 | ReturnedValue Runtime::method_createWithContext(ExecutionEngine *engine, Value *jsStackFrame) | - | ||||||||||||
1411 | { | - | ||||||||||||
1412 | QV4::Value &accumulator = jsStackFrame[CallData::Accumulator]; | - | ||||||||||||
1413 | accumulator = accumulator.toObject(engine); | - | ||||||||||||
1414 | if (engine->hasException) | - | ||||||||||||
1415 | return Encode::undefined(); | - | ||||||||||||
1416 | Q_ASSERT(accumulator.isObject()); | - | ||||||||||||
1417 | const Object &obj = static_cast<const Object &>(accumulator); | - | ||||||||||||
1418 | ExecutionContext *context = static_cast<ExecutionContext *>(jsStackFrame + CallData::Context); | - | ||||||||||||
1419 | return context->newWithContext(obj.d())->asReturnedValue(); | - | ||||||||||||
1420 | } | - | ||||||||||||
1421 | - | |||||||||||||
1422 | ReturnedValue Runtime::method_createCatchContext(ExecutionContext *parent, int blockIndex, int exceptionVarNameIndex) | - | ||||||||||||
1423 | { | - | ||||||||||||
1424 | ExecutionEngine *e = parent->engine(); | - | ||||||||||||
1425 | return parent->newCatchContext(e->currentStackFrame, blockIndex, | - | ||||||||||||
1426 | e->currentStackFrame->v4Function->compilationUnit->runtimeStrings[exceptionVarNameIndex])->asReturnedValue(); | - | ||||||||||||
1427 | } | - | ||||||||||||
1428 | - | |||||||||||||
1429 | ReturnedValue Runtime::method_createBlockContext(ExecutionContext *parent, int index) | - | ||||||||||||
1430 | { | - | ||||||||||||
1431 | ExecutionEngine *e = parent->engine(); | - | ||||||||||||
1432 | return parent->newBlockContext(e->currentStackFrame, index)->asReturnedValue(); | - | ||||||||||||
1433 | } | - | ||||||||||||
1434 | - | |||||||||||||
1435 | ReturnedValue Runtime::method_cloneBlockContext(ExecutionContext *previous) | - | ||||||||||||
1436 | { | - | ||||||||||||
1437 | return ExecutionContext::cloneBlockContext(static_cast<Heap::CallContext *>(previous->d()))->asReturnedValue(); | - | ||||||||||||
1438 | } | - | ||||||||||||
1439 | - | |||||||||||||
1440 | - | |||||||||||||
1441 | ReturnedValue Runtime::method_createScriptContext(ExecutionEngine *engine, int index) | - | ||||||||||||
1442 | { | - | ||||||||||||
1443 | Q_ASSERT(engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_GlobalContext || | - | ||||||||||||
1444 | engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_QmlContext); | - | ||||||||||||
1445 | ReturnedValue c = ExecutionContext::newBlockContext(engine->currentStackFrame, index)->asReturnedValue(); | - | ||||||||||||
1446 | engine->setScriptContext(c); | - | ||||||||||||
1447 | return c; | - | ||||||||||||
1448 | } | - | ||||||||||||
1449 | - | |||||||||||||
1450 | ReturnedValue Runtime::method_popScriptContext(ExecutionEngine *engine) | - | ||||||||||||
1451 | { | - | ||||||||||||
1452 | ReturnedValue root = engine->rootContext()->asReturnedValue(); | - | ||||||||||||
1453 | engine->setScriptContext(root); | - | ||||||||||||
1454 | return root; | - | ||||||||||||
1455 | } | - | ||||||||||||
1456 | - | |||||||||||||
1457 | - | |||||||||||||
1458 | void Runtime::method_declareVar(ExecutionEngine *engine, bool deletable, int nameIndex) | - | ||||||||||||
1459 | { | - | ||||||||||||
1460 | Scope scope(engine); | - | ||||||||||||
1461 | ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); | - | ||||||||||||
1462 | static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).createMutableBinding(name, deletable); | - | ||||||||||||
1463 | } | - | ||||||||||||
1464 | - | |||||||||||||
1465 | ReturnedValue Runtime::method_arrayLiteral(ExecutionEngine *engine, Value *values, uint length) | - | ||||||||||||
1466 | { | - | ||||||||||||
1467 | return engine->newArrayObject(values, length)->asReturnedValue(); | - | ||||||||||||
1468 | } | - | ||||||||||||
1469 | - | |||||||||||||
1470 | ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, int classId, int argc, const QV4::Value *args) | - | ||||||||||||
1471 | { | - | ||||||||||||
1472 | Scope scope(engine); | - | ||||||||||||
1473 | Scoped<InternalClass> klass(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeClasses[classId]); | - | ||||||||||||
1474 | ScopedObject o(scope, engine->newObject(klass->d())); | - | ||||||||||||
1475 | - | |||||||||||||
1476 | Q_ASSERT(uint(argc) >= klass->d()->size); | - | ||||||||||||
1477 | - | |||||||||||||
1478 | for (uint i = 0; i < klass->d()->size; ++i) | - | ||||||||||||
1479 | o->setProperty(i, *args++); | - | ||||||||||||
1480 | - | |||||||||||||
1481 | Q_ASSERT((argc - klass->d()->size) % 3 == 0); | - | ||||||||||||
1482 | int additionalArgs = (argc - int(klass->d()->size))/3; | - | ||||||||||||
1483 | - | |||||||||||||
1484 | if (!additionalArgs) | - | ||||||||||||
1485 | return o->asReturnedValue(); | - | ||||||||||||
1486 | - | |||||||||||||
1487 | ScopedPropertyKey name(scope); | - | ||||||||||||
1488 | ScopedProperty pd(scope); | - | ||||||||||||
1489 | for (int i = 0; i < additionalArgs; ++i) { | - | ||||||||||||
1490 | Q_ASSERT(args->isInteger()); | - | ||||||||||||
1491 | ObjectLiteralArgument arg = ObjectLiteralArgument(args->integerValue()); | - | ||||||||||||
1492 | name = args[1].toPropertyKey(engine); | - | ||||||||||||
1493 | if (engine->hasException) | - | ||||||||||||
1494 | return Encode::undefined(); | - | ||||||||||||
1495 | Q_ASSERT(arg == ObjectLiteralArgument::Value || args[2].isFunctionObject()); | - | ||||||||||||
1496 | if (arg == ObjectLiteralArgument::Value || arg == ObjectLiteralArgument::Getter) { | - | ||||||||||||
1497 | pd->value = args[2]; | - | ||||||||||||
1498 | pd->set = Primitive::emptyValue(); | - | ||||||||||||
1499 | } else { | - | ||||||||||||
1500 | pd->value = Primitive::emptyValue(); | - | ||||||||||||
1501 | pd->set = args[2]; | - | ||||||||||||
1502 | } | - | ||||||||||||
1503 | bool ok = o->defineOwnProperty(name, pd, (arg == ObjectLiteralArgument::Value ? Attr_Data : Attr_Accessor)); | - | ||||||||||||
1504 | if (!ok) | - | ||||||||||||
1505 | return engine->throwTypeError(); | - | ||||||||||||
1506 | - | |||||||||||||
1507 | args += 3; | - | ||||||||||||
1508 | } | - | ||||||||||||
1509 | return o.asReturnedValue(); | - | ||||||||||||
1510 | } | - | ||||||||||||
1511 | - | |||||||||||||
1512 | ReturnedValue Runtime::method_createClass(ExecutionEngine *engine, int classIndex, const Value &superClass, const Value *computedNames) | - | ||||||||||||
1513 | { | - | ||||||||||||
1514 | const CompiledData::CompilationUnit *unit = engine->currentStackFrame->v4Function->compilationUnit; | - | ||||||||||||
1515 | const QV4::CompiledData::Class *cls = unit->data->classAt(classIndex); | - | ||||||||||||
1516 | - | |||||||||||||
1517 | Scope scope(engine); | - | ||||||||||||
1518 | ScopedObject protoParent(scope, engine->objectPrototype()); | - | ||||||||||||
1519 | ScopedObject constructorParent(scope, engine->functionPrototype()); | - | ||||||||||||
1520 | if (!superClass.isEmpty()) { | - | ||||||||||||
1521 | if (superClass.isNull()) { | - | ||||||||||||
1522 | protoParent = Encode::null(); | - | ||||||||||||
1523 | } else { | - | ||||||||||||
1524 | // ### check that the heritage object is a constructor | - | ||||||||||||
1525 | if (!superClass.isFunctionObject()) | - | ||||||||||||
1526 | return engine->throwTypeError(QStringLiteral("The superclass is not a function object.")); | - | ||||||||||||
1527 | const FunctionObject *s = static_cast<const FunctionObject *>(&superClass); | - | ||||||||||||
1528 | ScopedValue result(scope, s->get(scope.engine->id_prototype())); | - | ||||||||||||
1529 | if (!result->isObject() && !result->isNull()) | - | ||||||||||||
1530 | return engine->throwTypeError(QStringLiteral("The value of the superclass's prototype property is not an object.")); | - | ||||||||||||
1531 | protoParent = *result; | - | ||||||||||||
1532 | constructorParent = superClass; | - | ||||||||||||
1533 | } | - | ||||||||||||
1534 | } | - | ||||||||||||
1535 | - | |||||||||||||
1536 | ScopedObject proto(scope, engine->newObject()); | - | ||||||||||||
1537 | proto->setPrototypeUnchecked(protoParent); | - | ||||||||||||
1538 | ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context); | - | ||||||||||||
1539 | - | |||||||||||||
1540 | ScopedFunctionObject constructor(scope); | - | ||||||||||||
1541 | QV4::Function *f = cls->constructorFunction != UINT_MAX ? unit->runtimeFunctions[cls->constructorFunction] : nullptr; | - | ||||||||||||
1542 | constructor = FunctionObject::createConstructorFunction(current, f, !superClass.isEmpty())->asReturnedValue(); | - | ||||||||||||
1543 | constructor->setPrototypeUnchecked(constructorParent); | - | ||||||||||||
1544 | constructor->defineDefaultProperty(engine->id_prototype(), proto); | - | ||||||||||||
1545 | proto->defineDefaultProperty(engine->id_constructor(), constructor); | - | ||||||||||||
1546 | - | |||||||||||||
1547 | ScopedString name(scope); | - | ||||||||||||
1548 | if (cls->nameIndex != UINT_MAX) { | - | ||||||||||||
1549 | name = unit->runtimeStrings[cls->nameIndex]; | - | ||||||||||||
1550 | constructor->defineReadonlyConfigurableProperty(engine->id_name(), name); | - | ||||||||||||
1551 | } | - | ||||||||||||
1552 | - | |||||||||||||
1553 | ScopedObject receiver(scope, *constructor); | - | ||||||||||||
1554 | ScopedPropertyKey propertyName(scope); | - | ||||||||||||
1555 | ScopedFunctionObject function(scope); | - | ||||||||||||
1556 | ScopedProperty property(scope); | - | ||||||||||||
1557 | const CompiledData::Method *methods = cls->methodTable(); | - | ||||||||||||
1558 | for (uint i = 0; i < cls->nStaticMethods + cls->nMethods; ++i) { | - | ||||||||||||
1559 | if (i == cls->nStaticMethods) | - | ||||||||||||
1560 | receiver = proto; | - | ||||||||||||
1561 | if (methods[i].name == UINT_MAX) { | - | ||||||||||||
1562 | propertyName = computedNames->toPropertyKey(engine); | - | ||||||||||||
1563 | if (engine->hasException) | - | ||||||||||||
1564 | return Encode::undefined(); | - | ||||||||||||
1565 | ++computedNames; | - | ||||||||||||
1566 | } else { | - | ||||||||||||
1567 | name = unit->runtimeStrings[methods[i].name]; | - | ||||||||||||
1568 | propertyName = name->toPropertyKey(); | - | ||||||||||||
1569 | } | - | ||||||||||||
1570 | QV4::Function *f = unit->runtimeFunctions[methods[i].function]; | - | ||||||||||||
1571 | Q_ASSERT(f); | - | ||||||||||||
1572 | if (f->isGenerator()) | - | ||||||||||||
1573 | function = MemberGeneratorFunction::create(current, f); | - | ||||||||||||
1574 | else | - | ||||||||||||
1575 | function = FunctionObject::createMemberFunction(current, f); | - | ||||||||||||
1576 | Q_ASSERT(function); | - | ||||||||||||
1577 | PropertyAttributes attributes; | - | ||||||||||||
1578 | switch (methods[i].type) { | - | ||||||||||||
1579 | case CompiledData::Method::Getter: | - | ||||||||||||
1580 | property->setGetter(function); | - | ||||||||||||
1581 | property->set = Primitive::emptyValue(); | - | ||||||||||||
1582 | attributes = Attr_Accessor|Attr_NotEnumerable; | - | ||||||||||||
1583 | break; | - | ||||||||||||
1584 | case CompiledData::Method::Setter: | - | ||||||||||||
1585 | property->value = Primitive::emptyValue(); | - | ||||||||||||
1586 | property->setSetter(function); | - | ||||||||||||
1587 | attributes = Attr_Accessor|Attr_NotEnumerable; | - | ||||||||||||
1588 | break; | - | ||||||||||||
1589 | default: // Regular | - | ||||||||||||
1590 | property->value = function; | - | ||||||||||||
1591 | property->set = Primitive::emptyValue(); | - | ||||||||||||
1592 | attributes = Attr_Data|Attr_NotEnumerable; | - | ||||||||||||
1593 | break; | - | ||||||||||||
1594 | } | - | ||||||||||||
1595 | receiver->defineOwnProperty(propertyName, property, attributes); | - | ||||||||||||
1596 | } | - | ||||||||||||
1597 | - | |||||||||||||
1598 | return constructor->asReturnedValue(); | - | ||||||||||||
1599 | } | - | ||||||||||||
1600 | - | |||||||||||||
1601 | QV4::ReturnedValue Runtime::method_createMappedArgumentsObject(ExecutionEngine *engine) | - | ||||||||||||
1602 | { | - | ||||||||||||
1603 | Q_ASSERT(engine->currentContext()->d()->type == Heap::ExecutionContext::Type_CallContext); | - | ||||||||||||
1604 | Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_ArgumentsObject); | - | ||||||||||||
1605 | return engine->memoryManager->allocObject<ArgumentsObject>(ic, engine->currentStackFrame)->asReturnedValue(); | - | ||||||||||||
1606 | } | - | ||||||||||||
1607 | - | |||||||||||||
1608 | QV4::ReturnedValue Runtime::method_createUnmappedArgumentsObject(ExecutionEngine *engine) | - | ||||||||||||
1609 | { | - | ||||||||||||
1610 | Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_StrictArgumentsObject); | - | ||||||||||||
1611 | return engine->memoryManager->allocObject<StrictArgumentsObject>(ic, engine->currentStackFrame)->asReturnedValue(); | - | ||||||||||||
1612 | } | - | ||||||||||||
1613 | - | |||||||||||||
1614 | QV4::ReturnedValue Runtime::method_createRestParameter(ExecutionEngine *engine, int argIndex) | - | ||||||||||||
1615 | { | - | ||||||||||||
1616 | const Value *values = engine->currentStackFrame->originalArguments + argIndex; | - | ||||||||||||
1617 | int nValues = engine->currentStackFrame->originalArgumentsCount - argIndex; | - | ||||||||||||
1618 | if (nValues <= 0) | - | ||||||||||||
1619 | return engine->newArrayObject(0)->asReturnedValue(); | - | ||||||||||||
1620 | return engine->newArrayObject(values, nValues)->asReturnedValue(); | - | ||||||||||||
1621 | } | - | ||||||||||||
1622 | - | |||||||||||||
1623 | - | |||||||||||||
1624 | ReturnedValue Runtime::method_loadQmlContext(NoThrowEngine *engine) | - | ||||||||||||
1625 | { | - | ||||||||||||
1626 | Heap::QmlContext *ctx = engine->qmlContext(); | - | ||||||||||||
1627 | Q_ASSERT(ctx); | - | ||||||||||||
1628 | return ctx->asReturnedValue(); | - | ||||||||||||
1629 | } | - | ||||||||||||
1630 | - | |||||||||||||
1631 | ReturnedValue Runtime::method_regexpLiteral(ExecutionEngine *engine, int id) | - | ||||||||||||
1632 | { | - | ||||||||||||
1633 | Heap::RegExpObject *ro = engine->newRegExpObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeRegularExpressions[id].as<RegExp>()); | - | ||||||||||||
1634 | return ro->asReturnedValue(); | - | ||||||||||||
1635 | } | - | ||||||||||||
1636 | - | |||||||||||||
1637 | ReturnedValue Runtime::method_loadQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired) | - | ||||||||||||
1638 | { | - | ||||||||||||
1639 | const QmlContext &c = static_cast<const QmlContext &>(context); | - | ||||||||||||
1640 | return QV4::QObjectWrapper::getProperty(engine, c.d()->qml()->scopeObject, propertyIndex, captureRequired); | - | ||||||||||||
1641 | } | - | ||||||||||||
1642 | - | |||||||||||||
1643 | ReturnedValue Runtime::method_loadQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired) | - | ||||||||||||
1644 | { | - | ||||||||||||
1645 | const QmlContext &c = static_cast<const QmlContext &>(context); | - | ||||||||||||
1646 | return QV4::QObjectWrapper::getProperty(engine, (*c.d()->qml()->context)->contextObject, propertyIndex, captureRequired); | - | ||||||||||||
1647 | } | - | ||||||||||||
1648 | - | |||||||||||||
1649 | ReturnedValue Runtime::method_loadQmlIdObject(ExecutionEngine *engine, const Value &c, uint index) | - | ||||||||||||
1650 | { | - | ||||||||||||
1651 | const QmlContext &qmlContext = static_cast<const QmlContext &>(c); | - | ||||||||||||
1652 | QQmlContextData *context = *qmlContext.d()->qml()->context; | - | ||||||||||||
1653 | if (!context || index >= (uint)context->idValueCount) | - | ||||||||||||
1654 | return Encode::undefined(); | - | ||||||||||||
1655 | - | |||||||||||||
1656 | QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : nullptr; | - | ||||||||||||
1657 | if (ep && ep->propertyCapture) | - | ||||||||||||
1658 | ep->propertyCapture->captureProperty(&context->idValues[index].bindings); | - | ||||||||||||
1659 | - | |||||||||||||
1660 | return QObjectWrapper::wrap(engine, context->idValues[index].data()); | - | ||||||||||||
1661 | } | - | ||||||||||||
1662 | - | |||||||||||||
1663 | void Runtime::method_storeQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value) | - | ||||||||||||
1664 | { | - | ||||||||||||
1665 | const QmlContext &c = static_cast<const QmlContext &>(context); | - | ||||||||||||
1666 | return QV4::QObjectWrapper::setProperty(engine, c.d()->qml()->scopeObject, propertyIndex, value); | - | ||||||||||||
1667 | } | - | ||||||||||||
1668 | - | |||||||||||||
1669 | void Runtime::method_storeQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value) | - | ||||||||||||
1670 | { | - | ||||||||||||
1671 | const QmlContext &c = static_cast<const QmlContext &>(context); | - | ||||||||||||
1672 | return QV4::QObjectWrapper::setProperty(engine, (*c.d()->qml()->context)->contextObject, propertyIndex, value); | - | ||||||||||||
1673 | } | - | ||||||||||||
1674 | - | |||||||||||||
1675 | ReturnedValue Runtime::method_loadQmlImportedScripts(NoThrowEngine *engine) | - | ||||||||||||
1676 | { | - | ||||||||||||
1677 | QQmlContextData *context = engine->callingQmlContext(); | - | ||||||||||||
1678 | if (!context) | - | ||||||||||||
1679 | return Encode::undefined(); | - | ||||||||||||
1680 | return context->importedScripts.value(); | - | ||||||||||||
1681 | } | - | ||||||||||||
1682 | - | |||||||||||||
1683 | ReturnedValue Runtime::method_uMinus(const Value &value) | - | ||||||||||||
1684 | { | - | ||||||||||||
1685 | TRACE1(value); | - | ||||||||||||
1686 | - | |||||||||||||
1687 | // +0 != -0, so we need to convert to double when negating 0 | - | ||||||||||||
1688 | if (value.isInteger() && value.integerValue() && | - | ||||||||||||
1689 | value.integerValue() != std::numeric_limits<int>::min()) | - | ||||||||||||
1690 | return Encode(-value.integerValue()); | - | ||||||||||||
1691 | else { | - | ||||||||||||
1692 | double n = RuntimeHelpers::toNumber(value); | - | ||||||||||||
1693 | return Encode(-n); | - | ||||||||||||
1694 | } | - | ||||||||||||
1695 | } | - | ||||||||||||
1696 | - | |||||||||||||
1697 | // binary operators | - | ||||||||||||
1698 | - | |||||||||||||
1699 | #ifndef V4_BOOTSTRAP | - | ||||||||||||
1700 | ReturnedValue Runtime::method_add(ExecutionEngine *engine, const Value &left, const Value &right) | - | ||||||||||||
1701 | { | - | ||||||||||||
1702 | TRACE2(left, right); | - | ||||||||||||
1703 | - | |||||||||||||
1704 | if (Q_LIKELY(left.integerCompatible() && right.integerCompatible())) | - | ||||||||||||
1705 | return add_int32(left.integerValue(), right.integerValue()); | - | ||||||||||||
1706 | if (left.isNumber() && right.isNumber()) | - | ||||||||||||
1707 | return Primitive::fromDouble(left.asDouble() + right.asDouble()).asReturnedValue(); | - | ||||||||||||
1708 | - | |||||||||||||
1709 | return RuntimeHelpers::addHelper(engine, left, right); | - | ||||||||||||
1710 | } | - | ||||||||||||
1711 | #endif // V4_BOOTSTRAP | - | ||||||||||||
1712 | - | |||||||||||||
1713 | ReturnedValue Runtime::method_sub(const Value &left, const Value &right) | - | ||||||||||||
1714 | { | - | ||||||||||||
1715 | TRACE2(left, right); | - | ||||||||||||
1716 | - | |||||||||||||
1717 | if (Q_LIKELY(left.integerCompatible() && right.integerCompatible())) | - | ||||||||||||
1718 | return sub_int32(left.integerValue(), right.integerValue()); | - | ||||||||||||
1719 | - | |||||||||||||
1720 | double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl(); | - | ||||||||||||
1721 | double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl(); | - | ||||||||||||
1722 | - | |||||||||||||
1723 | return Primitive::fromDouble(lval - rval).asReturnedValue(); | - | ||||||||||||
1724 | } | - | ||||||||||||
1725 | - | |||||||||||||
1726 | ReturnedValue Runtime::method_mul(const Value &left, const Value &right) | - | ||||||||||||
1727 | { | - | ||||||||||||
1728 | TRACE2(left, right); | - | ||||||||||||
1729 | - | |||||||||||||
1730 | if (Q_LIKELY(left.integerCompatible() && right.integerCompatible())) | - | ||||||||||||
1731 | return mul_int32(left.integerValue(), right.integerValue()); | - | ||||||||||||
1732 | - | |||||||||||||
1733 | double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl(); | - | ||||||||||||
1734 | double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl(); | - | ||||||||||||
1735 | - | |||||||||||||
1736 | return Primitive::fromDouble(lval * rval).asReturnedValue(); | - | ||||||||||||
1737 | } | - | ||||||||||||
1738 | - | |||||||||||||
1739 | ReturnedValue Runtime::method_div(const Value &left, const Value &right) | - | ||||||||||||
1740 | { | - | ||||||||||||
1741 | TRACE2(left, right); | - | ||||||||||||
1742 | - | |||||||||||||
1743 | if (Value::integerCompatible(left, right)) { | - | ||||||||||||
1744 | int lval = left.integerValue(); | - | ||||||||||||
1745 | int rval = right.integerValue(); | - | ||||||||||||
1746 | if (rval != 0 // division by zero should result in a NaN | - | ||||||||||||
1747 | && (lval % rval == 0) // fractions can't be stored in an int | - | ||||||||||||
1748 | && !(lval == 0 && rval < 0)) // 0 / -something results in -0.0 | - | ||||||||||||
1749 | return Encode(int(lval / rval)); | - | ||||||||||||
1750 | else | - | ||||||||||||
1751 | return Encode(double(lval) / rval); | - | ||||||||||||
1752 | } | - | ||||||||||||
1753 | - | |||||||||||||
1754 | double lval = left.toNumber(); | - | ||||||||||||
1755 | double rval = right.toNumber(); | - | ||||||||||||
1756 | return Primitive::fromDouble(lval / rval).asReturnedValue(); | - | ||||||||||||
1757 | } | - | ||||||||||||
1758 | - | |||||||||||||
1759 | ReturnedValue Runtime::method_mod(const Value &left, const Value &right) | - | ||||||||||||
1760 | { | - | ||||||||||||
1761 | TRACE2(left, right); | - | ||||||||||||
1762 | - | |||||||||||||
1763 | if (Value::integerCompatible(left, right) && left.integerValue() > 0 && right.integerValue() > 0) { | - | ||||||||||||
1764 | int intRes = left.integerValue() % right.integerValue(); | - | ||||||||||||
1765 | if (intRes != 0 || left.integerValue() >= 0) | - | ||||||||||||
1766 | return Encode(intRes); | - | ||||||||||||
1767 | } | - | ||||||||||||
1768 | - | |||||||||||||
1769 | double lval = RuntimeHelpers::toNumber(left); | - | ||||||||||||
1770 | double rval = RuntimeHelpers::toNumber(right); | - | ||||||||||||
1771 | #ifdef fmod | - | ||||||||||||
1772 | # undef fmod | - | ||||||||||||
1773 | #endif | - | ||||||||||||
1774 | return Primitive::fromDouble(std::fmod(lval, rval)).asReturnedValue(); | - | ||||||||||||
1775 | } | - | ||||||||||||
1776 | - | |||||||||||||
1777 | ReturnedValue Runtime::method_shl(const Value &left, const Value &right) | - | ||||||||||||
1778 | { | - | ||||||||||||
1779 | TRACE2(left, right); | - | ||||||||||||
1780 | - | |||||||||||||
1781 | int lval = left.toInt32(); | - | ||||||||||||
1782 | int rval = right.toInt32() & 0x1f; | - | ||||||||||||
1783 | return Encode((int)(lval << rval)); | - | ||||||||||||
1784 | } | - | ||||||||||||
1785 | - | |||||||||||||
1786 | ReturnedValue Runtime::method_shr(const Value &left, const Value &right) | - | ||||||||||||
1787 | { | - | ||||||||||||
1788 | TRACE2(left, right); | - | ||||||||||||
1789 | - | |||||||||||||
1790 | int lval = left.toInt32(); | - | ||||||||||||
1791 | unsigned rval = right.toUInt32() & 0x1f; | - | ||||||||||||
1792 | return Encode((int)(lval >> rval)); | - | ||||||||||||
1793 | } | - | ||||||||||||
1794 | - | |||||||||||||
1795 | ReturnedValue Runtime::method_ushr(const Value &left, const Value &right) | - | ||||||||||||
1796 | { | - | ||||||||||||
1797 | TRACE2(left, right); | - | ||||||||||||
1798 | - | |||||||||||||
1799 | unsigned lval = left.toUInt32(); | - | ||||||||||||
1800 | unsigned rval = right.toUInt32() & 0x1f; | - | ||||||||||||
1801 | uint res = lval >> rval; | - | ||||||||||||
1802 | - | |||||||||||||
1803 | return Encode(res); | - | ||||||||||||
1804 | } | - | ||||||||||||
1805 | - | |||||||||||||
1806 | #endif // V4_BOOTSTRAP | - | ||||||||||||
1807 | - | |||||||||||||
1808 | ReturnedValue Runtime::method_greaterThan(const Value &left, const Value &right) | - | ||||||||||||
1809 | { | - | ||||||||||||
1810 | TRACE2(left, right); | - | ||||||||||||
1811 | - | |||||||||||||
1812 | bool r = method_compareGreaterThan(left, right); | - | ||||||||||||
1813 | return Encode(r); never executed: return Encode(r); | 0 | ||||||||||||
1814 | } | - | ||||||||||||
1815 | - | |||||||||||||
1816 | ReturnedValue Runtime::method_lessThan(const Value &left, const Value &right) | - | ||||||||||||
1817 | { | - | ||||||||||||
1818 | TRACE2(left, right); | - | ||||||||||||
1819 | - | |||||||||||||
1820 | bool r = method_compareLessThan(left, right); | - | ||||||||||||
1821 | return Encode(r); never executed: return Encode(r); | 0 | ||||||||||||
1822 | } | - | ||||||||||||
1823 | - | |||||||||||||
1824 | ReturnedValue Runtime::method_greaterEqual(const Value &left, const Value &right) | - | ||||||||||||
1825 | { | - | ||||||||||||
1826 | TRACE2(left, right); | - | ||||||||||||
1827 | - | |||||||||||||
1828 | bool r = method_compareGreaterEqual(left, right); | - | ||||||||||||
1829 | return Encode(r); never executed: return Encode(r); | 0 | ||||||||||||
1830 | } | - | ||||||||||||
1831 | - | |||||||||||||
1832 | ReturnedValue Runtime::method_lessEqual(const Value &left, const Value &right) | - | ||||||||||||
1833 | { | - | ||||||||||||
1834 | TRACE2(left, right); | - | ||||||||||||
1835 | - | |||||||||||||
1836 | bool r = method_compareLessEqual(left, right); | - | ||||||||||||
1837 | return Encode(r); never executed: return Encode(r); | 0 | ||||||||||||
1838 | } | - | ||||||||||||
1839 | - | |||||||||||||
1840 | struct LazyScope | - | ||||||||||||
1841 | { | - | ||||||||||||
1842 | ExecutionEngine *engine = nullptr; | - | ||||||||||||
1843 | Value *stackMark = nullptr; | - | ||||||||||||
1844 | ~LazyScope() { | - | ||||||||||||
1845 | if (engine)
| 663-192641 | ||||||||||||
1846 | engine->jsStackTop = stackMark; executed 663 times by 5 tests: engine->jsStackTop = stackMark; Executed by:
| 663 | ||||||||||||
1847 | } executed 193304 times by 33 tests: end of block Executed by:
| 193304 | ||||||||||||
1848 | template <typename T> | - | ||||||||||||
1849 | void set(Value **scopedValue, T value, ExecutionEngine *e) { | - | ||||||||||||
1850 | if (!engine) {
| 0-662 | ||||||||||||
1851 | engine = e; | - | ||||||||||||
1852 | stackMark = engine->jsStackTop; | - | ||||||||||||
1853 | } executed 662 times by 5 tests: end of block Executed by:
| 662 | ||||||||||||
1854 | if (!*scopedValue)
| 0-661 | ||||||||||||
1855 | *scopedValue = e->jsAlloca(1); executed 662 times by 5 tests: *scopedValue = e->jsAlloca(1); Executed by:
| 662 | ||||||||||||
1856 | **scopedValue = value; | - | ||||||||||||
1857 | } executed 661 times by 5 tests: end of block Executed by:
| 661 | ||||||||||||
1858 | }; | - | ||||||||||||
1859 | - | |||||||||||||
1860 | Bool Runtime::method_compareEqual(const Value &left, const Value &right) | - | ||||||||||||
1861 | { | - | ||||||||||||
1862 | TRACE2(left, right); | - | ||||||||||||
1863 | - | |||||||||||||
1864 | Value lhs = left; | - | ||||||||||||
1865 | Value rhs = right; | - | ||||||||||||
1866 | - | |||||||||||||
1867 | #ifndef V4_BOOTSTRAP | - | ||||||||||||
1868 | LazyScope scope; | - | ||||||||||||
1869 | Value *lhsGuard = nullptr; | - | ||||||||||||
1870 | Value *rhsGuard = nullptr; | - | ||||||||||||
1871 | #endif | - | ||||||||||||
1872 | - | |||||||||||||
1873 | redo: code before this statement executed 193302 times by 33 tests: redo: Executed by:
| 193302 | ||||||||||||
1874 | if (lhs.asReturnedValue() == rhs.asReturnedValue())
| 2620-191347 | ||||||||||||
1875 | return !lhs.isNaN(); executed 2620 times by 17 tests: return !lhs.isNaN(); Executed by:
| 2620 | ||||||||||||
1876 | - | |||||||||||||
1877 | int lt = lhs.quickType(); | - | ||||||||||||
1878 | int rt = rhs.quickType(); | - | ||||||||||||
1879 | if (rt < lt) {
| 1040-190308 | ||||||||||||
1880 | qSwap(lhs, rhs); | - | ||||||||||||
1881 | qSwap(lt, rt); | - | ||||||||||||
1882 | } executed 1040 times by 10 tests: end of block Executed by:
| 1040 | ||||||||||||
1883 | - | |||||||||||||
1884 | switch (lt) { | - | ||||||||||||
1885 | case QV4::Value::QT_ManagedOrUndefined: executed 188032 times by 29 tests: case QV4::Value::QT_ManagedOrUndefined: Executed by:
| 188032 | ||||||||||||
1886 | if (lhs.isUndefined())
| 164-187867 | ||||||||||||
1887 | return rhs.isNullOrUndefined(); executed 164 times by 4 tests: return rhs.isNullOrUndefined(); Executed by:
| 164 | ||||||||||||
1888 | Q_FALLTHROUGH(); | - | ||||||||||||
1889 | case QV4::Value::QT_ManagedOrUndefined1: code before this statement executed 187867 times by 29 tests: case QV4::Value::QT_ManagedOrUndefined1: Executed by:
never executed: case QV4::Value::QT_ManagedOrUndefined1: | 0-187867 | ||||||||||||
1890 | case QV4::Value::QT_ManagedOrUndefined2: never executed: case QV4::Value::QT_ManagedOrUndefined2: | 0 | ||||||||||||
1891 | case QV4::Value::QT_ManagedOrUndefined3: never executed: case QV4::Value::QT_ManagedOrUndefined3: | 0 | ||||||||||||
1892 | // LHS: Managed | - | ||||||||||||
1893 | switch (rt) { | - | ||||||||||||
1894 | case QV4::Value::QT_ManagedOrUndefined: executed 187127 times by 29 tests: case QV4::Value::QT_ManagedOrUndefined: Executed by:
| 187127 | ||||||||||||
1895 | if (rhs.isUndefined())
| 70-187057 | ||||||||||||
1896 | return false; executed 70 times by 7 tests: return false; Executed by:
| 70 | ||||||||||||
1897 | Q_FALLTHROUGH(); | - | ||||||||||||
1898 | case QV4::Value::QT_ManagedOrUndefined1: code before this statement executed 187058 times by 28 tests: case QV4::Value::QT_ManagedOrUndefined1: Executed by:
never executed: case QV4::Value::QT_ManagedOrUndefined1: | 0-187058 | ||||||||||||
1899 | case QV4::Value::QT_ManagedOrUndefined2: never executed: case QV4::Value::QT_ManagedOrUndefined2: | 0 | ||||||||||||
1900 | case QV4::Value::QT_ManagedOrUndefined3: { never executed: case QV4::Value::QT_ManagedOrUndefined3: | 0 | ||||||||||||
1901 | #ifndef V4_BOOTSTRAP | - | ||||||||||||
1902 | // RHS: Managed | - | ||||||||||||
1903 | Heap::Base *l = lhs.m(); | - | ||||||||||||
1904 | Heap::Base *r = rhs.m(); | - | ||||||||||||
1905 | Q_ASSERT(l); | - | ||||||||||||
1906 | Q_ASSERT(r); | - | ||||||||||||
1907 | if (l->internalClass->vtable->isStringOrSymbol == r->internalClass->vtable->isStringOrSymbol) | - | ||||||||||||
1908 | return static_cast<QV4::Managed &>(lhs).isEqualTo(&static_cast<QV4::Managed &>(rhs)); | - | ||||||||||||
1909 | if (l->internalClass->vtable->isStringOrSymbol) { | - | ||||||||||||
1910 | scope.set(&rhsGuard, RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(rhs), PREFERREDTYPE_HINT), r->internalClass->engine); | - | ||||||||||||
1911 | rhs = rhsGuard->asReturnedValue(); | - | ||||||||||||
1912 | break; | - | ||||||||||||
1913 | } else { | - | ||||||||||||
1914 | Q_ASSERT(r->internalClass->vtable->isStringOrSymbol); | - | ||||||||||||
1915 | scope.set(&lhsGuard, RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT), l->internalClass->engine); | - | ||||||||||||
1916 | lhs = lhsGuard->asReturnedValue(); | - | ||||||||||||
1917 | break; | - | ||||||||||||
1918 | } | - | ||||||||||||
1919 | #endif | - | ||||||||||||
1920 | return false; never executed: return false; | 0 | ||||||||||||
1921 | } | - | ||||||||||||
1922 | case QV4::Value::QT_Empty: never executed: case QV4::Value::QT_Empty: | 0 | ||||||||||||
1923 | Q_UNREACHABLE(); | - | ||||||||||||
1924 | case QV4::Value::QT_Null: code before this statement never executed: case QV4::Value::QT_Null: executed 40 times by 5 tests: case QV4::Value::QT_Null: Executed by:
| 0-40 | ||||||||||||
1925 | return false; executed 40 times by 5 tests: return false; Executed by:
| 40 | ||||||||||||
1926 | case QV4::Value::QT_Bool: executed 188 times by 2 tests: case QV4::Value::QT_Bool: Executed by:
| 188 | ||||||||||||
1927 | case QV4::Value::QT_Int: executed 279 times by 4 tests: case QV4::Value::QT_Int: Executed by:
| 279 | ||||||||||||
1928 | rhs = Primitive::fromDouble(rhs.int_32()); | - | ||||||||||||
1929 | // fall through | - | ||||||||||||
1930 | default: // double code before this statement executed 467 times by 4 tests: default: Executed by:
executed 701 times by 5 tests: default: Executed by:
| 467-701 | ||||||||||||
1931 | #ifndef V4_BOOTSTRAP | - | ||||||||||||
1932 | if (lhs.m()->internalClass->vtable->isStringOrSymbol) { | - | ||||||||||||
1933 | return lhs.m()->internalClass->vtable->isString ? (RuntimeHelpers::toNumber(lhs) == rhs.doubleValue()) : false; | - | ||||||||||||
1934 | } else { | - | ||||||||||||
1935 | scope.set(&lhsGuard, RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT), lhs.m()->internalClass->engine); | - | ||||||||||||
1936 | lhs = lhsGuard->asReturnedValue(); | - | ||||||||||||
1937 | } | - | ||||||||||||
1938 | #else | - | ||||||||||||
1939 | Q_UNIMPLEMENTED(); | - | ||||||||||||
1940 | #endif | - | ||||||||||||
1941 | } never executed: end of block | 0 | ||||||||||||
1942 | goto redo; executed 662 times by 5 tests: goto redo; Executed by:
| 662 | ||||||||||||
1943 | case QV4::Value::QT_Empty: never executed: case QV4::Value::QT_Empty: | 0 | ||||||||||||
1944 | Q_UNREACHABLE(); | - | ||||||||||||
1945 | case QV4::Value::QT_Null: code before this statement never executed: case QV4::Value::QT_Null: executed 44 times by 3 tests: case QV4::Value::QT_Null: Executed by:
| 0-44 | ||||||||||||
1946 | return rhs.isNull(); executed 44 times by 3 tests: return rhs.isNull(); Executed by:
| 44 | ||||||||||||
1947 | case QV4::Value::QT_Bool: executed 2094 times by 10 tests: case QV4::Value::QT_Bool: Executed by:
| 2094 | ||||||||||||
1948 | case QV4::Value::QT_Int: executed 1090 times by 7 tests: case QV4::Value::QT_Int: Executed by:
| 1090 | ||||||||||||
1949 | switch (rt) { | - | ||||||||||||
1950 | case QV4::Value::QT_ManagedOrUndefined: never executed: case QV4::Value::QT_ManagedOrUndefined: | 0 | ||||||||||||
1951 | case QV4::Value::QT_ManagedOrUndefined1: never executed: case QV4::Value::QT_ManagedOrUndefined1: | 0 | ||||||||||||
1952 | case QV4::Value::QT_ManagedOrUndefined2: never executed: case QV4::Value::QT_ManagedOrUndefined2: | 0 | ||||||||||||
1953 | case QV4::Value::QT_ManagedOrUndefined3: never executed: case QV4::Value::QT_ManagedOrUndefined3: | 0 | ||||||||||||
1954 | case QV4::Value::QT_Empty: never executed: case QV4::Value::QT_Empty: | 0 | ||||||||||||
1955 | case QV4::Value::QT_Null: never executed: case QV4::Value::QT_Null: | 0 | ||||||||||||
1956 | Q_UNREACHABLE(); | - | ||||||||||||
1957 | case QV4::Value::QT_Bool: code before this statement never executed: case QV4::Value::QT_Bool: executed 1898 times by 10 tests: case QV4::Value::QT_Bool: Executed by:
| 0-1898 | ||||||||||||
1958 | case QV4::Value::QT_Int: executed 114 times by 2 tests: case QV4::Value::QT_Int: Executed by:
| 114 | ||||||||||||
1959 | return lhs.int_32() == rhs.int_32(); executed 2011 times by 10 tests: return lhs.int_32() == rhs.int_32(); Executed by:
| 2011 | ||||||||||||
1960 | default: // double executed 1173 times by 7 tests: default: Executed by:
| 1173 | ||||||||||||
1961 | return lhs.int_32() == rhs.doubleValue(); executed 1173 times by 7 tests: return lhs.int_32() == rhs.doubleValue(); Executed by:
| 1173 | ||||||||||||
1962 | } | - | ||||||||||||
1963 | default: // double executed 86 times by 5 tests: default: Executed by:
| 86 | ||||||||||||
1964 | Q_ASSERT(rhs.isDouble()); | - | ||||||||||||
1965 | return lhs.doubleValue() == rhs.doubleValue(); executed 86 times by 5 tests: return lhs.doubleValue() == rhs.doubleValue(); Executed by:
| 86 | ||||||||||||
1966 | } | - | ||||||||||||
1967 | } | - | ||||||||||||
1968 | - | |||||||||||||
1969 | ReturnedValue Runtime::method_equal(const Value &left, const Value &right) | - | ||||||||||||
1970 | { | - | ||||||||||||
1971 | TRACE2(left, right); | - | ||||||||||||
1972 | - | |||||||||||||
1973 | bool r = method_compareEqual(left, right); | - | ||||||||||||
1974 | return Encode(r); executed 12 times by 2 tests: return Encode(r); Executed by:
| 12 | ||||||||||||
1975 | } | - | ||||||||||||
1976 | - | |||||||||||||
1977 | ReturnedValue Runtime::method_notEqual(const Value &left, const Value &right) | - | ||||||||||||
1978 | { | - | ||||||||||||
1979 | TRACE2(left, right); | - | ||||||||||||
1980 | - | |||||||||||||
1981 | bool r = !method_compareEqual(left, right); | - | ||||||||||||
1982 | return Encode(r); never executed: return Encode(r); | 0 | ||||||||||||
1983 | } | - | ||||||||||||
1984 | - | |||||||||||||
1985 | ReturnedValue Runtime::method_strictEqual(const Value &left, const Value &right) | - | ||||||||||||
1986 | { | - | ||||||||||||
1987 | TRACE2(left, right); | - | ||||||||||||
1988 | - | |||||||||||||
1989 | bool r = RuntimeHelpers::strictEqual(left, right); | - | ||||||||||||
1990 | return Encode(r); executed 132 times by 1 test: return Encode(r); Executed by:
| 132 | ||||||||||||
1991 | } | - | ||||||||||||
1992 | - | |||||||||||||
1993 | ReturnedValue Runtime::method_strictNotEqual(const Value &left, const Value &right) | - | ||||||||||||
1994 | { | - | ||||||||||||
1995 | TRACE2(left, right); | - | ||||||||||||
1996 | - | |||||||||||||
1997 | bool r = ! RuntimeHelpers::strictEqual(left, right); | - | ||||||||||||
1998 | return Encode(r); never executed: return Encode(r); | 0 | ||||||||||||
1999 | } | - | ||||||||||||
2000 | - | |||||||||||||
2001 | Bool Runtime::method_compareNotEqual(const Value &left, const Value &right) | - | ||||||||||||
2002 | { | - | ||||||||||||
2003 | TRACE2(left, right); | - | ||||||||||||
2004 | - | |||||||||||||
2005 | return !Runtime::method_compareEqual(left, right); executed 1520 times by 4 tests: return !Runtime::method_compareEqual(left, right); Executed by:
| 1520 | ||||||||||||
2006 | } | - | ||||||||||||
2007 | - | |||||||||||||
2008 | Bool Runtime::method_compareStrictEqual(const Value &left, const Value &right) | - | ||||||||||||
2009 | { | - | ||||||||||||
2010 | TRACE2(left, right); | - | ||||||||||||
2011 | - | |||||||||||||
2012 | return RuntimeHelpers::strictEqual(left, right); never executed: return RuntimeHelpers::strictEqual(left, right); | 0 | ||||||||||||
2013 | } | - | ||||||||||||
2014 | - | |||||||||||||
2015 | Bool Runtime::method_compareStrictNotEqual(const Value &left, const Value &right) | - | ||||||||||||
2016 | { | - | ||||||||||||
2017 | TRACE2(left, right); | - | ||||||||||||
2018 | - | |||||||||||||
2019 | return ! RuntimeHelpers::strictEqual(left, right); never executed: return ! RuntimeHelpers::strictEqual(left, right); | 0 | ||||||||||||
2020 | } | - | ||||||||||||
2021 | - | |||||||||||||
2022 | } // namespace QV4 | - | ||||||||||||
2023 | - | |||||||||||||
2024 | QT_END_NAMESPACE | - | ||||||||||||
Source code | Switch to Preprocessed file |