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)); } }