aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4runtime.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4runtime.cpp')
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp529
1 files changed, 314 insertions, 215 deletions
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 21a0017728..184e7c7819 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1,83 +1,48 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4global_p.h"
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
#include "qv4runtime_p.h"
-#include "qv4engine_p.h"
-#include "qv4object_p.h"
-#include "qv4objectproto_p.h"
-#include "qv4globalobject_p.h"
-#include "qv4stringobject_p.h"
-#include "qv4argumentsobject_p.h"
-#include "qv4objectiterator_p.h"
-#include "qv4dateobject_p.h"
-#include "qv4lookup_p.h"
-#include "qv4function_p.h"
-#include "qv4numberobject_p.h"
-#include "qv4regexp_p.h"
-#include "qv4regexpobject_p.h"
-#include "private/qlocale_tools_p.h"
-#include "qv4scopedvalue_p.h"
-#include "qv4jscall_p.h"
-#include <private/qv4qmlcontext_p.h>
-#include <private/qqmltypewrapper_p.h>
+
#include <private/qqmlengine_p.h>
#include <private/qqmljavascriptexpression_p.h>
#include <private/qqmljsast_p.h>
-#include "qv4qobjectwrapper_p.h"
-#include "qv4symbol_p.h"
-#include "qv4generatorobject_p.h"
-
-#include <QtCore/QDebug>
-#include <cassert>
-#include <cstdio>
-#include <stdlib.h>
+#include <private/qqmltypewrapper_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qv4argumentsobject_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4function_p.h>
+#include <private/qv4generatorobject_p.h>
+#include <private/qv4global_p.h>
+#include <private/qv4globalobject_p.h>
+#include <private/qv4jscall_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4math_p.h>
+#include <private/qv4object_p.h>
+#include <private/qv4qmlcontext_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4regexp_p.h>
+#include <private/qv4regexpobject_p.h>
+#include <private/qv4scopedvalue_p.h>
+#include <private/qv4stackframe_p.h>
+#include <private/qv4symbol_p.h>
#include <wtf/MathExtras.h>
+#include <QtCore/private/qlocale_tools_p.h>
+#include <QtCore/qdebug.h>
+
#ifdef QV4_COUNT_RUNTIME_FUNCTIONS
-# include <QtCore/QBuffer>
-# include <QtCore/QDebug>
+# include <QtCore/qbuffer.h>
#endif // QV4_COUNT_RUNTIME_FUNCTIONS
+#include <cassert>
+#include <cstdio>
+#include <stdlib.h>
+
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcCoercingTypeAssertion, "qt.qml.coercingTypeAssertion");
+
namespace QV4 {
#ifdef QV4_COUNT_RUNTIME_FUNCTIONS
@@ -179,7 +144,7 @@ struct RuntimeCounters::Data {
}
std::sort(lines.begin(), lines.end(), Line::less);
outs << lines.size() << " counters:" << endl;
- for (const Line &line : qAsConst(lines))
+ for (const Line &line : std::as_const(lines))
outs << qSetFieldWidth(10) << line.count << qSetFieldWidth(0)
<< " | " << line.func
<< " | " << pretty(line.tag1)
@@ -252,7 +217,7 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
*result = qdtoa(num, &decpt, &sign);
if (decpt <= ecma_shortest_low || decpt > ecma_shortest_high) {
- if (result->length() > 1)
+ if (result->size() > 1)
result->insert(1, dot);
result->append(QLatin1Char('e'));
if (decpt > 0)
@@ -260,10 +225,10 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
result->append(QString::number(decpt - 1));
} else if (decpt <= 0) {
result->prepend(QLatin1String("0.") + QString(-decpt, zero));
- } else if (decpt < result->length()) {
+ } else if (decpt < result->size()) {
result->insert(decpt, dot);
} else {
- result->append(QString(decpt - result->length(), zero));
+ result->append(QString(decpt - result->size(), zero));
}
if (sign && num)
@@ -319,7 +284,7 @@ ReturnedValue Runtime::Closure::call(ExecutionEngine *engine, int functionId)
QV4::Function *clos = engine->currentStackFrame->v4Function->executableCompilationUnit()
->runtimeFunctions[functionId];
Q_ASSERT(clos);
- ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context);
+ ExecutionContext *current = engine->currentContext();
if (clos->isGenerator())
return GeneratorFunction::create(current, clos)->asReturnedValue();
return FunctionObject::createScriptFunction(current, clos)->asReturnedValue();
@@ -329,7 +294,7 @@ Bool Runtime::DeleteProperty_NoThrow::call(ExecutionEngine *engine, const Value
{
Scope scope(engine);
ScopedObject o(scope, base.toObject(engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return Encode::undefined();
Q_ASSERT(o);
@@ -354,7 +319,7 @@ Bool Runtime::DeleteName_NoThrow::call(ExecutionEngine *engine, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).deleteProperty(name);
+ return engine->currentContext()->deleteProperty(name);
}
ReturnedValue Runtime::DeleteName::call(ExecutionEngine *engine, Function *function, int name)
@@ -368,7 +333,7 @@ ReturnedValue Runtime::DeleteName::call(ExecutionEngine *engine, Function *funct
}
}
-QV4::ReturnedValue Runtime::Instanceof::call(ExecutionEngine *engine, const Value &lval, const Value &rval)
+static QV4::ReturnedValue doInstanceof(ExecutionEngine *engine, const Value &lval, const Value &rval)
{
// 11.8.6, 5: rval must be an Object
const Object *rhs = rval.as<Object>();
@@ -384,13 +349,58 @@ QV4::ReturnedValue Runtime::Instanceof::call(ExecutionEngine *engine, const Valu
Scope scope(engine);
ScopedValue hasInstance(scope, rhs->get(engine->symbol_hasInstance()));
if (hasInstance->isUndefined())
- return rhs->instanceOf(lval);
+ return Encode(rhs->instanceOf(lval));
+
FunctionObject *fHasInstance = hasInstance->as<FunctionObject>();
if (!fHasInstance)
return engine->throwTypeError();
- ScopedValue result(scope, fHasInstance->call(&rval, &lval, 1));
- return Encode(result->toBoolean());
+ return Encode(fHasInstance->call(&rval, &lval, 1));
+}
+
+QV4::ReturnedValue Runtime::Instanceof::call(ExecutionEngine *engine, const Value &lval, const Value &rval)
+{
+ Scope scope(engine);
+ ScopedValue result(scope, doInstanceof(engine, lval, rval));
+ return scope.hasException() ? Encode::undefined() : Encode(result->toBoolean());
+}
+
+QV4::ReturnedValue Runtime::As::call(ExecutionEngine *engine, const Value &lval, const Value &rval)
+{
+ Scope scope(engine);
+ ScopedValue result(scope, doInstanceof(engine, lval, rval));
+
+ if (scope.hasException()) {
+ // "foo instanceof valueType" must not throw an exception.
+ // So this can only be an object type.
+ engine->catchException();
+ return Encode::null();
+ }
+
+ if (result->toBoolean())
+ return lval.asReturnedValue();
+ else if (result->isBoolean())
+ return Encode::null();
+
+ if (engine->callingQmlContext()->valueTypesAreAssertable())
+ return Encode::undefined();
+
+ // Try to convert the value type
+ Scoped<QQmlTypeWrapper> typeWrapper(scope, rval);
+ if (!typeWrapper)
+ return Encode::undefined();
+
+ result = coerce(engine, lval, typeWrapper->d()->type(), false);
+ if (result->isUndefined())
+ return Encode::undefined();
+
+ const auto *stackFrame = engine->currentStackFrame;
+ qCWarning(lcCoercingTypeAssertion).nospace().noquote()
+ << stackFrame->source() << ':' << stackFrame->lineNumber() << ':'
+ << " Coercing a value to " << typeWrapper->toQStringNoThrow()
+ << " using a type assertion. This behavior is deprecated."
+ << " Add 'pragma ValueTypeBehavior: Assertable' to prevent it.";
+ return result->asReturnedValue();
}
QV4::ReturnedValue Runtime::In::call(ExecutionEngine *engine, const Value &left, const Value &right)
@@ -408,7 +418,16 @@ QV4::ReturnedValue Runtime::In::call(ExecutionEngine *engine, const Value &left,
double RuntimeHelpers::stringToNumber(const QString &string)
{
- const QStringRef s = QStringRef(&string).trimmed();
+ // The actual maximum valid length is certainly shorter, but due to the sheer number of
+ // different number formatting variants, we rather err on the side of caution here.
+ // For example, you can have up to 772 valid decimal digits left of the dot, as stated in the
+ // libdoubleconversion sources. The same maximum value would be represented by roughly 3.5 times
+ // as many binary digits.
+ const int excessiveLength = 16 * 1024;
+ if (string.size() > excessiveLength)
+ return qQNaN();
+
+ const QStringView s = QStringView(string).trimmed();
if (s.startsWith(QLatin1Char('0'))) {
int base = -1;
if (s.startsWith(QLatin1String("0x")) || s.startsWith(QLatin1String("0X")))
@@ -506,6 +525,8 @@ ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const
ScopedValue conv(scope, object->get(meth1));
if (FunctionObject *o = conv->as<FunctionObject>()) {
result = o->call(object, nullptr, 0);
+ if (engine->hasException)
+ return Encode::undefined();
if (result->isPrimitive())
return result->asReturnedValue();
}
@@ -516,6 +537,8 @@ ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const
conv = object->get(meth2);
if (FunctionObject *o = conv->as<FunctionObject>()) {
result = o->call(object, nullptr, 0);
+ if (engine->hasException)
+ return Encode::undefined();
if (result->isPrimitive())
return result->asReturnedValue();
}
@@ -577,7 +600,7 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, Value val
goto redo;
}
case Value::Integer_Type:
- return RuntimeHelpers::stringFromNumber(engine, value.int_32());
+ return engine->newString(QString::number(value.int_32()));
default: // double
return RuntimeHelpers::stringFromNumber(engine, value.doubleValue());
} // switch
@@ -651,7 +674,7 @@ static Q_NEVER_INLINE ReturnedValue getElementIntFallback(ExecutionEngine *engin
ScopedObject o(scope, object);
if (!o) {
if (const String *str = object.as<String>()) {
- if (idx >= (uint)str->toQString().length()) {
+ if (idx >= (uint)str->toQString().size()) {
return Encode::undefined();
}
const QString s = str->toQString().mid(idx, 1);
@@ -789,8 +812,10 @@ ReturnedValue Runtime::GetIterator::call(ExecutionEngine *engine, const Value &i
ScopedFunctionObject f(scope, o->get(engine->symbol_iterator()));
if (!f)
return engine->throwTypeError();
- JSCallData cData(scope, 0, nullptr, o);
+ JSCallData cData(o, nullptr, 0);
ScopedObject it(scope, f->call(cData));
+ if (engine->hasException)
+ return Encode::undefined();
if (!it)
return engine->throwTypeError();
return it->asReturnedValue();
@@ -810,7 +835,7 @@ ReturnedValue Runtime::IteratorNext::call(ExecutionEngine *engine, const Value &
engine->throwTypeError();
return Encode(true);
}
- JSCallData cData(scope, 0, nullptr, &iterator);
+ JSCallData cData(&iterator, nullptr, 0);
ScopedObject o(scope, f->call(cData));
if (scope.hasException())
return Encode(true);
@@ -853,6 +878,8 @@ ReturnedValue Runtime::IteratorNextForYieldStar::call(ExecutionEngine *engine, c
engine->hasException = false;
ScopedValue ret(scope, static_cast<const Object &>(iterator).get(engine->id_return()));
+ if (engine->hasException)
+ return Encode(true);
if (ret->isUndefined()) {
// propagate return()
return Encode::undefined();
@@ -867,14 +894,13 @@ ReturnedValue Runtime::IteratorNextForYieldStar::call(ExecutionEngine *engine, c
ScopedValue t(scope, static_cast<const Object &>(iterator).get(engine->id_throw()));
if (engine->hasException)
- return Encode::undefined();
+ return Encode(true);
if (t->isUndefined()) {
// no throw method on the iterator
- ScopedValue done(scope, Encode(false));
- IteratorClose::call(engine, iterator, done);
- if (engine->hasException)
- return Encode::undefined();
- return engine->throwTypeError();
+ IteratorClose::call(engine, iterator);
+ if (!engine->hasException)
+ engine->throwTypeError();
+ return Encode(true);
}
f = t->as<FunctionObject>();
arg = exceptionValue;
@@ -885,14 +911,18 @@ ReturnedValue Runtime::IteratorNextForYieldStar::call(ExecutionEngine *engine, c
f = next->as<FunctionObject>();
}
- if (!f)
- return engine->throwTypeError();
+ if (!f) {
+ engine->throwTypeError();
+ return Encode(true);
+ }
ScopedObject o(scope, f->call(&iterator, arg, 1));
if (scope.hasException())
return Encode(true);
- if (!o)
- return engine->throwTypeError();
+ if (!o) {
+ engine->throwTypeError();
+ return Encode(true);
+ }
ScopedValue d(scope, o->get(engine->id_done()));
if (scope.hasException())
@@ -900,18 +930,15 @@ ReturnedValue Runtime::IteratorNextForYieldStar::call(ExecutionEngine *engine, c
bool done = d->toBoolean();
if (done) {
*object = o->get(engine->id_value());
- return returnCalled ? Encode::undefined() : Encode(true);
+ return (returnCalled && !engine->hasException) ? Encode::undefined() : Encode(true);
}
*object = o;
return Encode(false);
}
-ReturnedValue Runtime::IteratorClose::call(ExecutionEngine *engine, const Value &iterator, const Value &done)
+ReturnedValue Runtime::IteratorClose::call(ExecutionEngine *engine, const Value &iterator)
{
Q_ASSERT(iterator.isObject());
- Q_ASSERT(done.isBoolean());
- if (done.booleanValue())
- return Encode::undefined();
Scope scope(engine);
ScopedValue e(scope);
@@ -972,7 +999,7 @@ void Runtime::StoreNameSloppy::call(ExecutionEngine *engine, int nameIndex, cons
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- ExecutionContext::Error e = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).setProperty(name, value);
+ ExecutionContext::Error e = engine->currentContext()->setProperty(name, value);
if (e == ExecutionContext::RangeError)
engine->globalObject->put(name, value);
@@ -982,7 +1009,7 @@ void Runtime::StoreNameStrict::call(ExecutionEngine *engine, int nameIndex, cons
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- ExecutionContext::Error e = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).setProperty(name, value);
+ ExecutionContext::Error e = engine->currentContext()->setProperty(name, value);
if (e == ExecutionContext::TypeError)
engine->throwTypeError();
else if (e == ExecutionContext::RangeError)
@@ -1013,32 +1040,50 @@ ReturnedValue Runtime::LoadName::call(ExecutionEngine *engine, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name);
+ return engine->currentContext()->getProperty(name);
}
static Object *getSuperBase(Scope &scope)
{
- if (scope.engine->currentStackFrame->jsFrame->thisObject.isEmpty()) {
- scope.engine->throwReferenceError(QStringLiteral("Missing call to super()."), QString(), 0, 0);
- return nullptr;
+ Scoped<JavaScriptFunctionObject> f(scope);
+ ScopedObject homeObject(scope);
+ if (scope.engine->currentStackFrame->isJSTypesFrame()) {
+ JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>(
+ scope.engine->currentStackFrame);
+
+ if (frame->jsFrame->thisObject.isEmpty()) {
+ scope.engine->throwReferenceError(
+ QStringLiteral("Missing call to super()."), QString(), 0, 0);
+ return nullptr;
+ }
+
+ f = Value::fromStaticValue(frame->jsFrame->function);
+ homeObject = f->getHomeObject();
+ } else {
+ Q_ASSERT(scope.engine->currentStackFrame->isMetaTypesFrame());
+ MetaTypesStackFrame *frame = static_cast<MetaTypesStackFrame *>(
+ scope.engine->currentStackFrame);
+ if (frame->thisObject() == nullptr) {
+ scope.engine->throwReferenceError(
+ QStringLiteral("Missing call to super()."), QString(), 0, 0);
+ return nullptr;
+ }
}
- ScopedFunctionObject f(
- scope, Value::fromStaticValue(scope.engine->currentStackFrame->jsFrame->function));
- ScopedObject homeObject(scope, f->getHomeObject());
if (!homeObject) {
- ScopedContext ctx(scope, static_cast<ExecutionContext *>(&scope.engine->currentStackFrame->jsFrame->context));
+ ScopedContext ctx(scope, scope.engine->currentContext());
Q_ASSERT(ctx);
while (ctx) {
if (CallContext *c = ctx->asCallContext()) {
f = c->d()->function;
QV4::Function *fn = f->function();
- if (fn && !fn->isArrowFunction() && !fn->isEval)
+ if (fn && !fn->isArrowFunction() && fn->kind != Function::Eval)
break;
}
ctx = ctx->d()->outer;
}
- homeObject = f->getHomeObject();
+ if (f)
+ homeObject = f->getHomeObject();
}
if (!homeObject) {
scope.engine->throwTypeError();
@@ -1062,8 +1107,18 @@ ReturnedValue Runtime::LoadSuperProperty::call(ExecutionEngine *engine, const Va
ScopedPropertyKey key(scope, property.toPropertyKey(engine));
if (engine->hasException)
return Encode::undefined();
- return base->get(
- key, &(engine->currentStackFrame->jsFrame->thisObject.asValue<Value>()));
+
+ if (scope.engine->currentStackFrame->isJSTypesFrame()) {
+ JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>(
+ scope.engine->currentStackFrame);
+ return base->get(key, &(frame->jsFrame->thisObject.asValue<Value>()));
+ } else {
+ Q_ASSERT(scope.engine->currentStackFrame->isMetaTypesFrame());
+ MetaTypesStackFrame *frame = static_cast<MetaTypesStackFrame *>(
+ scope.engine->currentStackFrame);
+ Scoped<QObjectWrapper> wrapper(scope, QObjectWrapper::wrap(engine, frame->thisObject()));
+ return base->get(key, wrapper);
+ }
}
void Runtime::StoreSuperProperty::call(ExecutionEngine *engine, const Value &property, const Value &value)
@@ -1075,8 +1130,20 @@ void Runtime::StoreSuperProperty::call(ExecutionEngine *engine, const Value &pro
ScopedPropertyKey key(scope, property.toPropertyKey(engine));
if (engine->hasException)
return;
- bool result = base->put(
- key, value, &(engine->currentStackFrame->jsFrame->thisObject.asValue<Value>()));
+
+ bool result;
+ if (scope.engine->currentStackFrame->isJSTypesFrame()) {
+ JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>(
+ scope.engine->currentStackFrame);
+ result = base->put(key, value, &(frame->jsFrame->thisObject.asValue<Value>()));
+ } else {
+ Q_ASSERT(scope.engine->currentStackFrame->isMetaTypesFrame());
+ MetaTypesStackFrame *frame = static_cast<MetaTypesStackFrame *>(
+ scope.engine->currentStackFrame);
+ Scoped<QObjectWrapper> wrapper(scope, QObjectWrapper::wrap(engine, frame->thisObject()));
+ result = base->put(key, value, wrapper);
+ }
+
if (!result && engine->currentStackFrame->v4Function->isStrict())
engine->throwTypeError();
}
@@ -1116,14 +1183,28 @@ void Runtime::SetLookupStrict::call(Function *f, const Value &base, int index, c
ReturnedValue Runtime::LoadSuperConstructor::call(ExecutionEngine *engine, const Value &t)
{
- if (engine->currentStackFrame->thisObject() != Value::emptyValue().asReturnedValue()) {
- return engine->throwReferenceError(QStringLiteral("super() already called."), QString(), 0, 0); // ### fix line number
+ if (engine->currentStackFrame->isJSTypesFrame()) {
+ JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>(engine->currentStackFrame);
+ if (frame->thisObject() != Value::emptyValue().asReturnedValue()) {
+ // ### TODO: fix line number
+ return engine->throwReferenceError(
+ QStringLiteral("super() already called."), QString(), 0, 0);
+ }
+ } else {
+ Q_ASSERT(engine->currentStackFrame->isMetaTypesFrame());
+ MetaTypesStackFrame *frame = static_cast<MetaTypesStackFrame *>(engine->currentStackFrame);
+ if (frame->thisObject() != nullptr) {
+ // ### TODO: fix line number
+ return engine->throwReferenceError(
+ QStringLiteral("super() already called."), QString(), 0, 0);
+ }
}
+
const FunctionObject *f = t.as<FunctionObject>();
if (!f)
return engine->throwTypeError();
Heap::Object *c = static_cast<const Object &>(t).getPrototypeOf();
- if (!c->vtable()->isFunctionObject || !static_cast<Heap::FunctionObject *>(c)->isConstructor())
+ if (!c->vtable()->callAsConstructor)
return engine->throwTypeError();
return c->asReturnedValue();
}
@@ -1332,7 +1413,8 @@ ReturnedValue Runtime::CallGlobalLookup::call(ExecutionEngine *engine, uint inde
engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
}
- return static_cast<FunctionObject &>(function).call(&thisObject, argv, argc);
+ return checkedResult(engine, static_cast<FunctionObject &>(function).call(
+ &thisObject, argv, argc));
}
ReturnedValue Runtime::CallQmlContextPropertyLookup::call(ExecutionEngine *engine, uint index,
@@ -1347,7 +1429,8 @@ ReturnedValue Runtime::CallQmlContextPropertyLookup::call(ExecutionEngine *engin
engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
}
- return static_cast<FunctionObject &>(function).call(thisObject, argv, argc);
+ return checkedResult(engine, static_cast<FunctionObject &>(function).call(
+ thisObject, argv, argc));
}
ReturnedValue Runtime::CallPossiblyDirectEval::call(ExecutionEngine *engine, Value *argv, int argc)
@@ -1355,8 +1438,8 @@ ReturnedValue Runtime::CallPossiblyDirectEval::call(ExecutionEngine *engine, Val
Scope scope(engine);
ScopedValue thisObject(scope);
- ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context);
- ScopedFunctionObject function(scope, ctx.getPropertyAndBase(engine->id_eval(), thisObject));
+ ScopedFunctionObject function(
+ scope, engine->currentContext()->getPropertyAndBase(engine->id_eval(), thisObject));
if (engine->hasException)
return Encode::undefined();
@@ -1366,7 +1449,7 @@ ReturnedValue Runtime::CallPossiblyDirectEval::call(ExecutionEngine *engine, Val
if (function->d() == engine->evalFunction()->d())
return static_cast<EvalFunction *>(function.getPointer())->evalCall(thisObject, argv, argc, true);
- return function->call(thisObject, argv, argc);
+ return checkedResult(engine, function->call(thisObject, argv, argc));
}
ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Value *argv, int argc)
@@ -1375,8 +1458,7 @@ ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Va
ScopedValue thisObject(scope);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context);
- ScopedFunctionObject f(scope, ctx.getPropertyAndBase(name, thisObject));
+ ScopedFunctionObject f(scope, engine->currentContext()->getPropertyAndBase(name, thisObject));
if (engine->hasException)
return Encode::undefined();
@@ -1386,7 +1468,7 @@ ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Va
->runtimeStrings[nameIndex]->toQString());
}
- return f->call(thisObject, argv, argc);
+ return checkedResult(engine, f->call(thisObject, argv, argc));
}
ReturnedValue Runtime::CallProperty::call(ExecutionEngine *engine, const Value &baseRef, int nameIndex, Value *argv, int argc)
@@ -1428,7 +1510,7 @@ ReturnedValue Runtime::CallProperty::call(ExecutionEngine *engine, const Value &
return engine->throwTypeError(error);
}
- return f->call(base, argv, argc);
+ return checkedResult(engine, f->call(base, argv, argc));
}
ReturnedValue Runtime::CallPropertyLookup::call(ExecutionEngine *engine, const Value &base, uint index, Value *argv, int argc)
@@ -1437,28 +1519,17 @@ ReturnedValue Runtime::CallPropertyLookup::call(ExecutionEngine *engine, const V
// ok to have the value on the stack here
Value f = Value::fromReturnedValue(l->getter(l, engine, base));
- if (!f.isFunctionObject())
- return engine->throwTypeError();
-
- return static_cast<FunctionObject &>(f).call(&base, argv, argc);
-}
+ if (Q_LIKELY(f.isFunctionObject()))
+ return checkedResult(engine, static_cast<FunctionObject &>(f).call(&base, argv, argc));
-ReturnedValue Runtime::CallElement::call(ExecutionEngine *engine, const Value &baseRef, const Value &index, Value *argv, int argc)
-{
- const Value *base = &baseRef;
- Scope scope(engine);
- ScopedValue thisObject(scope, base->toObject(engine));
- base = thisObject;
+ if (QmlSignalHandler *handler = f.as<QmlSignalHandler>())
+ return checkedResult(engine, handler->call(&base, argv, argc));
- ScopedPropertyKey str(scope, index.toPropertyKey(engine));
- if (engine->hasException)
- return Encode::undefined();
-
- ScopedFunctionObject f(scope, static_cast<const Object *>(base)->get(str));
- if (!f)
- return engine->throwTypeError();
-
- return f->call(base, argv, argc);
+ const QString message = QStringLiteral("Property '%1' of object %2 is not a function")
+ .arg(engine->currentStackFrame->v4Function->compilationUnit
+ ->runtimeStrings[l->nameIndex]->toQString())
+ .arg(base.toQStringNoThrow());
+ return engine->throwTypeError(message);
}
ReturnedValue Runtime::CallValue::call(ExecutionEngine *engine, const Value &func, Value *argv, int argc)
@@ -1466,7 +1537,8 @@ ReturnedValue Runtime::CallValue::call(ExecutionEngine *engine, const Value &fun
if (!func.isFunctionObject())
return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
Value undef = Value::undefinedValue();
- return static_cast<const FunctionObject &>(func).call(&undef, argv, argc);
+ return checkedResult(engine, static_cast<const FunctionObject &>(func).call(
+ &undef, argv, argc));
}
ReturnedValue Runtime::CallWithReceiver::call(ExecutionEngine *engine, const Value &func,
@@ -1474,7 +1546,8 @@ ReturnedValue Runtime::CallWithReceiver::call(ExecutionEngine *engine, const Val
{
if (!func.isFunctionObject())
return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
- return static_cast<const FunctionObject &>(func).call(&thisObject, argv, argc);
+ return checkedResult(engine, static_cast<const FunctionObject &>(func).call(
+ &thisObject, argv, argc));
}
struct CallArgs {
@@ -1501,16 +1574,21 @@ static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc)
// spread element
++i;
it = Runtime::GetIterator::call(scope.engine, argv[i], /* ForInIterator */ 1);
- if (scope.engine->hasException)
+ if (scope.hasException())
return { nullptr, 0 };
while (1) {
done = Runtime::IteratorNext::call(scope.engine, it, v);
- if (scope.engine->hasException)
+ if (scope.hasException())
return { nullptr, 0 };
Q_ASSERT(done->isBoolean());
if (done->booleanValue())
break;
++argCount;
+ constexpr auto safetyMargin = 100; // leave some space on the stack for actual work with the elements
+ if (qint64(scope.engine->jsStackLimit - scope.engine->jsStackTop) < safetyMargin) {
+ scope.engine->throwRangeError(QLatin1String("Too many elements in array to use it with the spread operator"));
+ return { nullptr, 0 };
+ }
v = scope.alloc<Scope::Uninitialized>();
}
}
@@ -1528,7 +1606,8 @@ ReturnedValue Runtime::CallWithSpread::call(ExecutionEngine *engine, const Value
if (engine->hasException)
return Encode::undefined();
- return static_cast<const FunctionObject &>(function).call(&thisObject, arguments.argv, arguments.argc);
+ return checkedResult(engine, static_cast<const FunctionObject &>(function).call(
+ &thisObject, arguments.argv, arguments.argc));
}
ReturnedValue Runtime::Construct::call(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc)
@@ -1552,7 +1631,7 @@ ReturnedValue Runtime::ConstructWithSpread::call(ExecutionEngine *engine, const
return static_cast<const FunctionObject &>(function).callAsConstructor(arguments.argv, arguments.argc, &newTarget);
}
-ReturnedValue Runtime::TailCall::call(CppStackFrame *frame, ExecutionEngine *engine)
+ReturnedValue Runtime::TailCall::call(JSTypesStackFrame *frame, ExecutionEngine *engine)
{
// IMPORTANT! The JIT assumes that this method has the same amount (or less) arguments than
// the jitted function, so it can safely do a tail call.
@@ -1564,22 +1643,26 @@ ReturnedValue Runtime::TailCall::call(CppStackFrame *frame, ExecutionEngine *eng
int argc = tos[StackOffsets::tailCall_argc].int_32();
Q_ASSERT(argc >= 0);
- if (!function.isFunctionObject())
+ const JavaScriptFunctionObject *jsfo = function.as<JavaScriptFunctionObject>();
+ if (!jsfo) {
+ if (const FunctionObject *fo = function.as<FunctionObject>())
+ return checkedResult(engine, fo->call(&thisObject, argv, argc));
return engine->throwTypeError();
+ }
- const FunctionObject &fo = static_cast<const FunctionObject &>(function);
- if (!frame->callerCanHandleTailCall || !fo.canBeTailCalled() || engine->debugger()
- || unsigned(argc) > fo.formalParameterCount()) {
+ if (!frame->callerCanHandleTailCall() || !jsfo->canBeTailCalled() || engine->debugger()
+ || unsigned(argc) > jsfo->formalParameterCount()) {
// Cannot tailcall, do a normal call:
- return fo.call(&thisObject, argv, argc);
+ return checkedResult(engine, jsfo->call(&thisObject, argv, argc));
}
- memcpy(frame->jsFrame->args, argv, argc * sizeof(Value));
- frame->init(engine, fo.function(), frame->jsFrame->argValues<Value>(), argc,
- frame->callerCanHandleTailCall);
- frame->setupJSFrame(frame->savedStackTop, fo, fo.scope(), thisObject, Primitive::undefinedValue());
- engine->jsStackTop = frame->savedStackTop + frame->requiredJSStackFrameSize();
- frame->pendingTailCall = true;
+ memmove(frame->jsFrame->args, argv, argc * sizeof(Value));
+ frame->init(jsfo->function(), frame->jsFrame->argValues<Value>(), argc,
+ frame->callerCanHandleTailCall());
+ frame->setupJSFrame(frame->framePointer(), *jsfo, jsfo->scope(), thisObject,
+ Primitive::undefinedValue());
+ engine->jsStackTop = frame->framePointer() + frame->requiredJSStackFrameSize();
+ frame->setPendingTailCall(true);
return Encode::undefined();
}
@@ -1624,20 +1707,21 @@ QV4::ReturnedValue Runtime::TypeofName::call(ExecutionEngine *engine, int nameIn
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- ScopedValue prop(scope, static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name));
+ ScopedValue prop(scope, engine->currentContext()->getProperty(name));
// typeof doesn't throw. clear any possible exception
scope.engine->hasException = false;
return TypeofValue::call(engine, prop);
}
-void Runtime::PushCallContext::call(CppStackFrame *frame)
+void Runtime::PushCallContext::call(JSTypesStackFrame *frame)
{
frame->jsFrame->context = ExecutionContext::newCallContext(frame)->asReturnedValue();
}
ReturnedValue Runtime::PushWithContext::call(ExecutionEngine *engine, const Value &acc)
{
- CallData *jsFrame = engine->currentStackFrame->jsFrame;
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
+ CallData *jsFrame = static_cast<JSTypesStackFrame *>(engine->currentStackFrame)->jsFrame;
Value &newAcc = jsFrame->accumulator.asValue<Value>();
newAcc = Value::fromHeapObject(acc.toObject(engine));
if (!engine->hasException) {
@@ -1652,18 +1736,23 @@ ReturnedValue Runtime::PushWithContext::call(ExecutionEngine *engine, const Valu
void Runtime::PushCatchContext::call(ExecutionEngine *engine, int blockIndex, int exceptionVarNameIndex)
{
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
auto name = engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[exceptionVarNameIndex];
- engine->currentStackFrame->jsFrame->context = ExecutionContext::newCatchContext(engine->currentStackFrame, blockIndex, name)->asReturnedValue();
+ static_cast<JSTypesStackFrame *>(engine->currentStackFrame)->jsFrame->context
+ = ExecutionContext::newCatchContext(engine->currentStackFrame, blockIndex, name)->asReturnedValue();
}
void Runtime::PushBlockContext::call(ExecutionEngine *engine, int index)
{
- engine->currentStackFrame->jsFrame->context = ExecutionContext::newBlockContext(engine->currentStackFrame, index)->asReturnedValue();
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
+ static_cast<JSTypesStackFrame *>(engine->currentStackFrame)->jsFrame->context
+ = ExecutionContext::newBlockContext(engine->currentStackFrame, index)->asReturnedValue();
}
void Runtime::CloneBlockContext::call(ExecutionEngine *engine)
{
- auto frame = engine->currentStackFrame;
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
+ auto frame = static_cast<JSTypesStackFrame *>(engine->currentStackFrame);
auto context = static_cast<Heap::CallContext *>(
Value::fromStaticValue(frame->jsFrame->context).m());
frame->jsFrame->context =
@@ -1672,18 +1761,20 @@ void Runtime::CloneBlockContext::call(ExecutionEngine *engine)
void Runtime::PushScriptContext::call(ExecutionEngine *engine, int index)
{
- Q_ASSERT(engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_GlobalContext ||
- engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_QmlContext);
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
+ Q_ASSERT(engine->currentContext()->d()->type == Heap::ExecutionContext::Type_GlobalContext ||
+ engine->currentContext()->d()->type == Heap::ExecutionContext::Type_QmlContext);
ReturnedValue c = ExecutionContext::newBlockContext(engine->currentStackFrame, index)->asReturnedValue();
engine->setScriptContext(c);
- engine->currentStackFrame->jsFrame->context = c;
+ static_cast<JSTypesStackFrame *>(engine->currentStackFrame)->jsFrame->context = c;
}
void Runtime::PopScriptContext::call(ExecutionEngine *engine)
{
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
ReturnedValue root = engine->rootContext()->asReturnedValue();
engine->setScriptContext(root);
- engine->currentStackFrame->jsFrame->context = root;
+ static_cast<JSTypesStackFrame *>(engine->currentStackFrame)->jsFrame->context = root;
}
void Runtime::ThrowReferenceError::call(ExecutionEngine *engine, int nameIndex)
@@ -1715,7 +1806,7 @@ void Runtime::DeclareVar::call(ExecutionEngine *engine, Bool deletable, int name
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).createMutableBinding(name, deletable);
+ engine->currentContext()->createMutableBinding(name, deletable);
}
ReturnedValue Runtime::ArrayLiteral::call(ExecutionEngine *engine, Value *values, uint length)
@@ -1768,7 +1859,7 @@ ReturnedValue Runtime::ObjectLiteral::call(ExecutionEngine *engine, int classId,
arg = ObjectLiteralArgument::Value;
fnName = name->asFunctionName(engine, prefix);
- ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context);
+ ExecutionContext *current = engine->currentContext();
if (clos->isGenerator())
value = MemberGeneratorFunction::create(current, clos, o, fnName)->asReturnedValue();
else
@@ -1826,7 +1917,7 @@ ReturnedValue Runtime::CreateClass::call(ExecutionEngine *engine, int classIndex
ScopedObject proto(scope, engine->newObject());
proto->setPrototypeUnchecked(protoParent);
- ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context);
+ ExecutionContext *current = engine->currentContext();
ScopedFunctionObject constructor(scope);
QV4::Function *f = cls->constructorFunction != UINT_MAX ? unit->runtimeFunctions[cls->constructorFunction] : nullptr;
@@ -1910,14 +2001,18 @@ QV4::ReturnedValue Runtime::CreateMappedArgumentsObject::call(ExecutionEngine *e
QV4::ReturnedValue Runtime::CreateUnmappedArgumentsObject::call(ExecutionEngine *engine)
{
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_StrictArgumentsObject);
- return engine->memoryManager->allocObject<StrictArgumentsObject>(ic, engine->currentStackFrame)->asReturnedValue();
+ return engine->memoryManager->allocObject<StrictArgumentsObject>(
+ ic, static_cast<JSTypesStackFrame *>(engine->currentStackFrame))->asReturnedValue();
}
QV4::ReturnedValue Runtime::CreateRestParameter::call(ExecutionEngine *engine, int argIndex)
{
- const Value *values = engine->currentStackFrame->originalArguments + argIndex;
- int nValues = engine->currentStackFrame->originalArgumentsCount - argIndex;
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
+ JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>(engine->currentStackFrame);
+ const Value *values = frame->argv() + argIndex;
+ int nValues = frame->argc() - argIndex;
if (nValues <= 0)
return engine->newArrayObject(0)->asReturnedValue();
return engine->newArrayObject(values, nValues)->asReturnedValue();
@@ -2049,9 +2144,7 @@ ReturnedValue Runtime::Exp::call(const Value &base, const Value &exp)
{
double b = base.toNumber();
double e = exp.toNumber();
- if (qt_is_inf(e) && (b == 1 || b == -1))
- return Encode(qt_qnan());
- return Encode(pow(b,e));
+ return Encode(QQmlPrivate::jsExponentiate(b, e));
}
ReturnedValue Runtime::BitAnd::call(const Value &left, const Value &right)
@@ -2173,35 +2266,23 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
Value *lhsGuard = nullptr;
Value *rhsGuard = nullptr;
- redo:
+ redo:
if (lhs.asReturnedValue() == rhs.asReturnedValue())
return !lhs.isNaN();
- int lt = lhs.quickType();
- int rt = rhs.quickType();
- if (rt < lt) {
- qSwap(lhs, rhs);
- qSwap(lt, rt);
- }
+ quint32 lt = lhs.quickType();
+ quint32 rt = rhs.quickType();
- switch (lt) {
- case QV4::Value::QT_ManagedOrUndefined:
+ // LHS: Check if managed
+ if ((lt & (Value::ManagedMask >> Value::Tag_Shift)) == 0) {
if (lhs.isUndefined())
return rhs.isNullOrUndefined();
- Q_FALLTHROUGH();
- case QV4::Value::QT_ManagedOrUndefined1:
- case QV4::Value::QT_ManagedOrUndefined2:
- case QV4::Value::QT_ManagedOrUndefined3:
- // LHS: Managed
- switch (rt) {
- case QV4::Value::QT_ManagedOrUndefined:
+
+ // RHS: Check if managed
+ if ((rt & (Value::ManagedMask >> Value::Tag_Shift)) == 0) {
if (rhs.isUndefined())
return false;
- Q_FALLTHROUGH();
- case QV4::Value::QT_ManagedOrUndefined1:
- case QV4::Value::QT_ManagedOrUndefined2:
- case QV4::Value::QT_ManagedOrUndefined3: {
- // RHS: Managed
+
Heap::Base *l = lhs.m();
Heap::Base *r = rhs.m();
Q_ASSERT(l);
@@ -2211,15 +2292,18 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
if (l->internalClass->vtable->isStringOrSymbol) {
scope.set(&rhsGuard, RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(rhs), PREFERREDTYPE_HINT), r->internalClass->engine);
rhs = rhsGuard->asReturnedValue();
- break;
+ goto redo;
} else {
Q_ASSERT(r->internalClass->vtable->isStringOrSymbol);
scope.set(&lhsGuard, RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT), l->internalClass->engine);
lhs = lhsGuard->asReturnedValue();
- break;
+ goto redo;
}
return false;
}
+
+lhs_managed_and_rhs_not:
+ switch (rt) {
case QV4::Value::QT_Empty:
Q_UNREACHABLE();
case QV4::Value::QT_Null:
@@ -2227,7 +2311,7 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
case QV4::Value::QT_Bool:
case QV4::Value::QT_Int:
rhs = Value::fromDouble(rhs.int_32());
- // fall through
+ Q_FALLTHROUGH();
default: // double
if (lhs.m()->internalClass->vtable->isStringOrSymbol) {
return lhs.m()->internalClass->vtable->isString ? (RuntimeHelpers::toNumber(lhs) == rhs.doubleValue()) : false;
@@ -2237,6 +2321,15 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
}
}
goto redo;
+ } else if ((rt & (Value::ManagedMask >> Value::Tag_Shift)) == 0) {
+ if (rhs.isUndefined())
+ return lhs.isNull(); // Can't be undefined
+ qSwap(lhs, rhs);
+ qSwap(lt, rt);
+ goto lhs_managed_and_rhs_not;
+ }
+
+ switch (lt) {
case QV4::Value::QT_Empty:
Q_UNREACHABLE();
case QV4::Value::QT_Null:
@@ -2244,13 +2337,10 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
case QV4::Value::QT_Bool:
case QV4::Value::QT_Int:
switch (rt) {
- case QV4::Value::QT_ManagedOrUndefined:
- case QV4::Value::QT_ManagedOrUndefined1:
- case QV4::Value::QT_ManagedOrUndefined2:
- case QV4::Value::QT_ManagedOrUndefined3:
case QV4::Value::QT_Empty:
- case QV4::Value::QT_Null:
Q_UNREACHABLE();
+ case QV4::Value::QT_Null:
+ return false;
case QV4::Value::QT_Bool:
case QV4::Value::QT_Int:
return lhs.int_32() == rhs.int_32();
@@ -2258,8 +2348,17 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
return lhs.int_32() == rhs.doubleValue();
}
default: // double
- Q_ASSERT(rhs.isDouble());
- return lhs.doubleValue() == rhs.doubleValue();
+ switch (rt) {
+ case QV4::Value::QT_Empty:
+ Q_UNREACHABLE();
+ case QV4::Value::QT_Null:
+ return false;
+ case QV4::Value::QT_Bool:
+ case QV4::Value::QT_Int:
+ return lhs.doubleValue() == rhs.int_32();
+ default: // double
+ return lhs.doubleValue() == rhs.doubleValue();
+ }
}
}
@@ -2331,7 +2430,6 @@ QHash<const void *, const char *> Runtime::symbolTable()
{symbol<CallName>(), "CallName" },
{symbol<CallProperty>(), "CallProperty" },
{symbol<CallPropertyLookup>(), "CallPropertyLookup" },
- {symbol<CallElement>(), "CallElement" },
{symbol<CallValue>(), "CallValue" },
{symbol<CallWithReceiver>(), "CallWithReceiver" },
{symbol<CallPossiblyDirectEval>(), "CallPossiblyDirectEval" },
@@ -2401,6 +2499,7 @@ QHash<const void *, const char *> Runtime::symbolTable()
{symbol<UMinus>(), "UMinus" },
{symbol<Instanceof>(), "Instanceof" },
+ {symbol<As>(), "As" },
{symbol<In>(), "In" },
{symbol<Add>(), "Add" },
{symbol<Sub>(), "Sub" },