void QEnginioCollectionObjectPrivate::QmlCallbackFunctor::operator ()(QEnginioOperationObject *aOperation)
{
    using namespace QV4;

    if (!aOperation)
        return;

    if (iCallback.isCallable()) {
        QJSValuePrivate *prv=QJSValuePrivate::get(iCallback);
        FunctionObject *f =prv->value.asFunctionObject();

        if (f) {
            ExecutionEngine *engine = prv->engine;
            Q_ASSERT(engine);

            Scope scope(engine);
            ScopedCallData callData(scope, 1); // args.length());
            callData->thisObject = engine->globalObject->asReturnedValue();

            ScopedValue result(scope);
            QV4::ExecutionContext *ctx = engine->currentContext();

            callData->args[0] = QObjectWrapper::wrap(engine,aOperation);

            result = f->call(callData);
            if (scope.hasException()) {
                result = ctx->catchException();
            }
            QJSValue tmp(new QJSValuePrivate(engine, result));
        }
    }

    delete aOperation;
}
Beispiel #2
0
/*!
  Returns the value of this QJSValue's property with the given \a name.
  If no such property exists, an undefined QJSValue is returned.

  If the property is implemented using a getter function (i.e. has the
  PropertyGetter flag set), calling property() has side-effects on the
  script engine, since the getter function will be called (possibly
  resulting in an uncaught script exception). If an exception
  occurred, property() returns the value that was thrown (typically
  an \c{Error} object).

  \sa setProperty(), hasProperty(), QJSValueIterator
*/
QJSValue QJSValue::property(const QString& name) const
{
    ExecutionEngine *engine = d->engine;
    if (!engine)
        return QJSValue();
    QV4::Scope scope(engine);

    ScopedObject o(scope, d->value);
    if (!o)
        return QJSValue();

    ScopedString s(scope, engine->newString(name));
    uint idx = s->asArrayIndex();
    if (idx < UINT_MAX)
        return property(idx);

    s->makeIdentifier();
    QV4::ExecutionContext *ctx = engine->currentContext();
    QV4::ScopedValue result(scope);
    result = o->get(s);
    if (scope.hasException())
        result = ctx->catchException();

    return new QJSValuePrivate(engine, result);
}
Beispiel #3
0
/*!
  Sets the value of this QJSValue's property with the given \a name to
  the given \a value.

  If this QJSValue is not an object, this function does nothing.

  If this QJSValue does not already have a property with name \a name,
  a new property is created.

  \sa property(), deleteProperty()
*/
void QJSValue::setProperty(const QString& name, const QJSValue& value)
{
    ExecutionEngine *engine = d->engine;
    if (!engine)
        return;
    Scope scope(engine);

    Scoped<Object> o(scope, d->value);
    if (!o)
        return;

    if (!value.d->checkEngine(o->engine())) {
        qWarning("QJSValue::setProperty(%s) failed: cannot set value created in a different engine", name.toUtf8().constData());
        return;
    }

    ScopedString s(scope, engine->newString(name));
    uint idx = s->asArrayIndex();
    if (idx < UINT_MAX) {
        setProperty(idx, value);
        return;
    }

    QV4::ExecutionContext *ctx = engine->currentContext();
    s->makeIdentifier();
    QV4::ScopedValue v(scope, value.d->getValue(engine));
    o->put(s, v);
    if (scope.hasException())
        ctx->catchException();
}
Beispiel #4
0
/*!
  Creates a new \c{Object} and calls this QJSValue as a
  constructor, using the created object as the `this' object and
  passing \a args as arguments. If the return value from the
  constructor call is an object, then that object is returned;
  otherwise the default constructed object is returned.

  If this QJSValue is not a function, callAsConstructor() does
  nothing and returns an undefined QJSValue.

  Calling this function can cause an exception to occur in the
  script engine; in that case, the value that was thrown
  (typically an \c{Error} object) is returned. You can call
  isError() on the return value to determine whether an
  exception occurred.

  \sa call(), QJSEngine::newObject()
*/
QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
{
    FunctionObject *f = d->value.asFunctionObject();
    if (!f)
        return QJSValue();

    ExecutionEngine *engine = d->engine;
    assert(engine);

    Scope scope(engine);
    ScopedCallData callData(scope, args.size());
    for (int i = 0; i < args.size(); ++i) {
        if (!args.at(i).d->checkEngine(engine)) {
            qWarning("QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine");
            return QJSValue();
        }
        callData->args[i] = args.at(i).d->getValue(engine);
    }

    ScopedValue result(scope);
    QV4::ExecutionContext *ctx = engine->currentContext();
    result = f->construct(callData);
    if (scope.hasException())
        result = ctx->catchException();

    return new QJSValuePrivate(engine, result);
}
Beispiel #5
0
/*!
  Returns the unsigned 32-bit integer value of this QJSValue, using
  the conversion rules described in \l{ECMA-262} section 9.6, "ToUint32".

  Note that if this QJSValue is an object, calling this function
  has side effects on the script engine, since the engine will call
  the object's valueOf() function (and possibly toString()) in an
  attempt to convert the object to a primitive value (possibly
  resulting in an uncaught script exception).

  \sa toNumber(), toInt()
*/
quint32 QJSValue::toUInt() const
{
    if (d->value.isEmpty())
        return QV4::Primitive::toUInt32(__qmljs_string_to_number(d->string));

    QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
    quint32 u = d->value.toUInt32();
    if (ctx && ctx->engine->hasException) {
        ctx->catchException();
        return 0;
    }
    return u;
}
Beispiel #6
0
/*!
  Returns the boolean value of this QJSValue, using the conversion
  rules described in \l{ECMA-262} section 9.2, "ToBoolean".

  Note that if this QJSValue is an object, calling this function
  has side effects on the script engine, since the engine will call
  the object's valueOf() function (and possibly toString()) in an
  attempt to convert the object to a primitive value (possibly
  resulting in an uncaught script exception).

  \sa isBool()
*/
bool QJSValue::toBool() const
{
    if (d->value.isEmpty())
        return d->string.length() > 0;

    QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
    bool b = d->value.toBoolean();
    if (ctx && ctx->engine->hasException) {
        ctx->catchException();
        return false;
    }
    return b;
}
Beispiel #7
0
/*!
  Returns the number value of this QJSValue, as defined in
  \l{ECMA-262} section 9.3, "ToNumber".

  Note that if this QJSValue is an object, calling this function
  has side effects on the script engine, since the engine will call
  the object's valueOf() function (and possibly toString()) in an
  attempt to convert the object to a primitive value (possibly
  resulting in an uncaught script exception).

  \sa isNumber(), toInt(), toUInt()
*/
double QJSValue::toNumber() const
{
    if (d->value.isEmpty())
        return __qmljs_string_to_number(d->string);

    QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
    double dbl = d->value.toNumber();
    if (ctx && ctx->engine->hasException) {
        ctx->catchException();
        return 0;
    }
    return dbl;
}
Beispiel #8
0
/*!
    Evaluates \a program, using \a lineNumber as the base line number,
    and returns the result of the evaluation.

    The script code will be evaluated in the current context.

    The evaluation of \a program can cause an exception in the
    engine; in this case the return value will be the exception
    that was thrown (typically an \c{Error} object; see
    QJSValue::isError()).

    \a lineNumber is used to specify a starting line number for \a
    program; line number information reported by the engine that pertains
    to this evaluation will be based on this argument. For example, if
    \a program consists of two lines of code, and the statement on the
    second line causes a script exception, the exception line number
    would be \a lineNumber plus one. When no starting line number is
    specified, line numbers will be 1-based.

    \a fileName is used for error reporting. For example, in error objects
    the file name is accessible through the "fileName" property if it is
    provided with this function.

    \note If an exception was thrown and the exception value is not an
    Error instance (i.e., QJSValue::isError() returns \c false), the
    exception value will still be returned, but there is currently no
    API for detecting that an exception did occur in this case.
*/
QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, int lineNumber)
{
    QV4::Scope scope(d->m_v4Engine);
    QV4::ExecutionContext *ctx = d->m_v4Engine->currentContext();
    QV4::ScopedValue result(scope);

    QV4::Script script(ctx, program, fileName, lineNumber);
    script.strictMode = ctx->strictMode;
    script.inheritContext = true;
    script.parse();
    if (!scope.engine->hasException)
        result = script.run();
    if (scope.engine->hasException)
        result = ctx->catchException();
    return new QJSValuePrivate(d->m_v4Engine, result);
}
Beispiel #9
0
QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine,  const QString &script, ObjectRef scopeObject)
{
    QV4::Scope scope(engine);
    QV4::Script qmlScript(engine, scopeObject, script, QString());

    QV4::ExecutionContext *ctx = engine->currentContext();
    qmlScript.parse();
    QV4::ScopedValue result(scope);
    if (!scope.engine->hasException)
        result = qmlScript.run();
    if (scope.engine->hasException) {
        ctx->catchException();
        return Encode::undefined();
    }
    return result.asReturnedValue();
}
Beispiel #10
0
/*!
  \overload

  Returns the property at the given \a arrayIndex.

  This function is provided for convenience and performance when
  working with array objects.

  If this QJSValue is not an Array object, this function behaves
  as if property() was called with the string representation of \a
  arrayIndex.
*/
QJSValue QJSValue::property(quint32 arrayIndex) const
{
    ExecutionEngine *engine = d->engine;
    if (!engine)
        return QJSValue();

    QV4::Scope scope(engine);
    ScopedObject o(scope, d->value);
    if (!o)
        return QJSValue();

    QV4::ExecutionContext *ctx = engine->currentContext();
    QV4::ScopedValue result(scope);
    result = arrayIndex == UINT_MAX ? o->get(engine->id_uintMax) : o->getIndexed(arrayIndex);
    if (scope.hasException())
        result = ctx->catchException();
    return new QJSValuePrivate(engine, result);
}
Beispiel #11
0
/*!
  \overload

  Sets the property at the given \a arrayIndex to the given \a value.

  This function is provided for convenience and performance when
  working with array objects.

  If this QJSValue is not an Array object, this function behaves
  as if setProperty() was called with the string representation of \a
  arrayIndex.
*/
void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
{
    ExecutionEngine *engine = d->engine;
    if (!engine)
        return;
    Scope scope(engine);

    Scoped<Object> o(scope, d->value);
    if (!o)
        return;

    QV4::ExecutionContext *ctx = engine->currentContext();
    QV4::ScopedValue v(scope, value.d->getValue(engine));
    if (arrayIndex != UINT_MAX)
        o->putIndexed(arrayIndex, v);
    else
        o->put(engine->id_uintMax, v);
    if (scope.hasException())
        ctx->catchException();
}
Beispiel #12
0
/*!
    Evaluates \a program, using \a lineNumber as the base line number,
    and returns the result of the evaluation.

    The script code will be evaluated in the context of the global object.

    The evaluation of \a program can cause an \l{Script Exceptions}{exception} in the
    engine; in this case the return value will be the exception
    that was thrown (typically an \c{Error} object; see
    QJSValue::isError()).

    \a lineNumber is used to specify a starting line number for \a
    program; line number information reported by the engine that pertains
    to this evaluation will be based on this argument. For example, if
    \a program consists of two lines of code, and the statement on the
    second line causes a script exception, the exception line number
    would be \a lineNumber plus one. When no starting line number is
    specified, line numbers will be 1-based.

    \a fileName is used for error reporting. For example, in error objects
    the file name is accessible through the "fileName" property if it is
    provided with this function.

    \note If an exception was thrown and the exception value is not an
    Error instance (i.e., QJSValue::isError() returns \c false), the
    exception value will still be returned, but there is currently no
    API for detecting that an exception did occur in this case.
*/
QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, int lineNumber)
{
    QV4::ExecutionEngine *v4 = d->m_v4Engine;
    QV4::Scope scope(v4);
    QV4::ExecutionContextSaver saver(scope);

    QV4::ExecutionContext *ctx = v4->currentContext;
    if (ctx->d() != v4->rootContext()->d())
        ctx = v4->pushGlobalContext();
    QV4::ScopedValue result(scope);

    QV4::Script script(ctx, program, fileName, lineNumber);
    script.strictMode = ctx->d()->strictMode;
    script.inheritContext = true;
    script.parse();
    if (!scope.engine->hasException)
        result = script.run();
    if (scope.engine->hasException)
        result = v4->catchException();

    return QJSValue(v4, result->asReturnedValue());
}
QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context,
                                   const QV4::ValueRef function,
                                   QV4::CallData *callData,
                                   bool *isUndefined)
{
    Q_ASSERT(context && context->engine);

    if (function->isUndefined()) {
        if (isUndefined)
            *isUndefined = true;
        return QV4::Encode::undefined();
    }

    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);

    // All code that follows must check with watcher before it accesses data members
    // incase we have been deleted.
    DeleteWatcher watcher(this);

    Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty());
    GuardCapture capture(context->engine, this, &watcher);

    QQmlEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture;
    ep->propertyCapture = notifyOnValueChanged()?&capture:0;


    if (notifyOnValueChanged())
        capture.guards.copyAndClearPrepend(activeGuards);

    QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine());
    QV4::Scope scope(v4);
    QV4::ScopedValue result(scope, QV4::Primitive::undefinedValue());
    QV4::ExecutionContext *ctx = v4->currentContext();
    callData->thisObject = v4->globalObject;
    if (scopeObject()) {
        QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(ctx->d()->engine, scopeObject()));
        if (value->isObject())
            callData->thisObject = value;
    }

    result = function->asFunctionObject()->call(callData);
    if (scope.hasException()) {
        if (watcher.wasDeleted())
            ctx->catchException(); // ignore exception
        else
            delayedError()->catchJavaScriptException(ctx);
        if (isUndefined)
            *isUndefined = true;
    } else {
        if (isUndefined)
            *isUndefined = result->isUndefined();

        if (!watcher.wasDeleted() && hasDelayedError())
            delayedError()->clearError();
    }

    if (capture.errorString) {
        for (int ii = 0; ii < capture.errorString->count(); ++ii)
            qWarning("%s", qPrintable(capture.errorString->at(ii)));
        delete capture.errorString;
        capture.errorString = 0;
    }

    while (Guard *g = capture.guards.takeFirst())
        g->Delete();

    ep->propertyCapture = lastPropertyCapture;

    return result.asReturnedValue();
}
Beispiel #14
0
void Serialize::serialize(QByteArray &data, const QV4::ValueRef v, QV8Engine *engine)
{
    QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
    QV4::Scope scope(v4);

    if (v->isEmpty()) {
        Q_ASSERT(!"Serialize: got empty value");
    } else if (v->isUndefined()) {
        push(data, valueheader(WorkerUndefined));
    } else if (v->isNull()) {
        push(data, valueheader(WorkerNull));
    } else if (v->isBoolean()) {
        push(data, valueheader(v->booleanValue() == true ? WorkerTrue : WorkerFalse));
    } else if (v->isString()) {
        const QString &qstr = v->toQString();
        int length = qstr.length();
        if (length > 0xFFFFFF) {
            push(data, valueheader(WorkerUndefined));
            return;
        }
        int utf16size = ALIGN(length * sizeof(uint16_t));

        reserve(data, utf16size + sizeof(quint32));
        push(data, valueheader(WorkerString, length));

        int offset = data.size();
        data.resize(data.size() + utf16size);
        char *buffer = data.data() + offset;

        memcpy(buffer, qstr.constData(), length*sizeof(QChar));
    } else if (v->asFunctionObject()) {
        // XXX TODO: Implement passing function objects between the main and
        // worker scripts
        push(data, valueheader(WorkerUndefined));
    } else if (v->asArrayObject()) {
        QV4::ScopedArrayObject array(scope, v);
        uint32_t length = array->getLength();
        if (length > 0xFFFFFF) {
            push(data, valueheader(WorkerUndefined));
            return;
        }
        reserve(data, sizeof(quint32) + length * sizeof(quint32));
        push(data, valueheader(WorkerArray, length));
        ScopedValue val(scope);
        for (uint32_t ii = 0; ii < length; ++ii)
            serialize(data, (val = array->getIndexed(ii)), engine);
    } else if (v->isInteger()) {
        reserve(data, 2 * sizeof(quint32));
        push(data, valueheader(WorkerInt32));
        push(data, (quint32)v->integerValue());
//    } else if (v->IsUint32()) {
//        reserve(data, 2 * sizeof(quint32));
//        push(data, valueheader(WorkerUint32));
//        push(data, v->Uint32Value());
    } else if (v->isNumber()) {
        reserve(data, sizeof(quint32) + sizeof(double));
        push(data, valueheader(WorkerNumber));
        push(data, v->asDouble());
    } else if (QV4::DateObject *d = v->asDateObject()) {
        reserve(data, sizeof(quint32) + sizeof(double));
        push(data, valueheader(WorkerDate));
        push(data, d->date().asDouble());
    } else if (v->as<RegExpObject>()) {
        Scoped<RegExpObject> re(scope, v);
        quint32 flags = re->flags();
        QString pattern = re->source();
        int length = pattern.length() + 1;
        if (length > 0xFFFFFF) {
            push(data, valueheader(WorkerUndefined));
            return;
        }
        int utf16size = ALIGN(length * sizeof(uint16_t));

        reserve(data, sizeof(quint32) + utf16size);
        push(data, valueheader(WorkerRegexp, flags));
        push(data, (quint32)length);

        int offset = data.size();
        data.resize(data.size() + utf16size);
        char *buffer = data.data() + offset;

        memcpy(buffer, pattern.constData(), length*sizeof(QChar));
    } else if (v->as<QV4::QObjectWrapper>()) {
        Scoped<QObjectWrapper> qobjectWrapper(scope, v);
        // XXX TODO: Generalize passing objects between the main thread and worker scripts so
        // that others can trivially plug in their elements.
        QQmlListModel *lm = qobject_cast<QQmlListModel *>(qobjectWrapper->object());
        if (lm && lm->agent()) {
            QQmlListModelWorkerAgent *agent = lm->agent();
            agent->addref();
            push(data, valueheader(WorkerListModel));
            push(data, (void *)agent);
            return;
        }
        // No other QObject's are allowed to be sent
        push(data, valueheader(WorkerUndefined));
    } else if (v->asObject()) {
        ScopedObject o(scope, v);
        if (o->isListType()) {
            // valid sequence.  we generate a length (sequence length + 1 for the sequence type)
            uint32_t seqLength = ScopedValue(scope, o->get(v4->id_length))->toUInt32();
            uint32_t length = seqLength + 1;
            if (length > 0xFFFFFF) {
                push(data, valueheader(WorkerUndefined));
                return;
            }
            reserve(data, sizeof(quint32) + length * sizeof(quint32));
            push(data, valueheader(WorkerSequence, length));
            serialize(data, QV4::Primitive::fromInt32(QV4::SequencePrototype::metaTypeForSequence(o)), engine); // sequence type
            ScopedValue val(scope);
            for (uint32_t ii = 0; ii < seqLength; ++ii)
                serialize(data, (val = o->getIndexed(ii)), engine); // sequence elements

            return;
        }

        // regular object
        QV4::ScopedValue val(scope, *v);
        QV4::ScopedArrayObject properties(scope, QV4::ObjectPrototype::getOwnPropertyNames(v4, val));
        quint32 length = properties->getLength();
        if (length > 0xFFFFFF) {
            push(data, valueheader(WorkerUndefined));
            return;
        }
        push(data, valueheader(WorkerObject, length));

        QV4::ScopedValue s(scope);
        QV4::ScopedString str(scope);
        for (quint32 ii = 0; ii < length; ++ii) {
            s = properties->getIndexed(ii);
            serialize(data, s, engine);

            QV4::ExecutionContext *ctx = v4->currentContext();
            str = s;
            val = o->get(str.getPointer());
            if (scope.hasException())
                ctx->catchException();

            serialize(data, val, engine);
        }
        return;
    } else {
        push(data, valueheader(WorkerUndefined));
    }
}