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 "qv4runtime_p.h"
42#include "qv4engine_p.h"
43#include "qv4object_p.h"
44#include "qv4objectproto_p.h"
45#include "qv4globalobject_p.h"
46#include "qv4stringobject_p.h"
47#include "qv4argumentsobject_p.h"
48#include "qv4objectiterator_p.h"
49#include "qv4dateobject_p.h"
50#include "qv4lookup_p.h"
51#include "qv4function_p.h"
52#include "qv4numberobject_p.h"
53#include "qv4regexp_p.h"
54#include "qv4regexpobject_p.h"
55#include "private/qlocale_tools_p.h"
56#include "qv4scopedvalue_p.h"
57#include "qv4jscall_p.h"
58#include <private/qv4qmlcontext_p.h>
59#include <private/qqmltypewrapper_p.h>
60#include <private/qqmlengine_p.h>
61#include <private/qqmljavascriptexpression_p.h>
62#include <private/qqmljsast_p.h>
63#include "qv4qobjectwrapper_p.h"
64#include "qv4symbol_p.h"
65#include "qv4generatorobject_p.h"
66
67#include <QtCore/QDebug>
68#include <cassert>
69#include <cstdio>
70#include <stdlib.h>
71
72#include <wtf/MathExtras.h>
73
74#ifdef QV4_COUNT_RUNTIME_FUNCTIONS
75# include <QtCore/QBuffer>
76# include <QtCore/QDebug>
77#endif // QV4_COUNT_RUNTIME_FUNCTIONS
78
79QT_BEGIN_NAMESPACE
80
81namespace QV4 {
82
83#ifdef QV4_COUNT_RUNTIME_FUNCTIONS
84struct RuntimeCounters::Data {
85 enum Type {
86 None = 0,
87 Undefined = 1,
88 Null = 2,
89 Boolean = 3,
90 Integer = 4,
91 Managed = 5,
92 Double = 7
93 };
94
95 static const char *pretty(Type t) {
96 switch (t) {
97 case None: return "";
98 case Undefined: return "Undefined";
99 case Null: return "Null";
100 case Boolean: return "Boolean";
101 case Integer: return "Integer";
102 case Managed: return "Managed";
103 case Double: return "Double";
104 default: return "Unknown";
105 }
106 }
107
108 static unsigned mangle(unsigned tag) {
109 switch (tag) {
110 case Value::Undefined_Type: return Undefined;
111 case Value::Null_Type: return Null;
112 case Value::Boolean_Type: return Boolean;
113 case Value::Integer_Type: return Integer;
114 case Value::Managed_Type: return Managed;
115 default: return Double;
116 }
117 }
118
119 static unsigned mangle(unsigned tag1, unsigned tag2) {
120 return (mangle(tag1) << 3) | mangle(tag2);
121 }
122
123 static void unmangle(unsigned signature, Type &tag1, Type &tag2) {
124 tag1 = Type((signature >> 3) & 7);
125 tag2 = Type(signature & 7);
126 }
127
128 typedef QVector<quint64> Counters;
129 QHash<const char *, Counters> counters;
130
131 inline void count(const char *func) {
132 QVector<quint64> &cnt = counters[func];
133 if (cnt.isEmpty())
134 cnt.resize(64);
135 cnt[0] += 1;
136 }
137
138 inline void count(const char *func, unsigned tag) {
139 QVector<quint64> &cnt = counters[func];
140 if (cnt.isEmpty())
141 cnt.resize(64);
142 cnt[mangle(tag)] += 1;
143 }
144
145 inline void count(const char *func, unsigned tag1, unsigned tag2) {
146 QVector<quint64> &cnt = counters[func];
147 if (cnt.isEmpty())
148 cnt.resize(64);
149 cnt[mangle(tag1, tag2)] += 1;
150 }
151
152 struct Line {
153 const char *func;
154 Type tag1, tag2;
155 quint64 count;
156
157 static bool less(const Line &line1, const Line &line2) {
158 return line1.count > line2.count;
159 }
160 };
161
162 void dump() const {
163 QBuffer buf;
164 buf.open(QIODevice::WriteOnly);
165 QTextStream outs(&buf);
166 QList<Line> lines;
167 for (auto it = counters.cbegin(), end = counters.cend(); it != end; ++it) {
168 const Counters &fCount = it.value();
169 for (int i = 0, ei = fCount.size(); i != ei; ++i) {
170 quint64 count = fCount[i];
171 if (!count)
172 continue;
173 Line line;
174 line.func = it.key();
175 unmangle(i, line.tag1, line.tag2);
176 line.count = count;
177 lines.append(line);
178 }
179 }
180 std::sort(lines.begin(), lines.end(), Line::less);
181 outs << lines.size() << " counters:" << endl;
182 for (const Line &line : qAsConst(lines))
183 outs << qSetFieldWidth(10) << line.count << qSetFieldWidth(0)
184 << " | " << line.func
185 << " | " << pretty(line.tag1)
186 << " | " << pretty(line.tag2)
187 << endl;
188 qDebug("%s", buf.data().constData());
189 }
190};
191
192RuntimeCounters *RuntimeCounters::instance = 0;
193static RuntimeCounters runtimeCountersInstance;
194RuntimeCounters::RuntimeCounters()
195 : d(new Data)
196{
197 if (!instance)
198 instance = this;
199}
200
201RuntimeCounters::~RuntimeCounters()
202{
203 d->dump();
204 delete d;
205}
206
207void RuntimeCounters::count(const char *func)
208{
209 d->count(func);
210}
211
212void RuntimeCounters::count(const char *func, uint tag)
213{
214 d->count(func, tag);
215}
216
217void RuntimeCounters::count(const char *func, uint tag1, uint tag2)
218{
219 d->count(func, tag1, tag2);
220}
221
222#endif // QV4_COUNT_RUNTIME_FUNCTIONS
223
224static QV4::Lookup *runtimeLookup(Function *f, uint i)
225{
226 return f->executableCompilationUnit()->runtimeLookups + i;
227}
228
229void RuntimeHelpers::numberToString(QString *result, double num, int radix)
230{
231 Q_ASSERT(result);
232
233 if (std::isnan(x: num)) {
234 *result = QStringLiteral("NaN");
235 return;
236 } else if (qt_is_inf(d: num)) {
237 *result = num < 0 ? QStringLiteral("-Infinity") : QStringLiteral("Infinity");
238 return;
239 }
240
241 if (radix == 10) {
242 // We cannot use our usual locale->toString(...) here, because EcmaScript has special rules
243 // about the longest permissible number, depending on if it's <0 or >0.
244 const int ecma_shortest_low = -6;
245 const int ecma_shortest_high = 21;
246
247 const QLatin1Char zero('0');
248 const QLatin1Char dot('.');
249
250 int decpt = 0;
251 int sign = 0;
252 *result = qdtoa(d: num, decpt: &decpt, sign: &sign);
253
254 if (decpt <= ecma_shortest_low || decpt > ecma_shortest_high) {
255 if (result->length() > 1)
256 result->insert(i: 1, c: dot);
257 result->append(c: QLatin1Char('e'));
258 if (decpt > 0)
259 result->append(c: QLatin1Char('+'));
260 result->append(s: QString::number(decpt - 1));
261 } else if (decpt <= 0) {
262 result->prepend(s: QLatin1String("0.") + QString(-decpt, zero));
263 } else if (decpt < result->length()) {
264 result->insert(i: decpt, c: dot);
265 } else {
266 result->append(s: QString(decpt - result->length(), zero));
267 }
268
269 if (sign && num)
270 result->prepend(c: QLatin1Char('-'));
271
272 return;
273 }
274
275 result->clear();
276 bool negative = false;
277
278 if (num < 0) {
279 negative = true;
280 num = -num;
281 }
282
283 double frac = num - ::floor(x: num);
284 num = Value::toInteger(d: num);
285
286 do {
287 char c = (char)::fmod(x: num, y: radix);
288 c = (c < 10) ? (c + '0') : (c - 10 + 'a');
289 result->prepend(c: QLatin1Char(c));
290 num = ::floor(x: num / radix);
291 } while (num != 0);
292
293 if (frac != 0) {
294 result->append(c: QLatin1Char('.'));
295 double magnitude = 1;
296 double next = frac;
297 do {
298 next *= radix;
299 const int floored = ::floor(x: next);
300 char c = char(floored);
301 c = (c < 10) ? (c + '0') : (c - 10 + 'a');
302 result->append(c: QLatin1Char(c));
303 magnitude /= radix;
304 frac -= double(floored) * magnitude;
305 next -= double(floored);
306
307 // The next digit still makes a difference
308 // if a value of "radix" for it would change frac.
309 // Otherwise we've reached the limit of numerical precision.
310 } while (frac > 0 && frac - magnitude != frac);
311 }
312
313 if (negative)
314 result->prepend(c: QLatin1Char('-'));
315}
316
317ReturnedValue Runtime::Closure::call(ExecutionEngine *engine, int functionId)
318{
319 QV4::Function *clos = engine->currentStackFrame->v4Function->executableCompilationUnit()
320 ->runtimeFunctions[functionId];
321 Q_ASSERT(clos);
322 ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context);
323 if (clos->isGenerator())
324 return GeneratorFunction::create(scope: current, function: clos)->asReturnedValue();
325 return FunctionObject::createScriptFunction(scope: current, function: clos)->asReturnedValue();
326}
327
328Bool Runtime::DeleteProperty_NoThrow::call(ExecutionEngine *engine, const Value &base, const Value &index)
329{
330 Scope scope(engine);
331 ScopedObject o(scope, base.toObject(e: engine));
332 if (scope.engine->hasException)
333 return Encode::undefined();
334 Q_ASSERT(o);
335
336 ScopedPropertyKey key(scope, index.toPropertyKey(e: engine));
337 if (engine->hasException)
338 return false;
339 return o->deleteProperty(id: key);
340}
341
342ReturnedValue Runtime::DeleteProperty::call(ExecutionEngine *engine, QV4::Function *function, const QV4::Value &base, const QV4::Value &index)
343{
344 if (!Runtime::DeleteProperty_NoThrow::call(engine, base, index)) {
345 if (function->isStrict())
346 engine->throwTypeError();
347 return Encode(false);
348 } else {
349 return Encode(true);
350 }
351}
352
353Bool Runtime::DeleteName_NoThrow::call(ExecutionEngine *engine, int nameIndex)
354{
355 Scope scope(engine);
356 ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
357 return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).deleteProperty(name);
358}
359
360ReturnedValue Runtime::DeleteName::call(ExecutionEngine *engine, Function *function, int name)
361{
362 if (!Runtime::DeleteName_NoThrow::call(engine, nameIndex: name)) {
363 if (function->isStrict())
364 engine->throwTypeError();
365 return Encode(false);
366 } else {
367 return Encode(true);
368 }
369}
370
371QV4::ReturnedValue Runtime::Instanceof::call(ExecutionEngine *engine, const Value &lval, const Value &rval)
372{
373 // 11.8.6, 5: rval must be an Object
374 const Object *rhs = rval.as<Object>();
375 if (!rhs)
376 return engine->throwTypeError();
377
378 const FunctionObject *f = rhs->as<FunctionObject>();
379 // shortcut hasInstance evaluation. In this case we know that we are calling the regular hasInstance()
380 // method of the FunctionPrototype
381 if (f && f->d()->prototype() == engine->functionPrototype()->d() && !f->hasHasInstanceProperty())
382 return Object::checkedInstanceOf(engine, typeObject: f, var: lval);
383
384 Scope scope(engine);
385 ScopedValue hasInstance(scope, rhs->get(name: engine->symbol_hasInstance()));
386 if (hasInstance->isUndefined())
387 return rhs->instanceOf(var: lval);
388 FunctionObject *fHasInstance = hasInstance->as<FunctionObject>();
389 if (!fHasInstance)
390 return engine->throwTypeError();
391
392 ScopedValue result(scope, fHasInstance->call(thisObject: &rval, argv: &lval, argc: 1));
393 return scope.hasException() ? Encode::undefined() : Encode(result->toBoolean());
394}
395
396QV4::ReturnedValue Runtime::In::call(ExecutionEngine *engine, const Value &left, const Value &right)
397{
398 Object *ro = right.objectValue();
399 if (!ro)
400 return engine->throwTypeError();
401 Scope scope(engine);
402 ScopedPropertyKey s(scope, left.toPropertyKey(e: engine));
403 if (scope.hasException())
404 return Encode::undefined();
405 bool r = ro->hasProperty(id: s);
406 return Encode(r);
407}
408
409double RuntimeHelpers::stringToNumber(const QString &string)
410{
411 // The actual maximum valid length is certainly shorter, but due to the sheer number of
412 // different number formatting variants, we rather err on the side of caution here.
413 // For example, you can have up to 772 valid decimal digits left of the dot, as stated in the
414 // libdoubleconversion sources. The same maximum value would be represented by roughly 3.5 times
415 // as many binary digits.
416 const int excessiveLength = 16 * 1024;
417 if (string.length() > excessiveLength)
418 return qQNaN();
419
420 const QStringRef s = QStringRef(&string).trimmed();
421 if (s.startsWith(c: QLatin1Char('0'))) {
422 int base = -1;
423 if (s.startsWith(s: QLatin1String("0x")) || s.startsWith(s: QLatin1String("0X")))
424 base = 16;
425 else if (s.startsWith(s: QLatin1String("0o")) || s.startsWith(s: QLatin1String("0O")))
426 base = 8;
427 else if (s.startsWith(s: QLatin1String("0b")) || s.startsWith(s: QLatin1String("0B")))
428 base = 2;
429 if (base > 0) {
430 bool ok = true;
431 qlonglong num;
432 num = s.mid(pos: 2).toLongLong(ok: &ok, base);
433 if (!ok)
434 return qQNaN();
435 return num;
436 }
437 }
438 bool ok = false;
439 QByteArray ba = s.toLatin1();
440 const char *begin = ba.constData();
441 const char *end = nullptr;
442 double d = qstrtod(s00: begin, se: &end, ok: &ok);
443 if (end - begin != ba.size()) {
444 if (ba == "Infinity" || ba == "+Infinity")
445 d = Q_INFINITY;
446 else if (ba == "-Infinity")
447 d = -Q_INFINITY;
448 else
449 d = std::numeric_limits<double>::quiet_NaN();
450 }
451 return d;
452}
453
454Heap::String *RuntimeHelpers::stringFromNumber(ExecutionEngine *engine, double number)
455{
456 QString qstr;
457 RuntimeHelpers::numberToString(result: &qstr, num: number, radix: 10);
458 return engine->newString(s: qstr);
459}
460
461ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeHint)
462{
463 ExecutionEngine *engine = object->internalClass()->engine;
464 if (engine->hasException)
465 return Encode::undefined();
466
467 String *hint;
468 switch (typeHint) {
469 case STRING_HINT:
470 hint = engine->id_string();
471 break;
472 case NUMBER_HINT:
473 hint = engine->id_number();
474 break;
475 default:
476 hint = engine->id_default();
477 break;
478 }
479
480 Scope scope(engine);
481 ScopedFunctionObject toPrimitive(scope, object->get(name: engine->symbol_toPrimitive()));
482 if (engine->hasException)
483 return Encode::undefined();
484 if (toPrimitive) {
485 ScopedValue result(scope, toPrimitive->call(thisObject: object, argv: hint, argc: 1));
486 if (engine->hasException)
487 return Encode::undefined();
488 if (!result->isPrimitive())
489 return engine->throwTypeError();
490 return result->asReturnedValue();
491 }
492
493 if (hint == engine->id_default())
494 hint = engine->id_number();
495 return ordinaryToPrimitive(engine, object, typeHint: hint);
496}
497
498
499ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const Object *object, String *typeHint)
500{
501 Q_ASSERT(!engine->hasException);
502
503 String *meth1 = engine->id_toString();
504 String *meth2 = engine->id_valueOf();
505
506 if (typeHint->propertyKey() == engine->id_number()->propertyKey()) {
507 qSwap(value1&: meth1, value2&: meth2);
508 } else {
509 Q_ASSERT(typeHint->propertyKey() == engine->id_string()->propertyKey());
510 }
511
512 Scope scope(engine);
513 ScopedValue result(scope);
514
515 ScopedValue conv(scope, object->get(name: meth1));
516 if (FunctionObject *o = conv->as<FunctionObject>()) {
517 result = o->call(thisObject: object, argv: nullptr, argc: 0);
518 if (engine->hasException)
519 return Encode::undefined();
520 if (result->isPrimitive())
521 return result->asReturnedValue();
522 }
523
524 if (engine->hasException)
525 return Encode::undefined();
526
527 conv = object->get(name: meth2);
528 if (FunctionObject *o = conv->as<FunctionObject>()) {
529 result = o->call(thisObject: object, argv: nullptr, argc: 0);
530 if (engine->hasException)
531 return Encode::undefined();
532 if (result->isPrimitive())
533 return result->asReturnedValue();
534 }
535
536 return engine->throwTypeError();
537}
538
539
540Heap::Object *RuntimeHelpers::convertToObject(ExecutionEngine *engine, const Value &value)
541{
542 Q_ASSERT(!value.isObject());
543 switch (value.type()) {
544 case Value::Undefined_Type:
545 engine->throwTypeError(message: QLatin1String("Value is undefined and could not be converted to an object"));
546 return nullptr;
547 case Value::Null_Type:
548 engine->throwTypeError(message: QLatin1String("Value is null and could not be converted to an object"));
549 return nullptr;
550 case Value::Boolean_Type:
551 return engine->newBooleanObject(b: value.booleanValue());
552 case Value::Managed_Type:
553 Q_ASSERT(value.isStringOrSymbol());
554 if (!value.isString())
555 return engine->newSymbolObject(symbol: value.symbolValue());
556 return engine->newStringObject(string: value.stringValue());
557 case Value::Integer_Type:
558 default: // double
559 return engine->newNumberObject(value: value.asDouble());
560 }
561}
562
563Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, Value value, TypeHint hint)
564{
565 redo:
566 switch (value.type()) {
567 case Value::Empty_Type:
568 Q_ASSERT(!"empty Value encountered");
569 Q_UNREACHABLE();
570 case Value::Undefined_Type:
571 return engine->id_undefined()->d();
572 case Value::Null_Type:
573 return engine->id_null()->d();
574 case Value::Boolean_Type:
575 if (value.booleanValue())
576 return engine->id_true()->d();
577 else
578 return engine->id_false()->d();
579 case Value::Managed_Type: {
580 if (value.isString())
581 return static_cast<const String &>(value).d();
582 if (value.isSymbol()) {
583 engine->throwTypeError(message: QLatin1String("Cannot convert a symbol to a string."));
584 return nullptr;
585 }
586 value = Value::fromReturnedValue(val: RuntimeHelpers::toPrimitive(value, typeHint: hint));
587 Q_ASSERT(value.isPrimitive());
588 if (value.isString())
589 return static_cast<const String &>(value).d();
590 goto redo;
591 }
592 case Value::Integer_Type:
593 return RuntimeHelpers::stringFromNumber(engine, number: value.int_32());
594 default: // double
595 return RuntimeHelpers::stringFromNumber(engine, number: value.doubleValue());
596 } // switch
597}
598
599// This is slightly different from the method above, as
600// the + operator requires a slightly different conversion
601static Heap::String *convert_to_string_add(ExecutionEngine *engine, Value value)
602{
603 return RuntimeHelpers::convertToString(engine, value, hint: PREFERREDTYPE_HINT);
604}
605
606QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Value &left, const Value &right)
607{
608 Scope scope(engine);
609
610 ScopedValue pleft(scope, RuntimeHelpers::toPrimitive(value: left, typeHint: PREFERREDTYPE_HINT));
611 ScopedValue pright(scope, RuntimeHelpers::toPrimitive(value: right, typeHint: PREFERREDTYPE_HINT));
612 String *sleft = pleft->stringValue();
613 String *sright = pright->stringValue();
614 if (sleft || sright) {
615 if (!sleft) {
616 pleft = convert_to_string_add(engine, value: pleft);
617 sleft = static_cast<String *>(pleft.ptr);
618 }
619 if (!sright) {
620 pright = convert_to_string_add(engine, value: pright);
621 sright = static_cast<String *>(pright.ptr);
622 }
623 if (engine->hasException)
624 return Encode::undefined();
625 if (!sleft->d()->length())
626 return sright->asReturnedValue();
627 if (!sright->d()->length())
628 return sleft->asReturnedValue();
629 MemoryManager *mm = engine->memoryManager;
630 return (mm->alloc<ComplexString>(args: sleft->d(), args: sright->d()))->asReturnedValue();
631 }
632 double x = RuntimeHelpers::toNumber(value: pleft);
633 double y = RuntimeHelpers::toNumber(value: pright);
634 return Encode(x + y);
635}
636
637ReturnedValue Runtime::GetTemplateObject::call(Function *function, int index)
638{
639 return function->executableCompilationUnit()->templateObjectAt(index)->asReturnedValue();
640}
641
642void Runtime::StoreProperty::call(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)
643{
644 Scope scope(engine);
645 QV4::Function *v4Function = engine->currentStackFrame->v4Function;
646 ScopedString name(scope, v4Function->compilationUnit->runtimeStrings[nameIndex]);
647 ScopedObject o(scope, object);
648 if (!o) {
649 if (v4Function->isStrict()) {
650 engine->throwTypeError();
651 return;
652 }
653 o = object.toObject(e: engine);
654 }
655 if ((!o || !o->put(name, v: value)) && v4Function->isStrict())
656 engine->throwTypeError();
657}
658
659static Q_NEVER_INLINE ReturnedValue getElementIntFallback(ExecutionEngine *engine, const Value &object, uint idx)
660{
661 Q_ASSERT(idx < UINT_MAX);
662 Scope scope(engine);
663
664 ScopedObject o(scope, object);
665 if (!o) {
666 if (const String *str = object.as<String>()) {
667 if (idx >= (uint)str->toQString().length()) {
668 return Encode::undefined();
669 }
670 const QString s = str->toQString().mid(position: idx, n: 1);
671 return scope.engine->newString(s)->asReturnedValue();
672 }
673
674 if (object.isNullOrUndefined()) {
675 QString message = QStringLiteral("Cannot read property '%1' of %2").arg(a: idx).arg(a: object.toQStringNoThrow());
676 return engine->throwTypeError(message);
677 }
678
679 o = RuntimeHelpers::convertToObject(engine: scope.engine, value: object);
680 Q_ASSERT(!!o); // can't fail as null/undefined is covered above
681 }
682
683 if (o->arrayData() && !o->arrayData()->attrs) {
684 ScopedValue v(scope, o->arrayData()->get(i: idx));
685 if (!v->isEmpty())
686 return v->asReturnedValue();
687 }
688
689 return o->get(idx);
690}
691
692static Q_NEVER_INLINE ReturnedValue getElementFallback(ExecutionEngine *engine, const Value &object, const Value &index)
693{
694 Q_ASSERT(!index.isPositiveInt());
695
696 Scope scope(engine);
697
698 ScopedObject o(scope, object);
699 if (!o) {
700 if (object.isNullOrUndefined()) {
701 QString message = QStringLiteral("Cannot read property '%1' of %2").arg(a: index.toQStringNoThrow()).arg(a: object.toQStringNoThrow());
702 return engine->throwTypeError(message);
703 }
704
705 o = RuntimeHelpers::convertToObject(engine: scope.engine, value: object);
706 Q_ASSERT(!!o); // can't fail as null/undefined is covered above
707 }
708
709 ScopedPropertyKey name(scope, index.toPropertyKey(e: engine));
710 if (scope.hasException())
711 return Encode::undefined();
712 return o->get(id: name);
713}
714
715ReturnedValue Runtime::LoadElement::call(ExecutionEngine *engine, const Value &object, const Value &index)
716{
717 if (index.isPositiveInt()) {
718 uint idx = static_cast<uint>(index.int_32());
719 if (Heap::Base *b = object.heapObject()) {
720 if (b->internalClass->vtable->isObject) {
721 Heap::Object *o = static_cast<Heap::Object *>(b);
722 if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
723 Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
724 if (idx < s->values.size)
725 if (!s->data(index: idx).isEmpty())
726 return s->data(index: idx).asReturnedValue();
727 }
728 }
729 }
730 return getElementIntFallback(engine, object, idx);
731 }
732
733 return getElementFallback(engine, object, index);
734}
735
736static Q_NEVER_INLINE bool setElementFallback(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
737{
738 Scope scope(engine);
739 ScopedObject o(scope, object);
740 if (!o) {
741 if (engine->currentStackFrame->v4Function->isStrict()) {
742 engine->throwTypeError();
743 return false;
744 }
745
746 o = object.toObject(e: engine);
747 }
748 if (engine->hasException)
749 return false;
750
751 if (index.isPositiveInt()) {
752 uint idx = static_cast<uint>(index.int_32());
753 if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) {
754 Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>();
755 if (idx < s->values.size) {
756 s->setData(e: engine, index: idx, newVal: value);
757 return true;
758 }
759 }
760 return o->put(idx, v: value);
761 }
762
763 ScopedPropertyKey name(scope, index.toPropertyKey(e: engine));
764 if (engine->hasException)
765 return false;
766 return o->put(id: name, v: value);
767}
768
769void Runtime::StoreElement::call(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
770{
771 if (index.isPositiveInt()) {
772 uint idx = static_cast<uint>(index.int_32());
773 if (Heap::Base *b = object.heapObject()) {
774 if (b->internalClass->vtable->isObject) {
775 Heap::Object *o = static_cast<Heap::Object *>(b);
776 if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
777 Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
778 if (idx < s->values.size) {
779 s->setData(e: engine, index: idx, newVal: value);
780 return;
781 }
782 }
783 }
784 }
785 }
786
787 if (!setElementFallback(engine, object, index, value) && engine->currentStackFrame->v4Function->isStrict())
788 engine->throwTypeError();
789}
790
791ReturnedValue Runtime::GetIterator::call(ExecutionEngine *engine, const Value &in, int iterator)
792{
793 Scope scope(engine);
794 ScopedObject o(scope, (Object *)nullptr);
795 if (!in.isNullOrUndefined())
796 o = in.toObject(e: engine);
797 if (engine->hasException)
798 return Encode::undefined();
799 if (iterator == static_cast<int>(QQmlJS::AST::ForEachType::Of)) {
800 if (!o)
801 return engine->throwTypeError();
802 ScopedFunctionObject f(scope, o->get(name: engine->symbol_iterator()));
803 if (!f)
804 return engine->throwTypeError();
805 JSCallData cData(scope, 0, nullptr, o);
806 ScopedObject it(scope, f->call(data: cData));
807 if (engine->hasException)
808 return Encode::undefined();
809 if (!it)
810 return engine->throwTypeError();
811 return it->asReturnedValue();
812 }
813 return engine->newForInIteratorObject(o)->asReturnedValue();
814}
815
816ReturnedValue Runtime::IteratorNext::call(ExecutionEngine *engine, const Value &iterator, Value *value)
817{
818 // if we throw an exception from here, return true, not undefined. This is to ensure iteratorDone is set to true
819 // and the stack unwinding won't close the iterator
820 Q_ASSERT(iterator.isObject());
821
822 Scope scope(engine);
823 ScopedFunctionObject f(scope, static_cast<const Object &>(iterator).get(name: engine->id_next()));
824 if (!f) {
825 engine->throwTypeError();
826 return Encode(true);
827 }
828 JSCallData cData(scope, 0, nullptr, &iterator);
829 ScopedObject o(scope, f->call(data: cData));
830 if (scope.hasException())
831 return Encode(true);
832 if (!o) {
833 engine->throwTypeError();
834 return Encode(true);
835 }
836
837 ScopedValue d(scope, o->get(name: engine->id_done()));
838 if (scope.hasException())
839 return Encode(true);
840 bool done = d->toBoolean();
841 if (done) {
842 *value = Encode::undefined();
843 return Encode(true);
844 }
845
846 *value = o->get(name: engine->id_value());
847 if (scope.hasException())
848 return Encode(true);
849 return Encode(false);
850}
851
852ReturnedValue Runtime::IteratorNextForYieldStar::call(ExecutionEngine *engine, const Value &received, const Value &iterator, Value *object)
853{
854 // the return value encodes how to continue the yield* iteration.
855 // true implies iteration is done, false for iteration to continue
856 // a return value of undefines is a special marker, that the iterator has been invoked with return()
857
858 Scope scope(engine);
859 Q_ASSERT(iterator.isObject());
860
861 const Value *arg = &received;
862 bool returnCalled = false;
863 FunctionObject *f = nullptr;
864 if (engine->hasException) {
865 if (engine->exceptionValue->isEmpty()) {
866 // generator called with return()
867 *engine->exceptionValue = Encode::undefined();
868 engine->hasException = false;
869
870 ScopedValue ret(scope, static_cast<const Object &>(iterator).get(name: engine->id_return()));
871 if (ret->isUndefined()) {
872 // propagate return()
873 return Encode::undefined();
874 }
875 returnCalled = true;
876 f = ret->as<FunctionObject>();
877 } else {
878 // generator called with throw
879 ScopedValue exceptionValue(scope, *engine->exceptionValue);
880 *engine->exceptionValue = Encode::undefined();
881 engine->hasException = false;
882
883 ScopedValue t(scope, static_cast<const Object &>(iterator).get(name: engine->id_throw()));
884 if (engine->hasException)
885 return Encode::undefined();
886 if (t->isUndefined()) {
887 // no throw method on the iterator
888 ScopedValue done(scope, Encode(false));
889 IteratorClose::call(engine, iterator, done);
890 if (engine->hasException)
891 return Encode::undefined();
892 return engine->throwTypeError();
893 }
894 f = t->as<FunctionObject>();
895 arg = exceptionValue;
896 }
897 } else {
898 // generator called with next()
899 ScopedFunctionObject next(scope, static_cast<const Object &>(iterator).get(name: engine->id_next()));
900 f = next->as<FunctionObject>();
901 }
902
903 if (!f)
904 return engine->throwTypeError();
905
906 ScopedObject o(scope, f->call(thisObject: &iterator, argv: arg, argc: 1));
907 if (scope.hasException())
908 return Encode(true);
909 if (!o)
910 return engine->throwTypeError();
911
912 ScopedValue d(scope, o->get(name: engine->id_done()));
913 if (scope.hasException())
914 return Encode(true);
915 bool done = d->toBoolean();
916 if (done) {
917 *object = o->get(name: engine->id_value());
918 return returnCalled ? Encode::undefined() : Encode(true);
919 }
920 *object = o;
921 return Encode(false);
922}
923
924ReturnedValue Runtime::IteratorClose::call(ExecutionEngine *engine, const Value &iterator, const Value &done)
925{
926 Q_ASSERT(iterator.isObject());
927 Q_ASSERT(done.isBoolean());
928 if (done.booleanValue())
929 return Encode::undefined();
930
931 Scope scope(engine);
932 ScopedValue e(scope);
933 bool hadException = engine->hasException;
934 if (hadException) {
935 e = *engine->exceptionValue;
936 engine->hasException = false;
937 }
938
939 auto originalCompletion = [=]() {
940 if (hadException) {
941 *engine->exceptionValue = e;
942 engine->hasException = hadException;
943 }
944 return Encode::undefined();
945 };
946
947 ScopedValue ret(scope, static_cast<const Object &>(iterator).get(name: engine->id_return()));
948 ScopedObject o(scope);
949 if (!ret->isUndefined()) {
950 FunctionObject *f = ret->as<FunctionObject>();
951 o = f->call(thisObject: &iterator, argv: nullptr, argc: 0);
952 if (engine->hasException && !hadException)
953 return Encode::undefined();
954 }
955 if (hadException || ret->isUndefined())
956 return originalCompletion();
957
958 if (!o)
959 return engine->throwTypeError();
960
961 return originalCompletion();
962}
963
964ReturnedValue Runtime::DestructureRestElement::call(ExecutionEngine *engine, const Value &iterator)
965{
966 Q_ASSERT(iterator.isObject());
967
968 Scope scope(engine);
969 ScopedArrayObject array(scope, engine->newArrayObject());
970 array->arrayCreate();
971 uint index = 0;
972 while (1) {
973 ScopedValue n(scope);
974 ScopedValue done(scope, IteratorNext::call(engine, iterator, value: n));
975 if (engine->hasException)
976 return Encode::undefined();
977 Q_ASSERT(done->isBoolean());
978 if (done->booleanValue())
979 break;
980 array->arraySet(index, value: n);
981 ++index;
982 }
983 return array->asReturnedValue();
984}
985
986void Runtime::StoreNameSloppy::call(ExecutionEngine *engine, int nameIndex, const Value &value)
987{
988 Scope scope(engine);
989 ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
990 ExecutionContext::Error e = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).setProperty(name, value);
991
992 if (e == ExecutionContext::RangeError)
993 engine->globalObject->put(name, v: value);
994}
995
996void Runtime::StoreNameStrict::call(ExecutionEngine *engine, int nameIndex, const Value &value)
997{
998 Scope scope(engine);
999 ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
1000 ExecutionContext::Error e = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).setProperty(name, value);
1001 if (e == ExecutionContext::TypeError)
1002 engine->throwTypeError();
1003 else if (e == ExecutionContext::RangeError)
1004 engine->throwReferenceError(value: name);
1005}
1006
1007ReturnedValue Runtime::LoadProperty::call(ExecutionEngine *engine, const Value &object, int nameIndex)
1008{
1009 Scope scope(engine);
1010 ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
1011
1012 ScopedObject o(scope, object);
1013 if (o)
1014 return o->get(name);
1015
1016 if (object.isNullOrUndefined()) {
1017 QString message = QStringLiteral("Cannot read property '%1' of %2").arg(a: name->toQString()).arg(a: object.toQStringNoThrow());
1018 return engine->throwTypeError(message);
1019 }
1020
1021 o = RuntimeHelpers::convertToObject(engine: scope.engine, value: object);
1022 if (!o) // type error
1023 return Encode::undefined();
1024 return o->get(name);
1025}
1026
1027ReturnedValue Runtime::LoadName::call(ExecutionEngine *engine, int nameIndex)
1028{
1029 Scope scope(engine);
1030 ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
1031 return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name);
1032}
1033
1034static Object *getSuperBase(Scope &scope)
1035{
1036 if (scope.engine->currentStackFrame->jsFrame->thisObject.isEmpty()) {
1037 scope.engine->throwReferenceError(QStringLiteral("Missing call to super()."), fileName: QString(), lineNumber: 0, column: 0);
1038 return nullptr;
1039 }
1040
1041 ScopedFunctionObject f(
1042 scope, Value::fromStaticValue(staticValue: scope.engine->currentStackFrame->jsFrame->function));
1043 ScopedObject homeObject(scope, f->getHomeObject());
1044 if (!homeObject) {
1045 ScopedContext ctx(scope, static_cast<ExecutionContext *>(&scope.engine->currentStackFrame->jsFrame->context));
1046 Q_ASSERT(ctx);
1047 while (ctx) {
1048 if (CallContext *c = ctx->asCallContext()) {
1049 f = c->d()->function;
1050 QV4::Function *fn = f->function();
1051 if (fn && !fn->isArrowFunction() && !fn->isEval)
1052 break;
1053 }
1054 ctx = ctx->d()->outer;
1055 }
1056 homeObject = f->getHomeObject();
1057 }
1058 if (!homeObject) {
1059 scope.engine->throwTypeError();
1060 return nullptr;
1061 }
1062 Q_ASSERT(homeObject);
1063 ScopedObject proto(scope, homeObject->getPrototypeOf());
1064 if (!proto) {
1065 scope.engine->throwTypeError();
1066 return nullptr;
1067 }
1068 return proto;
1069}
1070
1071ReturnedValue Runtime::LoadSuperProperty::call(ExecutionEngine *engine, const Value &property)
1072{
1073 Scope scope(engine);
1074 Object *base = getSuperBase(scope);
1075 if (!base)
1076 return Encode::undefined();
1077 ScopedPropertyKey key(scope, property.toPropertyKey(e: engine));
1078 if (engine->hasException)
1079 return Encode::undefined();
1080 return base->get(
1081 id: key, receiver: &(engine->currentStackFrame->jsFrame->thisObject.asValue<Value>()));
1082}
1083
1084void Runtime::StoreSuperProperty::call(ExecutionEngine *engine, const Value &property, const Value &value)
1085{
1086 Scope scope(engine);
1087 Object *base = getSuperBase(scope);
1088 if (!base)
1089 return;
1090 ScopedPropertyKey key(scope, property.toPropertyKey(e: engine));
1091 if (engine->hasException)
1092 return;
1093 bool result = base->put(
1094 id: key, v: value, receiver: &(engine->currentStackFrame->jsFrame->thisObject.asValue<Value>()));
1095 if (!result && engine->currentStackFrame->v4Function->isStrict())
1096 engine->throwTypeError();
1097}
1098
1099ReturnedValue Runtime::LoadGlobalLookup::call(ExecutionEngine *engine, Function *f, int index)
1100{
1101 Lookup *l = runtimeLookup(f, i: index);
1102 return l->globalGetter(l, engine);
1103}
1104
1105ReturnedValue Runtime::LoadQmlContextPropertyLookup::call(ExecutionEngine *engine, uint index)
1106{
1107 Lookup *l = runtimeLookup(f: engine->currentStackFrame->v4Function, i: index);
1108 return l->qmlContextPropertyGetter(l, engine, nullptr);
1109}
1110
1111ReturnedValue Runtime::GetLookup::call(ExecutionEngine *engine, Function *f, const Value &base, int index)
1112{
1113 Lookup *l = runtimeLookup(f, i: index);
1114 return l->getter(l, engine, base);
1115}
1116
1117void Runtime::SetLookupSloppy::call(Function *f, const Value &base, int index, const Value &value)
1118{
1119 ExecutionEngine *engine = f->internalClass->engine;
1120 QV4::Lookup *l = runtimeLookup(f, i: index);
1121 l->setter(l, engine, const_cast<Value &>(base), value);
1122}
1123
1124void Runtime::SetLookupStrict::call(Function *f, const Value &base, int index, const Value &value)
1125{
1126 ExecutionEngine *engine = f->internalClass->engine;
1127 QV4::Lookup *l = runtimeLookup(f, i: index);
1128 if (!l->setter(l, engine, const_cast<Value &>(base), value))
1129 engine->throwTypeError();
1130}
1131
1132ReturnedValue Runtime::LoadSuperConstructor::call(ExecutionEngine *engine, const Value &t)
1133{
1134 if (engine->currentStackFrame->thisObject() != Value::emptyValue().asReturnedValue()) {
1135 return engine->throwReferenceError(QStringLiteral("super() already called."), fileName: QString(), lineNumber: 0, column: 0); // ### fix line number
1136 }
1137 const FunctionObject *f = t.as<FunctionObject>();
1138 if (!f)
1139 return engine->throwTypeError();
1140 Heap::Object *c = static_cast<const Object &>(t).getPrototypeOf();
1141 if (!c->vtable()->isFunctionObject || !static_cast<Heap::FunctionObject *>(c)->isConstructor())
1142 return engine->throwTypeError();
1143 return c->asReturnedValue();
1144}
1145
1146uint RuntimeHelpers::equalHelper(const Value &x, const Value &y)
1147{
1148 Q_ASSERT(x.type() != y.type() || (x.isManaged() && (x.isString() != y.isString())));
1149
1150 if (x.isNumber() && y.isNumber())
1151 return x.asDouble() == y.asDouble();
1152 if (x.isNull() && y.isUndefined()) {
1153 return true;
1154 } else if (x.isUndefined() && y.isNull()) {
1155 return true;
1156 } else if (x.isNumber() && y.isString()) {
1157 double dy = RuntimeHelpers::toNumber(value: y);
1158 return x.asDouble() == dy;
1159 } else if (x.isString() && y.isNumber()) {
1160 double dx = RuntimeHelpers::toNumber(value: x);
1161 return dx == y.asDouble();
1162 } else if (x.isBoolean()) {
1163 return Runtime::CompareEqual::call(Value::fromDouble(d: (double) x.booleanValue()), y);
1164 } else if (y.isBoolean()) {
1165 return Runtime::CompareEqual::call(x, Value::fromDouble(d: (double) y.booleanValue()));
1166 } else {
1167 Object *xo = x.objectValue();
1168 Object *yo = y.objectValue();
1169 if (yo && (x.isNumber() || x.isString())) {
1170 Scope scope(yo->engine());
1171 ScopedValue py(scope, RuntimeHelpers::objectDefaultValue(object: yo, typeHint: PREFERREDTYPE_HINT));
1172 return Runtime::CompareEqual::call(x, py);
1173 } else if (xo && (y.isNumber() || y.isString())) {
1174 Scope scope(xo->engine());
1175 ScopedValue px(scope, RuntimeHelpers::objectDefaultValue(object: xo, typeHint: PREFERREDTYPE_HINT));
1176 return Runtime::CompareEqual::call(px, y);
1177 }
1178 }
1179
1180 return false;
1181}
1182
1183Bool RuntimeHelpers::strictEqual(const Value &x, const Value &y)
1184{
1185 TRACE2(x, y);
1186
1187 if (x.rawValue() == y.rawValue())
1188 // NaN != NaN
1189 return !x.isNaN();
1190
1191 if (x.isNumber())
1192 return y.isNumber() && x.asDouble() == y.asDouble();
1193 if (x.isManaged()) {
1194 return y.isManaged() && x.cast<Managed>()->isEqualTo(other: y.cast<Managed>());
1195 }
1196 return false;
1197}
1198
1199QV4::Bool Runtime::CompareGreaterThan::call(const Value &l, const Value &r)
1200{
1201 TRACE2(l, r);
1202 if (l.isInteger() && r.isInteger())
1203 return l.integerValue() > r.integerValue();
1204 if (l.isNumber() && r.isNumber())
1205 return l.asDouble() > r.asDouble();
1206 String *sl = l.stringValue();
1207 String *sr = r.stringValue();
1208 if (sl && sr) {
1209 return sr->lessThan(other: sl);
1210 }
1211
1212 Object *ro = r.objectValue();
1213 Object *lo = l.objectValue();
1214 if (ro || lo) {
1215 QV4::ExecutionEngine *e = (lo ? lo : ro)->engine();
1216 QV4::Scope scope(e);
1217 QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(object: lo, typeHint: QV4::NUMBER_HINT) : l.asReturnedValue());
1218 QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(object: ro, typeHint: QV4::NUMBER_HINT) : r.asReturnedValue());
1219 return Runtime::CompareGreaterThan::call(l: pl, r: pr);
1220 }
1221
1222 double dl = RuntimeHelpers::toNumber(value: l);
1223 double dr = RuntimeHelpers::toNumber(value: r);
1224 return dl > dr;
1225}
1226
1227QV4::Bool Runtime::CompareLessThan::call(const Value &l, const Value &r)
1228{
1229 TRACE2(l, r);
1230 if (l.isInteger() && r.isInteger())
1231 return l.integerValue() < r.integerValue();
1232 if (l.isNumber() && r.isNumber())
1233 return l.asDouble() < r.asDouble();
1234 String *sl = l.stringValue();
1235 String *sr = r.stringValue();
1236 if (sl && sr) {
1237 return sl->lessThan(other: sr);
1238 }
1239
1240 Object *ro = r.objectValue();
1241 Object *lo = l.objectValue();
1242 if (ro || lo) {
1243 QV4::ExecutionEngine *e = (lo ? lo : ro)->engine();
1244 QV4::Scope scope(e);
1245 QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(object: lo, typeHint: QV4::NUMBER_HINT) : l.asReturnedValue());
1246 QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(object: ro, typeHint: QV4::NUMBER_HINT) : r.asReturnedValue());
1247 return Runtime::CompareLessThan::call(l: pl, r: pr);
1248 }
1249
1250 double dl = RuntimeHelpers::toNumber(value: l);
1251 double dr = RuntimeHelpers::toNumber(value: r);
1252 return dl < dr;
1253}
1254
1255QV4::Bool Runtime::CompareGreaterEqual::call(const Value &l, const Value &r)
1256{
1257 TRACE2(l, r);
1258 if (l.isInteger() && r.isInteger())
1259 return l.integerValue() >= r.integerValue();
1260 if (l.isNumber() && r.isNumber())
1261 return l.asDouble() >= r.asDouble();
1262 String *sl = l.stringValue();
1263 String *sr = r.stringValue();
1264 if (sl && sr) {
1265 return !sl->lessThan(other: sr);
1266 }
1267
1268 Object *ro = r.objectValue();
1269 Object *lo = l.objectValue();
1270 if (ro || lo) {
1271 QV4::ExecutionEngine *e = (lo ? lo : ro)->engine();
1272 QV4::Scope scope(e);
1273 QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(object: lo, typeHint: QV4::NUMBER_HINT) : l.asReturnedValue());
1274 QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(object: ro, typeHint: QV4::NUMBER_HINT) : r.asReturnedValue());
1275 return Runtime::CompareGreaterEqual::call(l: pl, r: pr);
1276 }
1277
1278 double dl = RuntimeHelpers::toNumber(value: l);
1279 double dr = RuntimeHelpers::toNumber(value: r);
1280 return dl >= dr;
1281}
1282
1283QV4::Bool Runtime::CompareLessEqual::call(const Value &l, const Value &r)
1284{
1285 TRACE2(l, r);
1286 if (l.isInteger() && r.isInteger())
1287 return l.integerValue() <= r.integerValue();
1288 if (l.isNumber() && r.isNumber())
1289 return l.asDouble() <= r.asDouble();
1290 String *sl = l.stringValue();
1291 String *sr = r.stringValue();
1292 if (sl && sr) {
1293 return !sr->lessThan(other: sl);
1294 }
1295
1296 Object *ro = r.objectValue();
1297 Object *lo = l.objectValue();
1298 if (ro || lo) {
1299 QV4::ExecutionEngine *e = (lo ? lo : ro)->engine();
1300 QV4::Scope scope(e);
1301 QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(object: lo, typeHint: QV4::NUMBER_HINT) : l.asReturnedValue());
1302 QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(object: ro, typeHint: QV4::NUMBER_HINT) : r.asReturnedValue());
1303 return Runtime::CompareLessEqual::call(l: pl, r: pr);
1304 }
1305
1306 double dl = RuntimeHelpers::toNumber(value: l);
1307 double dr = RuntimeHelpers::toNumber(value: r);
1308 return dl <= dr;
1309}
1310
1311Bool Runtime::CompareInstanceof::call(ExecutionEngine *engine, const Value &left, const Value &right)
1312{
1313 TRACE2(left, right);
1314
1315 Scope scope(engine);
1316 ScopedValue v(scope, Instanceof::call(engine, lval: left, rval: right));
1317 return v->booleanValue();
1318}
1319
1320uint Runtime::CompareIn::call(ExecutionEngine *engine, const Value &left, const Value &right)
1321{
1322 TRACE2(left, right);
1323
1324 Scope scope(engine);
1325 ScopedValue v(scope, In::call(engine, left, right));
1326 return v->booleanValue();
1327}
1328
1329static ReturnedValue throwPropertyIsNotAFunctionTypeError(ExecutionEngine *engine, Value *thisObject, const QString &propertyName)
1330{
1331 QString objectAsString = QStringLiteral("[null]");
1332 if (!thisObject->isUndefined())
1333 objectAsString = thisObject->toQStringNoThrow();
1334 QString msg = QStringLiteral("Property '%1' of object %2 is not a function")
1335 .arg(args: propertyName, args&: objectAsString);
1336 return engine->throwTypeError(message: msg);
1337}
1338
1339ReturnedValue Runtime::CallGlobalLookup::call(ExecutionEngine *engine, uint index, Value argv[], int argc)
1340{
1341 Scope scope(engine);
1342 Lookup *l = runtimeLookup(f: engine->currentStackFrame->v4Function, i: index);
1343 Value function = Value::fromReturnedValue(val: l->globalGetter(l, engine));
1344 Value thisObject = Value::undefinedValue();
1345 if (!function.isFunctionObject()) {
1346 return throwPropertyIsNotAFunctionTypeError(engine, thisObject: &thisObject,
1347 propertyName: engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
1348 }
1349
1350 return checkedResult(v4: engine, result: static_cast<FunctionObject &>(function).call(
1351 thisObject: &thisObject, argv, argc));
1352}
1353
1354ReturnedValue Runtime::CallQmlContextPropertyLookup::call(ExecutionEngine *engine, uint index,
1355 Value *argv, int argc)
1356{
1357 Scope scope(engine);
1358 ScopedValue thisObject(scope);
1359 Lookup *l = runtimeLookup(f: engine->currentStackFrame->v4Function, i: index);
1360 Value function = Value::fromReturnedValue(val: l->qmlContextPropertyGetter(l, engine, thisObject));
1361 if (!function.isFunctionObject()) {
1362 return throwPropertyIsNotAFunctionTypeError(engine, thisObject,
1363 propertyName: engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
1364 }
1365
1366 return checkedResult(v4: engine, result: static_cast<FunctionObject &>(function).call(
1367 thisObject, argv, argc));
1368}
1369
1370ReturnedValue Runtime::CallPossiblyDirectEval::call(ExecutionEngine *engine, Value *argv, int argc)
1371{
1372 Scope scope(engine);
1373 ScopedValue thisObject(scope);
1374
1375 ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context);
1376 ScopedFunctionObject function(scope, ctx.getPropertyAndBase(name: engine->id_eval(), base: thisObject));
1377 if (engine->hasException)
1378 return Encode::undefined();
1379
1380 if (!function)
1381 return throwPropertyIsNotAFunctionTypeError(engine, thisObject, propertyName: QLatin1String("eval"));
1382
1383 if (function->d() == engine->evalFunction()->d())
1384 return static_cast<EvalFunction *>(function.getPointer())->evalCall(thisObject, argv, argc, directCall: true);
1385
1386 return checkedResult(v4: engine, result: function->call(thisObject, argv, argc));
1387}
1388
1389ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Value *argv, int argc)
1390{
1391 Scope scope(engine);
1392 ScopedValue thisObject(scope);
1393 ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
1394
1395 ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context);
1396 ScopedFunctionObject f(scope, ctx.getPropertyAndBase(name, base: thisObject));
1397 if (engine->hasException)
1398 return Encode::undefined();
1399
1400 if (!f) {
1401 return throwPropertyIsNotAFunctionTypeError(
1402 engine, thisObject, propertyName: engine->currentStackFrame->v4Function->compilationUnit
1403 ->runtimeStrings[nameIndex]->toQString());
1404 }
1405
1406 return checkedResult(v4: engine, result: f->call(thisObject, argv, argc));
1407}
1408
1409ReturnedValue Runtime::CallProperty::call(ExecutionEngine *engine, const Value &baseRef, int nameIndex, Value *argv, int argc)
1410{
1411 const Value *base = &baseRef;
1412 Scope scope(engine);
1413 ScopedString name(
1414 scope,
1415 engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
1416 ScopedObject lookupObject(scope, base);
1417
1418 if (!lookupObject) {
1419 Q_ASSERT(!base->isEmpty());
1420 if (base->isNullOrUndefined()) {
1421 QString message = QStringLiteral("Cannot call method '%1' of %2")
1422 .arg(args: name->toQString(), args: base->toQStringNoThrow());
1423 return engine->throwTypeError(message);
1424 }
1425
1426 if (base->isManaged()) {
1427 const Managed *m = static_cast<const Managed *>(base);
1428 lookupObject = m->internalClass()->prototype;
1429 Q_ASSERT(m->internalClass()->prototype);
1430 } else {
1431 lookupObject = RuntimeHelpers::convertToObject(engine, value: *base);
1432 if (engine->hasException) // type error
1433 return Encode::undefined();
1434 if (!engine->currentStackFrame->v4Function->isStrict())
1435 base = lookupObject;
1436 }
1437 }
1438
1439 ScopedFunctionObject f(scope, static_cast<Object *>(lookupObject)->get(name));
1440
1441 if (!f) {
1442 QString error = QStringLiteral("Property '%1' of object %2 is not a function")
1443 .arg(args: name->toQString(),
1444 args: base->toQStringNoThrow());
1445 return engine->throwTypeError(message: error);
1446 }
1447
1448 return checkedResult(v4: engine, result: f->call(thisObject: base, argv, argc));
1449}
1450
1451ReturnedValue Runtime::CallPropertyLookup::call(ExecutionEngine *engine, const Value &base, uint index, Value *argv, int argc)
1452{
1453 Lookup *l = runtimeLookup(f: engine->currentStackFrame->v4Function, i: index);
1454 // ok to have the value on the stack here
1455 Value f = Value::fromReturnedValue(val: l->getter(l, engine, base));
1456
1457 if (!f.isFunctionObject())
1458 return engine->throwTypeError();
1459
1460 return checkedResult(v4: engine, result: static_cast<FunctionObject &>(f).call(thisObject: &base, argv, argc));
1461}
1462
1463ReturnedValue Runtime::CallElement::call(ExecutionEngine *engine, const Value &baseRef, const Value &index, Value *argv, int argc)
1464{
1465 const Value *base = &baseRef;
1466 Scope scope(engine);
1467 ScopedValue thisObject(scope, base->toObject(e: engine));
1468 base = thisObject;
1469
1470 ScopedPropertyKey str(scope, index.toPropertyKey(e: engine));
1471 if (engine->hasException)
1472 return Encode::undefined();
1473
1474 ScopedFunctionObject f(scope, static_cast<const Object *>(base)->get(id: str));
1475 if (!f)
1476 return engine->throwTypeError();
1477
1478 return checkedResult(v4: engine, result: f->call(thisObject: base, argv, argc));
1479}
1480
1481ReturnedValue Runtime::CallValue::call(ExecutionEngine *engine, const Value &func, Value *argv, int argc)
1482{
1483 if (!func.isFunctionObject())
1484 return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(a: func.toQStringNoThrow()));
1485 Value undef = Value::undefinedValue();
1486 return checkedResult(v4: engine, result: static_cast<const FunctionObject &>(func).call(
1487 thisObject: &undef, argv, argc));
1488}
1489
1490ReturnedValue Runtime::CallWithReceiver::call(ExecutionEngine *engine, const Value &func,
1491 const Value &thisObject, Value argv[], int argc)
1492{
1493 if (!func.isFunctionObject())
1494 return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(a: func.toQStringNoThrow()));
1495 return checkedResult(v4: engine, result: static_cast<const FunctionObject &>(func).call(
1496 thisObject: &thisObject, argv, argc));
1497}
1498
1499struct CallArgs {
1500 Value *argv;
1501 int argc;
1502};
1503
1504static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc)
1505{
1506 ScopedValue it(scope);
1507 ScopedValue done(scope);
1508
1509 int argCount = 0;
1510
1511 Value *v = scope.alloc<Scope::Uninitialized>();
1512 Value *arguments = v;
1513 for (int i = 0; i < argc; ++i) {
1514 if (!argv[i].isEmpty()) {
1515 *v = argv[i];
1516 ++argCount;
1517 v = scope.alloc<Scope::Uninitialized>();
1518 continue;
1519 }
1520 // spread element
1521 ++i;
1522 it = Runtime::GetIterator::call(engine: scope.engine, in: argv[i], /* ForInIterator */ iterator: 1);
1523 if (scope.engine->hasException)
1524 return { .argv: nullptr, .argc: 0 };
1525 while (1) {
1526 done = Runtime::IteratorNext::call(engine: scope.engine, iterator: it, value: v);
1527 if (scope.engine->hasException)
1528 return { .argv: nullptr, .argc: 0 };
1529 Q_ASSERT(done->isBoolean());
1530 if (done->booleanValue())
1531 break;
1532 ++argCount;
1533 v = scope.alloc<Scope::Uninitialized>();
1534 }
1535 }
1536 return { .argv: arguments, .argc: argCount };
1537}
1538
1539ReturnedValue Runtime::CallWithSpread::call(ExecutionEngine *engine, const Value &function, const Value &thisObject, Value *argv, int argc)
1540{
1541 Q_ASSERT(argc >= 1);
1542 if (!function.isFunctionObject())
1543 return engine->throwTypeError();
1544
1545 Scope scope(engine);
1546 CallArgs arguments = createSpreadArguments(scope, argv, argc);
1547 if (engine->hasException)
1548 return Encode::undefined();
1549
1550 return checkedResult(v4: engine, result: static_cast<const FunctionObject &>(function).call(
1551 thisObject: &thisObject, argv: arguments.argv, argc: arguments.argc));
1552}
1553
1554ReturnedValue Runtime::Construct::call(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc)
1555{
1556 if (!function.isFunctionObject())
1557 return engine->throwTypeError();
1558
1559 return static_cast<const FunctionObject &>(function).callAsConstructor(argv, argc, newTarget: &newTarget);
1560}
1561
1562ReturnedValue Runtime::ConstructWithSpread::call(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc)
1563{
1564 if (!function.isFunctionObject())
1565 return engine->throwTypeError();
1566
1567 Scope scope(engine);
1568 CallArgs arguments = createSpreadArguments(scope, argv, argc);
1569 if (engine->hasException)
1570 return Encode::undefined();
1571
1572 return static_cast<const FunctionObject &>(function).callAsConstructor(argv: arguments.argv, argc: arguments.argc, newTarget: &newTarget);
1573}
1574
1575ReturnedValue Runtime::TailCall::call(CppStackFrame *frame, ExecutionEngine *engine)
1576{
1577 // IMPORTANT! The JIT assumes that this method has the same amount (or less) arguments than
1578 // the jitted function, so it can safely do a tail call.
1579
1580 Value *tos = engine->jsStackTop;
1581 const Value &function = tos[StackOffsets::tailCall_function];
1582 const Value &thisObject = tos[StackOffsets::tailCall_thisObject];
1583 Value *argv = reinterpret_cast<Value *>(frame->jsFrame) + tos[StackOffsets::tailCall_argv].int_32();
1584 int argc = tos[StackOffsets::tailCall_argc].int_32();
1585 Q_ASSERT(argc >= 0);
1586
1587 if (!function.isFunctionObject())
1588 return engine->throwTypeError();
1589
1590 const FunctionObject &fo = static_cast<const FunctionObject &>(function);
1591 if (!frame->callerCanHandleTailCall || !fo.canBeTailCalled() || engine->debugger()
1592 || unsigned(argc) > fo.formalParameterCount()) {
1593 // Cannot tailcall, do a normal call:
1594 return checkedResult(v4: engine, result: fo.call(thisObject: &thisObject, argv, argc));
1595 }
1596
1597 memcpy(dest: frame->jsFrame->args, src: argv, n: argc * sizeof(Value));
1598 frame->init(engine, v4Function: fo.function(), argv: frame->jsFrame->argValues<Value>(), argc,
1599 callerCanHandleTailCall: frame->callerCanHandleTailCall);
1600 frame->setupJSFrame(stackSpace: frame->savedStackTop, function: fo, scope: fo.scope(), thisObject, newTarget: Primitive::undefinedValue());
1601 engine->jsStackTop = frame->savedStackTop + frame->requiredJSStackFrameSize();
1602 frame->pendingTailCall = true;
1603 return Encode::undefined();
1604}
1605
1606void Runtime::ThrowException::call(ExecutionEngine *engine, const Value &value)
1607{
1608 if (!value.isEmpty())
1609 engine->throwError(value);
1610}
1611
1612ReturnedValue Runtime::TypeofValue::call(ExecutionEngine *engine, const Value &value)
1613{
1614 Scope scope(engine);
1615 ScopedString res(scope);
1616 switch (value.type()) {
1617 case Value::Undefined_Type:
1618 res = engine->id_undefined();
1619 break;
1620 case Value::Null_Type:
1621 res = engine->id_object();
1622 break;
1623 case Value::Boolean_Type:
1624 res = engine->id_boolean();
1625 break;
1626 case Value::Managed_Type:
1627 if (value.isString())
1628 res = engine->id_string();
1629 else if (value.isSymbol())
1630 res = engine->id_symbol();
1631 else if (value.objectValue()->as<FunctionObject>())
1632 res = engine->id_function();
1633 else
1634 res = engine->id_object(); // ### implementation-defined
1635 break;
1636 default:
1637 res = engine->id_number();
1638 break;
1639 }
1640 return res.asReturnedValue();
1641}
1642
1643QV4::ReturnedValue Runtime::TypeofName::call(ExecutionEngine *engine, int nameIndex)
1644{
1645 Scope scope(engine);
1646 ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
1647 ScopedValue prop(scope, static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name));
1648 // typeof doesn't throw. clear any possible exception
1649 scope.engine->hasException = false;
1650 return TypeofValue::call(engine, value: prop);
1651}
1652
1653void Runtime::PushCallContext::call(CppStackFrame *frame)
1654{
1655 frame->jsFrame->context = ExecutionContext::newCallContext(frame)->asReturnedValue();
1656}
1657
1658ReturnedValue Runtime::PushWithContext::call(ExecutionEngine *engine, const Value &acc)
1659{
1660 CallData *jsFrame = engine->currentStackFrame->jsFrame;
1661 Value &newAcc = jsFrame->accumulator.asValue<Value>();
1662 newAcc = Value::fromHeapObject(m: acc.toObject(e: engine));
1663 if (!engine->hasException) {
1664 Q_ASSERT(newAcc.isObject());
1665 const Object &obj = static_cast<const Object &>(newAcc);
1666 Value &context = jsFrame->context.asValue<Value>();
1667 auto ec = static_cast<const ExecutionContext *>(&context);
1668 context = ec->newWithContext(with: obj.d())->asReturnedValue();
1669 }
1670 return newAcc.asReturnedValue();
1671}
1672
1673void Runtime::PushCatchContext::call(ExecutionEngine *engine, int blockIndex, int exceptionVarNameIndex)
1674{
1675 auto name = engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[exceptionVarNameIndex];
1676 engine->currentStackFrame->jsFrame->context = ExecutionContext::newCatchContext(frame: engine->currentStackFrame, blockIndex, exceptionVarName: name)->asReturnedValue();
1677}
1678
1679void Runtime::PushBlockContext::call(ExecutionEngine *engine, int index)
1680{
1681 engine->currentStackFrame->jsFrame->context = ExecutionContext::newBlockContext(frame: engine->currentStackFrame, blockIndex: index)->asReturnedValue();
1682}
1683
1684void Runtime::CloneBlockContext::call(ExecutionEngine *engine)
1685{
1686 auto frame = engine->currentStackFrame;
1687 auto context = static_cast<Heap::CallContext *>(
1688 Value::fromStaticValue(staticValue: frame->jsFrame->context).m());
1689 frame->jsFrame->context =
1690 ExecutionContext::cloneBlockContext(engine, callContext: context)->asReturnedValue();
1691}
1692
1693void Runtime::PushScriptContext::call(ExecutionEngine *engine, int index)
1694{
1695 Q_ASSERT(engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_GlobalContext ||
1696 engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_QmlContext);
1697 ReturnedValue c = ExecutionContext::newBlockContext(frame: engine->currentStackFrame, blockIndex: index)->asReturnedValue();
1698 engine->setScriptContext(c);
1699 engine->currentStackFrame->jsFrame->context = c;
1700}
1701
1702void Runtime::PopScriptContext::call(ExecutionEngine *engine)
1703{
1704 ReturnedValue root = engine->rootContext()->asReturnedValue();
1705 engine->setScriptContext(root);
1706 engine->currentStackFrame->jsFrame->context = root;
1707}
1708
1709void Runtime::ThrowReferenceError::call(ExecutionEngine *engine, int nameIndex)
1710{
1711 Scope scope(engine);
1712 ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
1713 engine->throwReferenceError(value: name);
1714}
1715
1716void Runtime::ThrowOnNullOrUndefined::call(ExecutionEngine *engine, const Value &v)
1717{
1718 if (v.isNullOrUndefined())
1719 engine->throwTypeError();
1720}
1721
1722ReturnedValue Runtime::ConvertThisToObject::call(ExecutionEngine *engine, const Value &t)
1723{
1724 if (!t.isObject()) {
1725 if (t.isNullOrUndefined()) {
1726 return engine->globalObject->asReturnedValue();
1727 } else {
1728 return t.toObject(e: engine)->asReturnedValue();
1729 }
1730 }
1731 return t.asReturnedValue();
1732}
1733
1734void Runtime::DeclareVar::call(ExecutionEngine *engine, Bool deletable, int nameIndex)
1735{
1736 Scope scope(engine);
1737 ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
1738 static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).createMutableBinding(name, deletable);
1739}
1740
1741ReturnedValue Runtime::ArrayLiteral::call(ExecutionEngine *engine, Value *values, uint length)
1742{
1743 return engine->newArrayObject(values, length)->asReturnedValue();
1744}
1745
1746ReturnedValue Runtime::ObjectLiteral::call(ExecutionEngine *engine, int classId, QV4::Value args[], int argc)
1747{
1748 Scope scope(engine);
1749 Scoped<InternalClass> klass(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeClasses[classId]);
1750 ScopedObject o(scope, engine->newObject(internalClass: klass->d()));
1751
1752 Q_ASSERT(uint(argc) >= klass->d()->size);
1753
1754 for (uint i = 0; i < klass->d()->size; ++i)
1755 o->setProperty(index: i, v: *args++);
1756
1757 Q_ASSERT((argc - klass->d()->size) % 3 == 0);
1758 int additionalArgs = (argc - int(klass->d()->size))/3;
1759
1760 if (!additionalArgs)
1761 return o->asReturnedValue();
1762
1763 ScopedPropertyKey name(scope);
1764 ScopedProperty pd(scope);
1765 ScopedFunctionObject fn(scope);
1766 ScopedString fnName(scope);
1767 ScopedValue value(scope);
1768 for (int i = 0; i < additionalArgs; ++i) {
1769 Q_ASSERT(args->isInteger());
1770 ObjectLiteralArgument arg = ObjectLiteralArgument(args->integerValue());
1771 name = args[1].toPropertyKey(e: engine);
1772 value = args[2];
1773 if (engine->hasException)
1774 return Encode::undefined();
1775 if (arg != ObjectLiteralArgument::Value) {
1776 Q_ASSERT(args[2].isInteger());
1777 int functionId = args[2].integerValue();
1778 QV4::Function *clos = engine->currentStackFrame->v4Function->executableCompilationUnit()
1779 ->runtimeFunctions[functionId];
1780 Q_ASSERT(clos);
1781
1782 PropertyKey::FunctionNamePrefix prefix = PropertyKey::None;
1783 if (arg == ObjectLiteralArgument::Getter)
1784 prefix = PropertyKey::Getter;
1785 else if (arg == ObjectLiteralArgument::Setter)
1786 prefix = PropertyKey::Setter;
1787 else
1788 arg = ObjectLiteralArgument::Value;
1789 fnName = name->asFunctionName(e: engine, prefix);
1790
1791 ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context);
1792 if (clos->isGenerator())
1793 value = MemberGeneratorFunction::create(scope: current, function: clos, homeObject: o, name: fnName)->asReturnedValue();
1794 else
1795 value = FunctionObject::createMemberFunction(scope: current, function: clos, homeObject: o, name: fnName)->asReturnedValue();
1796 } else if (args[2].isFunctionObject()) {
1797 fn = static_cast<const FunctionObject &>(args[2]);
1798
1799 fnName = name->asFunctionName(e: engine, prefix: PropertyKey::None);
1800 fn->setName(fnName);
1801 }
1802 Q_ASSERT(arg != ObjectLiteralArgument::Method);
1803 Q_ASSERT(arg == ObjectLiteralArgument::Value || value->isFunctionObject());
1804 if (arg == ObjectLiteralArgument::Value || arg == ObjectLiteralArgument::Getter) {
1805 pd->value = value;
1806 pd->set = Value::emptyValue();
1807 } else {
1808 pd->value = Value::emptyValue();
1809 pd->set = value;
1810 }
1811 bool ok = o->defineOwnProperty(id: name, p: pd, attrs: (arg == ObjectLiteralArgument::Value ? Attr_Data : Attr_Accessor));
1812 if (!ok)
1813 return engine->throwTypeError();
1814
1815 args += 3;
1816 }
1817 return o.asReturnedValue();
1818}
1819
1820ReturnedValue Runtime::CreateClass::call(ExecutionEngine *engine, int classIndex,
1821 const Value &superClass, Value computedNames[])
1822{
1823 const QV4::ExecutableCompilationUnit *unit
1824 = engine->currentStackFrame->v4Function->executableCompilationUnit();
1825 const QV4::CompiledData::Class *cls = unit->unitData()->classAt(idx: classIndex);
1826
1827 Scope scope(engine);
1828 ScopedObject protoParent(scope, engine->objectPrototype());
1829 ScopedObject constructorParent(scope, engine->functionPrototype());
1830 if (!superClass.isEmpty()) {
1831 if (superClass.isNull()) {
1832 protoParent = Encode::null();
1833 } else {
1834 const FunctionObject *superFunction = superClass.as<FunctionObject>();
1835 // ### check that the heritage object is a constructor
1836 if (!superFunction || !superFunction->isConstructor())
1837 return engine->throwTypeError(QStringLiteral("The superclass is not a function object."));
1838 const FunctionObject *s = static_cast<const FunctionObject *>(&superClass);
1839 ScopedValue result(scope, s->get(name: scope.engine->id_prototype()));
1840 if (!result->isObject() && !result->isNull())
1841 return engine->throwTypeError(QStringLiteral("The value of the superclass's prototype property is not an object."));
1842 protoParent = *result;
1843 constructorParent = superClass;
1844 }
1845 }
1846
1847 ScopedObject proto(scope, engine->newObject());
1848 proto->setPrototypeUnchecked(protoParent);
1849 ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context);
1850
1851 ScopedFunctionObject constructor(scope);
1852 QV4::Function *f = cls->constructorFunction != UINT_MAX ? unit->runtimeFunctions[cls->constructorFunction] : nullptr;
1853 constructor = FunctionObject::createConstructorFunction(scope: current, function: f, homeObject: proto, isDerivedConstructor: !superClass.isEmpty())->asReturnedValue();
1854 constructor->setPrototypeUnchecked(constructorParent);
1855 Value argCount = Value::fromInt32(i: f ? f->nFormals : 0);
1856 constructor->defineReadonlyConfigurableProperty(name: scope.engine->id_length(), value: argCount);
1857 constructor->defineReadonlyConfigurableProperty(name: engine->id_prototype(), value: proto);
1858 proto->defineDefaultProperty(name: engine->id_constructor(), value: constructor);
1859
1860 ScopedString name(scope);
1861 if (cls->nameIndex != UINT_MAX) {
1862 name = unit->runtimeStrings[cls->nameIndex];
1863 constructor->defineReadonlyConfigurableProperty(name: engine->id_name(), value: name);
1864 }
1865
1866 ScopedObject receiver(scope, *constructor);
1867 ScopedPropertyKey propertyName(scope);
1868 ScopedFunctionObject function(scope);
1869 ScopedProperty property(scope);
1870 const CompiledData::Method *methods = cls->methodTable();
1871 for (uint i = 0; i < cls->nStaticMethods + cls->nMethods; ++i) {
1872 if (i == cls->nStaticMethods)
1873 receiver = proto;
1874 if (methods[i].name == UINT_MAX) {
1875 propertyName = computedNames->toPropertyKey(e: engine);
1876 if (propertyName == scope.engine->id_prototype()->propertyKey() && receiver->d() == constructor->d())
1877 return engine->throwTypeError(QStringLiteral("Cannot declare a static method named 'prototype'."));
1878 if (engine->hasException)
1879 return Encode::undefined();
1880 ++computedNames;
1881 } else {
1882 name = unit->runtimeStrings[methods[i].name];
1883 propertyName = name->toPropertyKey();
1884 }
1885 QV4::Function *f = unit->runtimeFunctions[methods[i].function];
1886 Q_ASSERT(f);
1887 PropertyKey::FunctionNamePrefix prefix = PropertyKey::None;
1888 if (methods[i].type == CompiledData::Method::Getter)
1889 prefix = PropertyKey::Getter;
1890 else if (methods[i].type == CompiledData::Method::Setter)
1891 prefix = PropertyKey::Setter;
1892
1893 name = propertyName->asFunctionName(e: engine, prefix);
1894
1895 if (f->isGenerator())
1896 function = MemberGeneratorFunction::create(scope: current, function: f, homeObject: receiver, name);
1897 else
1898 function = FunctionObject::createMemberFunction(scope: current, function: f, homeObject: receiver, name);
1899 Q_ASSERT(function);
1900 PropertyAttributes attributes;
1901 switch (methods[i].type) {
1902 case CompiledData::Method::Getter:
1903 property->setGetter(function);
1904 property->set = Value::emptyValue();
1905 attributes = Attr_Accessor|Attr_NotEnumerable;
1906 break;
1907 case CompiledData::Method::Setter:
1908 property->value = Value::emptyValue();
1909 property->setSetter(function);
1910 attributes = Attr_Accessor|Attr_NotEnumerable;
1911 break;
1912 default: // Regular
1913 property->value = function;
1914 property->set = Value::emptyValue();
1915 attributes = Attr_Data|Attr_NotEnumerable;
1916 break;
1917 }
1918 receiver->defineOwnProperty(id: propertyName, p: property, attrs: attributes);
1919 }
1920
1921 return constructor->asReturnedValue();
1922}
1923
1924QV4::ReturnedValue Runtime::CreateMappedArgumentsObject::call(ExecutionEngine *engine)
1925{
1926 Q_ASSERT(engine->currentContext()->d()->type == Heap::ExecutionContext::Type_CallContext);
1927 Heap::InternalClass *ic = engine->internalClasses(icType: EngineBase::Class_ArgumentsObject);
1928 return engine->memoryManager->allocObject<ArgumentsObject>(ic, args: engine->currentStackFrame)->asReturnedValue();
1929}
1930
1931QV4::ReturnedValue Runtime::CreateUnmappedArgumentsObject::call(ExecutionEngine *engine)
1932{
1933 Heap::InternalClass *ic = engine->internalClasses(icType: EngineBase::Class_StrictArgumentsObject);
1934 return engine->memoryManager->allocObject<StrictArgumentsObject>(ic, args: engine->currentStackFrame)->asReturnedValue();
1935}
1936
1937QV4::ReturnedValue Runtime::CreateRestParameter::call(ExecutionEngine *engine, int argIndex)
1938{
1939 const Value *values = engine->currentStackFrame->originalArguments + argIndex;
1940 int nValues = engine->currentStackFrame->originalArgumentsCount - argIndex;
1941 if (nValues <= 0)
1942 return engine->newArrayObject(count: 0)->asReturnedValue();
1943 return engine->newArrayObject(values, length: nValues)->asReturnedValue();
1944}
1945
1946ReturnedValue Runtime::RegexpLiteral::call(ExecutionEngine *engine, int id)
1947{
1948 const auto val
1949 = engine->currentStackFrame->v4Function->compilationUnit->runtimeRegularExpressions[id];
1950 Heap::RegExpObject *ro = engine->newRegExpObject(re: Value::fromStaticValue(staticValue: val).as<RegExp>());
1951 return ro->asReturnedValue();
1952}
1953
1954ReturnedValue Runtime::ToObject::call(ExecutionEngine *engine, const Value &obj)
1955{
1956 if (obj.isObject())
1957 return obj.asReturnedValue();
1958
1959 return obj.toObject(e: engine)->asReturnedValue();
1960}
1961
1962Bool Runtime::ToBoolean::call(const Value &obj)
1963{
1964 return obj.toBoolean();
1965}
1966
1967ReturnedValue Runtime::ToNumber::call(ExecutionEngine *, const Value &v)
1968{
1969 return Encode(v.toNumber());
1970}
1971
1972ReturnedValue Runtime::UMinus::call(const Value &value)
1973{
1974 TRACE1(value);
1975
1976 // +0 != -0, so we need to convert to double when negating 0
1977 if (value.isInteger() && value.integerValue() &&
1978 value.integerValue() != std::numeric_limits<int>::min())
1979 return Encode(-value.integerValue());
1980 else {
1981 double n = RuntimeHelpers::toNumber(value);
1982 return Encode(-n);
1983 }
1984}
1985
1986// binary operators
1987
1988ReturnedValue Runtime::Add::call(ExecutionEngine *engine, const Value &left, const Value &right)
1989{
1990 TRACE2(left, right);
1991
1992 if (Q_LIKELY(left.integerCompatible() && right.integerCompatible()))
1993 return add_int32(a: left.integerValue(), b: right.integerValue());
1994 if (left.isNumber() && right.isNumber())
1995 return Value::fromDouble(d: left.asDouble() + right.asDouble()).asReturnedValue();
1996
1997 return RuntimeHelpers::addHelper(engine, left, right);
1998}
1999
2000ReturnedValue Runtime::Sub::call(const Value &left, const Value &right)
2001{
2002 TRACE2(left, right);
2003
2004 if (Q_LIKELY(left.integerCompatible() && right.integerCompatible()))
2005 return sub_int32(a: left.integerValue(), b: right.integerValue());
2006
2007 double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl();
2008 double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl();
2009
2010 return Value::fromDouble(d: lval - rval).asReturnedValue();
2011}
2012
2013ReturnedValue Runtime::Mul::call(const Value &left, const Value &right)
2014{
2015 TRACE2(left, right);
2016
2017 if (Q_LIKELY(left.integerCompatible() && right.integerCompatible()))
2018 return mul_int32(a: left.integerValue(), b: right.integerValue());
2019
2020 double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl();
2021 double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl();
2022
2023 return Value::fromDouble(d: lval * rval).asReturnedValue();
2024}
2025
2026ReturnedValue Runtime::Div::call(const Value &left, const Value &right)
2027{
2028 TRACE2(left, right);
2029
2030 if (Value::integerCompatible(a: left, b: right)) {
2031 int lval = left.integerValue();
2032 int rval = right.integerValue();
2033 if (rval != 0 // division by zero should result in a NaN
2034 && !(lval == std::numeric_limits<int>::min() && rval == -1) // doesn't fit in int
2035 && (lval % rval == 0) // fractions can't be stored in an int
2036 && !(lval == 0 && rval < 0)) // 0 / -something results in -0.0
2037 return Encode(int(lval / rval));
2038 else
2039 return Encode(double(lval) / rval);
2040 }
2041
2042 double lval = left.toNumber();
2043 double rval = right.toNumber();
2044 return Value::fromDouble(d: lval / rval).asReturnedValue();
2045}
2046
2047ReturnedValue Runtime::Mod::call(const Value &left, const Value &right)
2048{
2049 TRACE2(left, right);
2050
2051 if (Value::integerCompatible(a: left, b: right) && left.integerValue() >= 0 && right.integerValue() > 0) {
2052 // special cases are handled by fmod, among them:
2053 // - arithmic execeptions for ints in c++, eg: INT_MIN % -1
2054 // - undefined behavior in c++, e.g.: anything % 0
2055 // - uncommon cases which would complicate the condition, e.g.: negative integers
2056 // (this makes sure that -1 % 1 == -0 by passing it to fmod)
2057 return Encode(left.integerValue() % right.integerValue());
2058 }
2059
2060 double lval = RuntimeHelpers::toNumber(value: left);
2061 double rval = RuntimeHelpers::toNumber(value: right);
2062#ifdef fmod
2063# undef fmod
2064#endif
2065 return Value::fromDouble(d: std::fmod(x: lval, y: rval)).asReturnedValue();
2066}
2067
2068ReturnedValue Runtime::Exp::call(const Value &base, const Value &exp)
2069{
2070 double b = base.toNumber();
2071 double e = exp.toNumber();
2072 if (qt_is_inf(d: e) && (b == 1 || b == -1))
2073 return Encode(qt_qnan());
2074 return Encode(pow(x: b,y: e));
2075}
2076
2077ReturnedValue Runtime::BitAnd::call(const Value &left, const Value &right)
2078{
2079 TRACE2(left, right);
2080
2081 int lval = left.toInt32();
2082 int rval = right.toInt32();
2083 return Encode((int)(lval & rval));
2084}
2085
2086ReturnedValue Runtime::BitOr::call(const Value &left, const Value &right)
2087{
2088 TRACE2(left, right);
2089
2090 int lval = left.toInt32();
2091 int rval = right.toInt32();
2092 return Encode((int)(lval | rval));
2093}
2094
2095ReturnedValue Runtime::BitXor::call(const Value &left, const Value &right)
2096{
2097 TRACE2(left, right);
2098
2099 int lval = left.toInt32();
2100 int rval = right.toInt32();
2101 return Encode((int)(lval ^ rval));
2102}
2103
2104ReturnedValue Runtime::Shl::call(const Value &left, const Value &right)
2105{
2106 TRACE2(left, right);
2107
2108 int lval = left.toInt32();
2109 int rval = right.toInt32() & 0x1f;
2110 return Encode((int)(lval << rval));
2111}
2112
2113ReturnedValue Runtime::Shr::call(const Value &left, const Value &right)
2114{
2115 TRACE2(left, right);
2116
2117 int lval = left.toInt32();
2118 unsigned rval = right.toUInt32() & 0x1f;
2119 return Encode((int)(lval >> rval));
2120}
2121
2122ReturnedValue Runtime::UShr::call(const Value &left, const Value &right)
2123{
2124 TRACE2(left, right);
2125
2126 unsigned lval = left.toUInt32();
2127 unsigned rval = right.toUInt32() & 0x1f;
2128 uint res = lval >> rval;
2129
2130 return Encode(res);
2131}
2132
2133ReturnedValue Runtime::GreaterThan::call(const Value &left, const Value &right)
2134{
2135 TRACE2(left, right);
2136
2137 bool r = CompareGreaterThan::call(l: left, r: right);
2138 return Encode(r);
2139}
2140
2141ReturnedValue Runtime::LessThan::call(const Value &left, const Value &right)
2142{
2143 TRACE2(left, right);
2144
2145 bool r = CompareLessThan::call(l: left, r: right);
2146 return Encode(r);
2147}
2148
2149ReturnedValue Runtime::GreaterEqual::call(const Value &left, const Value &right)
2150{
2151 TRACE2(left, right);
2152
2153 bool r = CompareGreaterEqual::call(l: left, r: right);
2154 return Encode(r);
2155}
2156
2157ReturnedValue Runtime::LessEqual::call(const Value &left, const Value &right)
2158{
2159 TRACE2(left, right);
2160
2161 bool r = CompareLessEqual::call(l: left, r: right);
2162 return Encode(r);
2163}
2164
2165struct LazyScope
2166{
2167 ExecutionEngine *engine = nullptr;
2168 Value *stackMark = nullptr;
2169 ~LazyScope() {
2170 if (engine)
2171 engine->jsStackTop = stackMark;
2172 }
2173 template <typename T>
2174 void set(Value **scopedValue, T value, ExecutionEngine *e) {
2175 if (!engine) {
2176 engine = e;
2177 stackMark = engine->jsStackTop;
2178 }
2179 if (!*scopedValue)
2180 *scopedValue = e->jsAlloca(nValues: 1);
2181 **scopedValue = value;
2182 }
2183};
2184
2185Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
2186{
2187 TRACE2(left, right);
2188
2189 Value lhs = left;
2190 Value rhs = right;
2191
2192 LazyScope scope;
2193 Value *lhsGuard = nullptr;
2194 Value *rhsGuard = nullptr;
2195
2196 redo:
2197 if (lhs.asReturnedValue() == rhs.asReturnedValue())
2198 return !lhs.isNaN();
2199
2200 int lt = lhs.quickType();
2201 int rt = rhs.quickType();
2202 if (rt < lt) {
2203 qSwap(value1&: lhs, value2&: rhs);
2204 qSwap(value1&: lt, value2&: rt);
2205 }
2206
2207 switch (lt) {
2208 case QV4::Value::QT_ManagedOrUndefined:
2209 if (lhs.isUndefined())
2210 return rhs.isNullOrUndefined();
2211 Q_FALLTHROUGH();
2212 case QV4::Value::QT_ManagedOrUndefined1:
2213 case QV4::Value::QT_ManagedOrUndefined2:
2214 case QV4::Value::QT_ManagedOrUndefined3:
2215 // LHS: Managed
2216 switch (rt) {
2217 case QV4::Value::QT_ManagedOrUndefined:
2218 if (rhs.isUndefined())
2219 return false;
2220 Q_FALLTHROUGH();
2221 case QV4::Value::QT_ManagedOrUndefined1:
2222 case QV4::Value::QT_ManagedOrUndefined2:
2223 case QV4::Value::QT_ManagedOrUndefined3: {
2224 // RHS: Managed
2225 Heap::Base *l = lhs.m();
2226 Heap::Base *r = rhs.m();
2227 Q_ASSERT(l);
2228 Q_ASSERT(r);
2229 if (l->internalClass->vtable->isStringOrSymbol == r->internalClass->vtable->isStringOrSymbol)
2230 return static_cast<QV4::Managed &>(lhs).isEqualTo(other: &static_cast<QV4::Managed &>(rhs));
2231 if (l->internalClass->vtable->isStringOrSymbol) {
2232 scope.set(scopedValue: &rhsGuard, value: RuntimeHelpers::objectDefaultValue(object: &static_cast<QV4::Object &>(rhs), typeHint: PREFERREDTYPE_HINT), e: r->internalClass->engine);
2233 rhs = rhsGuard->asReturnedValue();
2234 break;
2235 } else {
2236 Q_ASSERT(r->internalClass->vtable->isStringOrSymbol);
2237 scope.set(scopedValue: &lhsGuard, value: RuntimeHelpers::objectDefaultValue(object: &static_cast<QV4::Object &>(lhs), typeHint: PREFERREDTYPE_HINT), e: l->internalClass->engine);
2238 lhs = lhsGuard->asReturnedValue();
2239 break;
2240 }
2241 return false;
2242 }
2243 case QV4::Value::QT_Empty:
2244 Q_UNREACHABLE();
2245 case QV4::Value::QT_Null:
2246 return false;
2247 case QV4::Value::QT_Bool:
2248 case QV4::Value::QT_Int:
2249 rhs = Value::fromDouble(d: rhs.int_32());
2250 // fall through
2251 default: // double
2252 if (lhs.m()->internalClass->vtable->isStringOrSymbol) {
2253 return lhs.m()->internalClass->vtable->isString ? (RuntimeHelpers::toNumber(value: lhs) == rhs.doubleValue()) : false;
2254 } else {
2255 scope.set(scopedValue: &lhsGuard, value: RuntimeHelpers::objectDefaultValue(object: &static_cast<QV4::Object &>(lhs), typeHint: PREFERREDTYPE_HINT), e: lhs.m()->internalClass->engine);
2256 lhs = lhsGuard->asReturnedValue();
2257 }
2258 }
2259 goto redo;
2260 case QV4::Value::QT_Empty:
2261 Q_UNREACHABLE();
2262 case QV4::Value::QT_Null:
2263 return rhs.isNull();
2264 case QV4::Value::QT_Bool:
2265 case QV4::Value::QT_Int:
2266 switch (rt) {
2267 case QV4::Value::QT_ManagedOrUndefined:
2268 case QV4::Value::QT_ManagedOrUndefined1:
2269 case QV4::Value::QT_ManagedOrUndefined2:
2270 case QV4::Value::QT_ManagedOrUndefined3:
2271 case QV4::Value::QT_Empty:
2272 case QV4::Value::QT_Null:
2273 Q_UNREACHABLE();
2274 case QV4::Value::QT_Bool:
2275 case QV4::Value::QT_Int:
2276 return lhs.int_32() == rhs.int_32();
2277 default: // double
2278 return lhs.int_32() == rhs.doubleValue();
2279 }
2280 default: // double
2281 Q_ASSERT(rhs.isDouble());
2282 return lhs.doubleValue() == rhs.doubleValue();
2283 }
2284}
2285
2286ReturnedValue Runtime::Equal::call(const Value &left, const Value &right)
2287{
2288 TRACE2(left, right);
2289
2290 bool r = CompareEqual::call(left, right);
2291 return Encode(r);
2292}
2293
2294ReturnedValue Runtime::NotEqual::call(const Value &left, const Value &right)
2295{
2296 TRACE2(left, right);
2297
2298 bool r = !CompareEqual::call(left, right);
2299 return Encode(r);
2300}
2301
2302ReturnedValue Runtime::StrictEqual::call(const Value &left, const Value &right)
2303{
2304 TRACE2(left, right);
2305
2306 bool r = RuntimeHelpers::strictEqual(x: left, y: right);
2307 return Encode(r);
2308}
2309
2310ReturnedValue Runtime::StrictNotEqual::call(const Value &left, const Value &right)
2311{
2312 TRACE2(left, right);
2313
2314 bool r = ! RuntimeHelpers::strictEqual(x: left, y: right);
2315 return Encode(r);
2316}
2317
2318Bool Runtime::CompareNotEqual::call(const Value &left, const Value &right)
2319{
2320 TRACE2(left, right);
2321
2322 return !Runtime::CompareEqual::call(left, right);
2323}
2324
2325Bool Runtime::CompareStrictEqual::call(const Value &left, const Value &right)
2326{
2327 TRACE2(left, right);
2328
2329 return RuntimeHelpers::strictEqual(x: left, y: right);
2330}
2331
2332Bool Runtime::CompareStrictNotEqual::call(const Value &left, const Value &right)
2333{
2334 TRACE2(left, right);
2335
2336 return ! RuntimeHelpers::strictEqual(x: left, y: right);
2337}
2338
2339template<typename Operation>
2340static inline const void *symbol()
2341{
2342 return reinterpret_cast<void *>(&Operation::call);
2343}
2344
2345QHash<const void *, const char *> Runtime::symbolTable()
2346{
2347 static const QHash<const void *, const char *> symbols({
2348#ifndef V4_BOOTSTRAP
2349 {symbol<CallGlobalLookup>(), "CallGlobalLookup" },
2350 {symbol<CallQmlContextPropertyLookup>(), "CallQmlContextPropertyLookup" },
2351 {symbol<CallName>(), "CallName" },
2352 {symbol<CallProperty>(), "CallProperty" },
2353 {symbol<CallPropertyLookup>(), "CallPropertyLookup" },
2354 {symbol<CallElement>(), "CallElement" },
2355 {symbol<CallValue>(), "CallValue" },
2356 {symbol<CallWithReceiver>(), "CallWithReceiver" },
2357 {symbol<CallPossiblyDirectEval>(), "CallPossiblyDirectEval" },
2358 {symbol<CallWithSpread>(), "CallWithSpread" },
2359 {symbol<TailCall>(), "TailCall" },
2360
2361 {symbol<Construct>(), "Construct" },
2362 {symbol<ConstructWithSpread>(), "ConstructWithSpread" },
2363
2364 {symbol<StoreNameStrict>(), "StoreNameStrict" },
2365 {symbol<StoreNameSloppy>(), "StoreNameSloppy" },
2366 {symbol<StoreProperty>(), "StoreProperty" },
2367 {symbol<StoreElement>(), "StoreElement" },
2368 {symbol<LoadProperty>(), "LoadProperty" },
2369 {symbol<LoadName>(), "LoadName" },
2370 {symbol<LoadElement>(), "LoadElement" },
2371 {symbol<LoadSuperProperty>(), "LoadSuperProperty" },
2372 {symbol<StoreSuperProperty>(), "StoreSuperProperty" },
2373 {symbol<LoadSuperConstructor>(), "LoadSuperConstructor" },
2374 {symbol<LoadGlobalLookup>(), "LoadGlobalLookup" },
2375 {symbol<LoadQmlContextPropertyLookup>(), "LoadQmlContextPropertyLookup" },
2376 {symbol<GetLookup>(), "GetLookup" },
2377 {symbol<SetLookupStrict>(), "SetLookupStrict" },
2378 {symbol<SetLookupSloppy>(), "SetLookupSloppy" },
2379
2380 {symbol<TypeofValue>(), "TypeofValue" },
2381 {symbol<TypeofName>(), "TypeofName" },
2382
2383 {symbol<DeleteProperty_NoThrow>(), "DeleteProperty_NoThrow" },
2384 {symbol<DeleteProperty>(), "DeleteProperty" },
2385 {symbol<DeleteName_NoThrow>(), "DeleteName_NoThrow" },
2386 {symbol<DeleteName>(), "DeleteName" },
2387
2388 {symbol<ThrowException>(), "ThrowException" },
2389 {symbol<PushCallContext>(), "PushCallContext" },
2390 {symbol<PushWithContext>(), "PushWithContext" },
2391 {symbol<PushCatchContext>(), "PushCatchContext" },
2392 {symbol<PushBlockContext>(), "PushBlockContext" },
2393 {symbol<CloneBlockContext>(), "CloneBlockContext" },
2394 {symbol<PushScriptContext>(), "PushScriptContext" },
2395 {symbol<PopScriptContext>(), "PopScriptContext" },
2396 {symbol<ThrowReferenceError>(), "ThrowReferenceError" },
2397 {symbol<ThrowOnNullOrUndefined>(), "ThrowOnNullOrUndefined" },
2398
2399 {symbol<Closure>(), "Closure" },
2400
2401 {symbol<ConvertThisToObject>(), "ConvertThisToObject" },
2402 {symbol<DeclareVar>(), "DeclareVar" },
2403 {symbol<CreateMappedArgumentsObject>(), "CreateMappedArgumentsObject" },
2404 {symbol<CreateUnmappedArgumentsObject>(), "CreateUnmappedArgumentsObject" },
2405 {symbol<CreateRestParameter>(), "CreateRestParameter" },
2406
2407 {symbol<ArrayLiteral>(), "ArrayLiteral" },
2408 {symbol<ObjectLiteral>(), "ObjectLiteral" },
2409 {symbol<CreateClass>(), "CreateClass" },
2410
2411 {symbol<GetIterator>(), "GetIterator" },
2412 {symbol<IteratorNext>(), "IteratorNext" },
2413 {symbol<IteratorNextForYieldStar>(), "IteratorNextForYieldStar" },
2414 {symbol<IteratorClose>(), "IteratorClose" },
2415 {symbol<DestructureRestElement>(), "DestructureRestElement" },
2416
2417 {symbol<ToObject>(), "ToObject" },
2418 {symbol<ToBoolean>(), "ToBoolean" },
2419 {symbol<ToNumber>(), "ToNumber" },
2420
2421 {symbol<UMinus>(), "UMinus" },
2422
2423 {symbol<Instanceof>(), "Instanceof" },
2424 {symbol<In>(), "In" },
2425 {symbol<Add>(), "Add" },
2426 {symbol<Sub>(), "Sub" },
2427 {symbol<Mul>(), "Mul" },
2428 {symbol<Div>(), "Div" },
2429 {symbol<Mod>(), "Mod" },
2430 {symbol<Exp>(), "Exp" },
2431 {symbol<BitAnd>(), "BitAnd" },
2432 {symbol<BitOr>(), "BitOr" },
2433 {symbol<BitXor>(), "BitXor" },
2434 {symbol<Shl>(), "Shl" },
2435 {symbol<Shr>(), "Shr" },
2436 {symbol<UShr>(), "UShr" },
2437 {symbol<GreaterThan>(), "GreaterThan" },
2438 {symbol<LessThan>(), "LessThan" },
2439 {symbol<GreaterEqual>(), "GreaterEqual" },
2440 {symbol<LessEqual>(), "LessEqual" },
2441 {symbol<Equal>(), "Equal" },
2442 {symbol<NotEqual>(), "NotEqual" },
2443 {symbol<StrictEqual>(), "StrictEqual" },
2444 {symbol<StrictNotEqual>(), "StrictNotEqual" },
2445
2446 {symbol<CompareGreaterThan>(), "CompareGreaterThan" },
2447 {symbol<CompareLessThan>(), "CompareLessThan" },
2448 {symbol<CompareGreaterEqual>(), "CompareGreaterEqual" },
2449 {symbol<CompareLessEqual>(), "CompareLessEqual" },
2450 {symbol<CompareEqual>(), "CompareEqual" },
2451 {symbol<CompareNotEqual>(), "CompareNotEqual" },
2452 {symbol<CompareStrictEqual>(), "CompareStrictEqual" },
2453 {symbol<CompareStrictNotEqual>(), "CompareStrictNotEqual" },
2454
2455 {symbol<CompareInstanceof>(), "CompareInstanceOf" },
2456 {symbol<CompareIn>(), "CompareIn" },
2457
2458 {symbol<RegexpLiteral>(), "RegexpLiteral" },
2459 {symbol<GetTemplateObject>(), "GetTemplateObject" }
2460#endif
2461 });
2462
2463 return symbols;
2464}
2465
2466} // namespace QV4
2467
2468QT_END_NAMESPACE
2469

source code of qtdeclarative/src/qml/jsruntime/qv4runtime.cpp