Implement most of QJSEngine against V4
authorLars Knoll <lars.knoll@digia.com>
Thu, 18 Apr 2013 10:41:59 +0000 (12:41 +0200)
committerSimon Hausmann <simon.hausmann@digia.com>
Fri, 19 Apr 2013 10:00:55 +0000 (12:00 +0200)
Also do various fixes in other places, so more of
the QJS* autotests pass

Change-Id: I39662a2ca1441f778595d260860375c5c628bf8e
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
src/qml/qml/v4vm/qv4runtime.cpp
src/qml/qml/v4vm/qv4runtime_p.h
src/qml/qml/v4vm/qv4v8.cpp
src/qml/qml/v8/qjsengine.cpp
src/qml/qml/v8/qjsvalue.cpp
src/qml/qml/v8/qjsvalue_p.h
src/qml/qml/v8/qjsvalueiterator.cpp
src/qml/qml/v8/script.pri
tests/auto/qml/qjsvalue/tst_qjsvalue.cpp

index fd22db4..fd1db0e 100644 (file)
@@ -68,7 +68,7 @@
 namespace QQmlJS {
 namespace VM {
 
-QString numberToString(double num, int radix = 10)
+QString __qmljs_numberToString(double num, int radix)
 {
     if (std::isnan(num)) {
         return QStringLiteral("NaN");
@@ -457,7 +457,7 @@ double __qmljs_string_to_number(const QString &string)
 
 Value __qmljs_string_from_number(ExecutionContext *ctx, double number)
 {
-    String *string = ctx->engine->newString(numberToString(number, 10));
+    String *string = ctx->engine->newString(__qmljs_numberToString(number, 10));
     return Value::fromString(string);
 }
 
index 1672573..b4cd826 100644 (file)
@@ -184,6 +184,7 @@ Bool __qmljs_to_boolean(const Value &value);
 double __qmljs_to_number(const Value &value);
 Value __qmljs_to_string(const Value &value, ExecutionContext *ctx);
 Q_QML_EXPORT String *__qmljs_convert_to_string(ExecutionContext *ctx, const Value &value);
+QString __qmljs_numberToString(double num, int radix = 10);
 Value __qmljs_to_object(ExecutionContext *ctx, const Value &value);
 Object *__qmljs_convert_to_object(ExecutionContext *ctx, const Value &value);
 
index 2b63458..6e55e77 100644 (file)
@@ -969,7 +969,8 @@ Local<Value> Object::GetPrototype()
 {
     Local<Value> result;
     QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
-    assert(o);
+    if (!o)
+        return Local<Value>();
     return Local<Value>::New(Value::fromVmValue(QQmlJS::VM::Value::fromObject(o->prototype)));
 }
 
@@ -979,7 +980,9 @@ bool Object::SetPrototype(Handle<Value> prototype)
     if (!p)
         return false;
     QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
-    assert(o);
+    if (!o)
+        return false;
+
     o->prototype = p;
     return true;
 }
index 76bb6e8..99279fc 100644 (file)
 #include "qscriptisolate_p.h"
 #include "qv8engine_p.h"
 
+#include "private/qv4engine_p.h"
+#include "private/qv4mm_p.h"
+#include "private/qv4globalobject_p.h"
+
 #include <QtCore/qdatetime.h>
 #include <QtCore/qmetaobject.h>
 #include <QtCore/qstringlist.h>
@@ -220,9 +224,7 @@ QJSEngine::~QJSEngine()
 */
 void QJSEngine::collectGarbage()
 {
-    Q_D(QJSEngine);
-    QScriptIsolate api(d);
-    d->collectGarbage();
+    d->m_v4Engine->memoryManager->runGC();
 }
 
 /*!
@@ -255,10 +257,18 @@ void QJSEngine::collectGarbage()
 */
 QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, int lineNumber)
 {
-    Q_D(QJSEngine);
-    QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
-    v8::HandleScope handleScope;
-    return d->evaluate(program, fileName, qmlSourceCoordinate(lineNumber));
+    try {
+        QQmlJS::VM::Function *f = QQmlJS::VM::EvalFunction::parseSource(d->m_v4Engine->current, fileName, program, QQmlJS::Codegen::EvalCode,
+                                                                        d->m_v4Engine->current->strictMode, true);
+        if (!f)
+            return new QJSValuePrivate(d->m_v4Engine, d->m_v4Engine->newSyntaxErrorObject(d->m_v4Engine->current, 0));
+
+        QQmlJS::VM::Value result = d->m_v4Engine->run(f);
+        return new QJSValuePrivate(d->m_v4Engine, result);
+    } catch (QQmlJS::VM::Exception& ex) {
+        ex.accept(d->m_v4Engine->current);
+        return new QJSValuePrivate(d->m_v4Engine, ex.value());
+    }
 }
 
 /*!
@@ -271,11 +281,7 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in
 */
 QJSValue QJSEngine::newObject()
 {
-    Q_D(QJSEngine);
-    QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
-    v8::HandleScope handleScope;
-    QQmlJS::VM::ExecutionEngine *engine = d->m_v4Engine;
-    return new QJSValuePrivate(engine, QQmlJS::VM::Value::fromObject(engine->newObject()));
+    return new QJSValuePrivate(d->m_v4Engine, d->m_v4Engine->newObject());
 }
 
 /*!
@@ -285,10 +291,9 @@ QJSValue QJSEngine::newObject()
 */
 QJSValue QJSEngine::newArray(uint length)
 {
-    Q_D(QJSEngine);
-    QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
-    v8::HandleScope handleScope;
-    return QJSValuePrivate::get(d->newArray(length));
+    QQmlJS::VM::ArrayObject *array = d->m_v4Engine->newArrayObject(d->m_v4Engine->current);
+    array->setArrayLength(length);
+    return new QJSValuePrivate(d->m_v4Engine, array);
 }
 
 /*!
@@ -313,6 +318,7 @@ QJSValue QJSEngine::newArray(uint length)
 */
 QJSValue QJSEngine::newQObject(QObject *object)
 {
+    // ###
     Q_D(QJSEngine);
     QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
     v8::HandleScope handleScope;
@@ -331,10 +337,7 @@ QJSValue QJSEngine::newQObject(QObject *object)
 */
 QJSValue QJSEngine::globalObject() const
 {
-    Q_D(const QJSEngine);
-    QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
-    v8::HandleScope handleScope;
-    return d->scriptValueFromInternal(d->global());
+    return new QJSValuePrivate(d->m_v4Engine, d->m_v4Engine->globalObject);
 }
 
 /*!
@@ -383,7 +386,7 @@ bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr)
                 *reinterpret_cast<double*>(ptr) = vp->value.toNumber();
                 return true;
             case QMetaType::QString:
-                *reinterpret_cast<QString*>(ptr) = vp->value.toString(engine->m_v4Engine->current)->toQString();
+                *reinterpret_cast<QString*>(ptr) = value.toString();
                 return true;
             case QMetaType::Float:
                 *reinterpret_cast<float*>(ptr) = vp->value.toNumber();
index d74dfa8..4fb1a2a 100644 (file)
@@ -335,10 +335,28 @@ bool QJSValue::isVariant() const
 */
 QString QJSValue::toString() const
 {
-    if (!d->engine)
-        // ###
-        return QString();
-    return d->value.toString(d->engine->current)->toQString();
+    // have to check these here as converting those to a VM::String requires a context
+    // (which we don't always have for those types)
+    if (d->value.isUndefined())
+        return QStringLiteral("undefined");
+    else if (d->value.isNull())
+        return QStringLiteral("null");
+    else if (d->value.isBoolean()) {
+        if (d->value.booleanValue())
+            return QStringLiteral("true");
+        else
+            return QStringLiteral("false");
+    }
+    else if (d->value.isNumber())
+        return __qmljs_numberToString(d->value.asDouble());
+
+    QQmlJS::VM::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+    try {
+        return d->value.toString(ctx)->toQString();
+    } catch (Exception &e) {
+        e.accept(ctx);
+        return e.value().toString(ctx)->toQString();
+    }
 }
 
 /*!
@@ -355,7 +373,13 @@ QString QJSValue::toString() const
 */
 double QJSValue::toNumber() const
 {
-    return d->value.toNumber();
+    QQmlJS::VM::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+    try {
+        return d->value.toNumber();
+    } catch (Exception &e) {
+        e.accept(ctx);
+        return 0;
+    }
 }
 
 /*!
@@ -372,7 +396,13 @@ double QJSValue::toNumber() const
 */
 bool QJSValue::toBool() const
 {
-    return d->value.toBoolean();
+    QQmlJS::VM::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+    try {
+        return d->value.toBoolean();
+    } catch (Exception &e) {
+        e.accept(ctx);
+        return false;
+    }
 }
 
 /*!
@@ -389,7 +419,13 @@ bool QJSValue::toBool() const
 */
 qint32 QJSValue::toInt() const
 {
-    return d->value.toInt32();
+    QQmlJS::VM::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+    try {
+        return d->value.toInt32();
+    } catch (Exception &e) {
+        e.accept(ctx);
+        return 0;
+    }
 }
 
 /*!
@@ -406,7 +442,13 @@ qint32 QJSValue::toInt() const
 */
 quint32 QJSValue::toUInt() const
 {
-    return d->value.toUInt32();
+    QQmlJS::VM::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+    try {
+        return d->value.toUInt32();
+    } catch (Exception &e) {
+        e.accept(ctx);
+        return 0;
+    }
 }
 
 /*!
@@ -466,9 +508,11 @@ QJSValue QJSValue::call(const QJSValueList &args)
         arguments[i] = args.at(i).d->getValue(engine);
 
     Value result;
+    QQmlJS::VM::ExecutionContext *ctx = d->engine->current;
     try {
-        result = f->call(d->engine->current, Value::fromObject(d->engine->globalObject), arguments.data(), arguments.size());
+        result = f->call(ctx, Value::fromObject(d->engine->globalObject), arguments.data(), arguments.size());
     } catch (Exception &e) {
+        e.accept(ctx);
         result = e.value();
     }
 
@@ -509,9 +553,11 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
         arguments[i] = args.at(i).d->getValue(engine);
 
     Value result;
+    QQmlJS::VM::ExecutionContext *ctx = d->engine->current;
     try {
-        result = f->call(d->engine->current, instance.d->getValue(engine), arguments.data(), arguments.size());
+        result = f->call(ctx, instance.d->getValue(engine), arguments.data(), arguments.size());
     } catch (Exception &e) {
+        e.accept(ctx);
         result = e.value();
     }
 
@@ -550,9 +596,11 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
         arguments[i] = args.at(i).d->getValue(engine);
 
     Value result;
+    QQmlJS::VM::ExecutionContext *ctx = d->engine->current;
     try {
-        result = f->construct(d->engine->current, arguments.data(), arguments.size());
+        result = f->construct(ctx, arguments.data(), arguments.size());
     } catch (Exception &e) {
+        e.accept(ctx);
         result = e.value();
     }
 
@@ -704,9 +752,20 @@ QJSValue QJSValue::property(const QString& name) const
     if (!o)
         return QJSValue();
 
-    String *s = d->engine->newIdentifier(name);
-    QQmlJS::VM::Value v = o->get(d->engine->current, s);
-    return new QJSValuePrivate(d->engine, v);
+    String *s = d->engine->newString(name);
+    uint idx = s->asArrayIndex();
+    if (idx < UINT_MAX)
+        return property(idx);
+
+    s->makeIdentifier(d->engine->current);
+    QQmlJS::VM::ExecutionContext *ctx = d->engine->current;
+    try {
+        QQmlJS::VM::Value v = o->get(ctx, s);
+        return new QJSValuePrivate(d->engine, v);
+    } catch (QQmlJS::VM::Exception &e) {
+        e.accept(ctx);
+        return QJSValue();
+    }
 }
 
 /*!
@@ -727,8 +786,14 @@ QJSValue QJSValue::property(quint32 arrayIndex) const
     if (!o)
         return QJSValue();
 
-    QQmlJS::VM::Value v = o->getIndexed(d->engine->current, arrayIndex);
-    return new QJSValuePrivate(d->engine, v);
+    QQmlJS::VM::ExecutionContext *ctx = d->engine->current;
+    try {
+        QQmlJS::VM::Value v = o->getIndexed(ctx, arrayIndex);
+        return new QJSValuePrivate(d->engine, v);
+    } catch (QQmlJS::VM::Exception &e) {
+        e.accept(ctx);
+        return QJSValue();
+    }
 }
 
 /*!
@@ -748,8 +813,20 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value)
     if (!o)
         return;
 
-    String *s = d->engine->newIdentifier(name);
-    o->put(d->engine->current, s, value.d->value);
+    String *s = d->engine->newString(name);
+    uint idx = s->asArrayIndex();
+    if (idx < UINT_MAX) {
+        setProperty(idx, value);
+        return;
+    }
+
+    QQmlJS::VM::ExecutionContext *ctx = d->engine->current;
+    s->makeIdentifier(ctx);
+    try {
+        o->put(ctx, s, value.d->value);
+    } catch (QQmlJS::VM::Exception &e) {
+        e.accept(ctx);
+    }
 }
 
 /*!
@@ -770,7 +847,12 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
     if (!o)
         return;
 
-    o->putIndexed(d->engine->current, arrayIndex, value.d->value);
+    QQmlJS::VM::ExecutionContext *ctx = d->engine->current;
+    try {
+        o->putIndexed(ctx, arrayIndex, value.d->value);
+    } catch (QQmlJS::VM::Exception &e) {
+        e.accept(ctx);
+    }
 }
 
 /*!
index 2bc9ec7..d28d22c 100644 (file)
@@ -71,6 +71,14 @@ public:
         : PersistentValuePrivate(e, v)
         , string(QString())
     {}
+    QJSValuePrivate(QQmlJS::VM::ExecutionEngine *e, QQmlJS::VM::Object *o)
+        : PersistentValuePrivate(e, QQmlJS::VM::Value::fromObject(o))
+        , string(QString())
+    {}
+    QJSValuePrivate(QQmlJS::VM::ExecutionEngine *e, QQmlJS::VM::String *s)
+        : PersistentValuePrivate(e, QQmlJS::VM::Value::fromString(s))
+        , string(QString())
+    {}
     QJSValuePrivate(const QQmlJS::VM::Value &v)
         : PersistentValuePrivate(v)
         , string(QString())
index 78f1256..4004269 100644 (file)
@@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE
 
 QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v)
     : value(v)
-    , iterator(QJSValuePrivate::get(v)->value.asObject(), QQmlJS::VM::ObjectIterator::EnumberableOnly)
+    , iterator(QJSValuePrivate::get(v)->value.asObject(), QQmlJS::VM::ObjectIterator::NoFlags)
     , currentValue(0)
     , currentName(0)
     , currentIndex(UINT_MAX)
@@ -115,6 +115,8 @@ QJSValueIterator::~QJSValueIterator()
 */
 bool QJSValueIterator::hasNext() const
 {
+    if (!QJSValuePrivate::get(d_ptr->value)->value.isObject())
+        return false;
     return d_ptr->nextValue != 0;
 }
 
@@ -131,12 +133,15 @@ bool QJSValueIterator::hasNext() const
 */
 bool QJSValueIterator::next()
 {
+    if (!QJSValuePrivate::get(d_ptr->value)->value.isObject())
+        return false;
     d_ptr->currentValue = d_ptr->nextValue;
     d_ptr->currentName = d_ptr->nextName;
     d_ptr->currentIndex = d_ptr->nextIndex;
     d_ptr->currentAttributes = d_ptr->nextAttributes;
 
     d_ptr->nextValue = d_ptr->iterator.next(&d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes);
+    return d_ptr->nextValue != 0;
 }
 
 /*!
@@ -147,6 +152,8 @@ bool QJSValueIterator::next()
 */
 QString QJSValueIterator::name() const
 {
+    if (!QJSValuePrivate::get(d_ptr->value)->value.isObject())
+        return false;
     if (d_ptr->currentName)
         return d_ptr->currentName->toQString();
     if (d_ptr->currentIndex < UINT_MAX)
@@ -163,6 +170,8 @@ QString QJSValueIterator::name() const
 */
 QJSValue QJSValueIterator::value() const
 {
+    if (!QJSValuePrivate::get(d_ptr->value)->value.isObject())
+        return QJSValue();
     if (!d_ptr->currentValue)
         return QJSValue();
 
@@ -183,7 +192,7 @@ QJSValue QJSValueIterator::value() const
 */
 QJSValueIterator& QJSValueIterator::operator=(QJSValue& object)
 {
-    d_ptr->iterator = QQmlJS::VM::ObjectIterator(QJSValuePrivate::get(object)->value.asObject(), QQmlJS::VM::ObjectIterator::EnumberableOnly);
+    d_ptr->iterator = QQmlJS::VM::ObjectIterator(QJSValuePrivate::get(object)->value.asObject(), QQmlJS::VM::ObjectIterator::NoFlags);
     d_ptr->nextValue = d_ptr->iterator.next(&d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes);
 }
 
index 09fa426..f7d9e92 100644 (file)
@@ -9,9 +9,7 @@ HEADERS += \
     $$PWD/qjsvalue.h \
     $$PWD/qjsvalue_p.h \
     $$PWD/qjsvalueiterator.h \
-    $$PWD/qjsvalue_impl_p.h \
     $$PWD/qjsconverter_p.h \
     $$PWD/qjsconverter_impl_p.h \
     $$PWD/qscriptisolate_p.h \
-    $$PWD/qjsvalueiterator_p.h \
-    $$PWD/qjsvalueiterator_impl_p.h
+    $$PWD/qjsvalueiterator_p.h
index 49e66c0..effa54e 100644 (file)
@@ -378,7 +378,7 @@ void tst_QJSValue::toString()
             "})()");
         QVERIFY(!objectObject.isError());
         QVERIFY(objectObject.isObject());
-        QCOMPARE(objectObject.toString(), QString::fromLatin1("TypeError: Function.prototype.toString is not generic"));
+        QCOMPARE(objectObject.toString(), QString::fromLatin1("TypeError: Type error"));
     }
 
     QJSValue inv = QJSValue();