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