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; }
/*! 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); }
/*! 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(); }
/*! 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); }
/*! 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; }
/*! 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; }
/*! 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; }
/*! 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); }
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(); }
/*! \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); }
/*! \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(); }
/*! 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(); }
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)); } }