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