diff options
Diffstat (limited to 'src/qml')
87 files changed, 1051 insertions, 1319 deletions
diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp index 45379d5155..383c20239f 100644 --- a/src/qml/compiler/qqmlpropertyvalidator.cpp +++ b/src/qml/compiler/qqmlpropertyvalidator.cpp @@ -412,7 +412,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache } } break; -#ifndef QT_NO_DATESTRING +#if QT_CONFIG(datestring) case QVariant::Date: { bool ok = false; QQmlStringConverters::dateFromString(binding->valueAsString(qmlUnit), &ok); @@ -437,7 +437,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache } } break; -#endif // QT_NO_DATESTRING +#endif // datestring case QVariant::Point: { bool ok = false; QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok); diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 2308e66609..393616dfac 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -1570,19 +1570,15 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR: if (!_canSimplify) return false; } - if (!_canSimplify) - return false; } if (_returnValueOfBindingExpression == -1) return false; - if (_canSimplify) { - if (_nameOfFunctionCalled) { - if (_functionCallReturnValue != _returnValueOfBindingExpression) - return false; - return detectTranslationCallAndConvertBinding(binding); - } + if (_nameOfFunctionCalled) { + if (_functionCallReturnValue != _returnValueOfBindingExpression) + return false; + return detectTranslationCallAndConvertBinding(binding); } return false; diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index f8668b48e4..8586c84c3d 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -471,7 +471,7 @@ QString Binding::valueAsString(const Unit *unit) const return QString::number(valueAsNumber()); case Type_Invalid: return QString(); -#ifdef QT_NO_TRANSLATION +#if !QT_CONFIG(translation) case Type_TranslationById: case Type_Translation: return unit->stringAt(stringIndex); diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 3a0c83ddad..2682365182 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -71,7 +71,7 @@ QT_BEGIN_NAMESPACE // Bump this whenever the compiler data structures change in an incompatible way. -#define QV4_DATA_STRUCTURE_VERSION 0x07 +#define QV4_DATA_STRUCTURE_VERSION 0x08 class QIODevice; class QQmlPropertyCache; @@ -207,9 +207,9 @@ struct String struct Function { enum Flags : unsigned int { - HasDirectEval = 0x1, - UsesArgumentsObject = 0x2, - IsStrict = 0x4, + IsStrict = 0x1, + HasDirectEval = 0x2, + UsesArgumentsObject = 0x4, IsNamedExpression = 0x8, HasCatchOrWith = 0x10 }; diff --git a/src/qml/debugger/qqmlmemoryprofiler.cpp b/src/qml/debugger/qqmlmemoryprofiler.cpp index 53d4e7ab21..b89dbfd02d 100644 --- a/src/qml/debugger/qqmlmemoryprofiler.cpp +++ b/src/qml/debugger/qqmlmemoryprofiler.cpp @@ -62,13 +62,13 @@ static qmlmemprofile_pop_location *memprofile_pop_location; static qmlmemprofile_save *memprofile_save; static qmlmemprofile_is_enabled *memprofile_is_enabled; -#ifndef QT_NO_LIBRARY +#if QT_CONFIG(library) extern QFunctionPointer qt_linux_find_symbol_sys(const char *symbol); #endif bool QQmlMemoryScope::doOpenLibrary() { -#if defined(Q_OS_LINUX) && !defined(QT_NO_LIBRARY) +#if defined(Q_OS_LINUX) && QT_CONFIG(library) if (state == Unloaded) { memprofile_stats = (qmlmemprofile_stats *) qt_linux_find_symbol_sys("qmlmemprofile_stats"); memprofile_clear = (qmlmemprofile_clear *) qt_linux_find_symbol_sys("qmlmemprofile_clear"); diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h index 6643695d11..3a507bef74 100644 --- a/src/qml/debugger/qqmlprofiler_p.h +++ b/src/qml/debugger/qqmlprofiler_p.h @@ -149,40 +149,38 @@ class Q_QML_PRIVATE_EXPORT QQmlProfiler : public QObject, public QQmlProfilerDef Q_OBJECT public: - class BindingRefCount : public QQmlRefCount { + class FunctionRefCount : public QQmlRefCount { public: - BindingRefCount(QQmlBinding *binding): - m_binding(binding) + FunctionRefCount(QV4::Function *function): + m_function(function) { - m_binding->ref.ref(); + m_function->compilationUnit->addref(); } - BindingRefCount(const BindingRefCount &other) : - QQmlRefCount(other), m_binding(other.m_binding) + FunctionRefCount(const FunctionRefCount &other) : + QQmlRefCount(other), m_function(other.m_function) { - m_binding->ref.ref(); + m_function->compilationUnit->addref(); } - BindingRefCount &operator=(const BindingRefCount &other) + FunctionRefCount &operator=(const FunctionRefCount &other) { if (this != &other) { QQmlRefCount::operator=(other); - other.m_binding->ref.ref(); - if (!m_binding->ref.deref()) - delete m_binding; - m_binding = other.m_binding; + other.m_function->compilationUnit->addref(); + m_function->compilationUnit->release(); + m_function = other.m_function; } return *this; } - ~BindingRefCount() + ~FunctionRefCount() { - if (!m_binding->ref.deref()) - delete m_binding; + m_function->compilationUnit->release(); } private: - QQmlBinding *m_binding; + QV4::Function *m_function; }; struct Location { @@ -199,9 +197,10 @@ public: RefLocation() : Location(), locationType(MaximumRangeType), ref(nullptr), sent(false) {} - RefLocation(QQmlBinding *binding, QV4::FunctionObject *function) : + RefLocation(QV4::Function *function) : Location(function->sourceLocation()), locationType(Binding), - ref(new BindingRefCount(binding), QQmlRefPointer<QQmlRefCount>::Adopt), sent(false) + ref(new FunctionRefCount(function), + QQmlRefPointer<QQmlRefCount>::Adopt), sent(false) {} RefLocation(QV4::CompiledData::CompilationUnit *ref, const QUrl &url, const QV4::CompiledData::Object *obj, @@ -231,16 +230,21 @@ public: typedef QHash<quintptr, Location> LocationHash; - void startBinding(QQmlBinding *binding, QV4::FunctionObject *function) + void startBinding(QV4::Function *function) { - quintptr locationId(id(binding)); + // Use the QV4::Function as ID, as that is common among different instances of the same + // component. QQmlBinding is per instance. + // Add 1 to the ID, to make it different from the IDs the V4 profiler produces. The +1 makes + // the pointer point into the middle of the QV4::Function. Thus it still points to valid + // memory but we cannot accidentally create a duplicate key from another object. + quintptr locationId(id(function) + 1); m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), (1 << RangeStart | 1 << RangeLocation), Binding, locationId)); RefLocation &location = m_locations[locationId]; if (!location.isValid()) - location = RefLocation(binding, function); + location = RefLocation(function); } // Have toByteArrays() construct another RangeData event from the same QString later. @@ -276,7 +280,8 @@ public: Creating, id(obj))); } - void updateCreating(const QV4::CompiledData::Object *obj, QV4::CompiledData::CompilationUnit *ref, + void updateCreating(const QV4::CompiledData::Object *obj, + QV4::CompiledData::CompilationUnit *ref, const QUrl &url, const QString &type) { quintptr locationId(id(obj)); @@ -325,12 +330,11 @@ struct QQmlProfilerHelper : public QQmlProfilerDefinitions { }; struct QQmlBindingProfiler : public QQmlProfilerHelper { - QQmlBindingProfiler(QQmlProfiler *profiler, QQmlBinding *binding, - QV4::FunctionObject *function) : + QQmlBindingProfiler(QQmlProfiler *profiler, QV4::Function *function) : QQmlProfilerHelper(profiler) { Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileBinding, profiler, - startBinding(binding, function)); + startBinding(function)); } ~QQmlBindingProfiler() diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index ed1455b086..6b8264d801 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -69,13 +69,6 @@ using namespace QV4::JIT; namespace { -inline bool isPregOrConst(IR::Expr *e) -{ - if (IR::Temp *t = e->asTemp()) - return t->kind == IR::Temp::PhysicalRegister; - return e->asConst() != 0; -} - class QIODevicePrintStream: public FilePrintStream { Q_DISABLE_COPY(QIODevicePrintStream) @@ -1171,11 +1164,41 @@ void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target) _as->storeBool(false, target); break; case IR::StringType: + generateRuntimeCall(Assembler::ReturnValueRegister, toBoolean, + Assembler::PointerToValue(source)); + _as->storeBool(Assembler::ReturnValueRegister, target); case IR::VarType: default: + Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source); + Assembler::Pointer tagAddr = addr; + tagAddr.offset += 4; + _as->load32(tagAddr, Assembler::ReturnValueRegister); + + // checkif it's a bool: + Assembler::Jump notBool = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister, + Assembler::TrustedImm32(Value::Boolean_Type_Internal)); + _as->load32(addr, Assembler::ReturnValueRegister); + Assembler::Jump boolDone = _as->jump(); + // check if it's an int32: + notBool.link(_as); + Assembler::Jump fallback = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister, + Assembler::TrustedImm32(Value::Integer_Type_Internal)); + _as->load32(addr, Assembler::ReturnValueRegister); + Assembler::Jump isZero = _as->branch32(Assembler::Equal, Assembler::ReturnValueRegister, + Assembler::TrustedImm32(0)); + _as->move(Assembler::TrustedImm32(1), Assembler::ReturnValueRegister); + Assembler::Jump intDone = _as->jump(); + + // not an int: + fallback.link(_as); generateRuntimeCall(Assembler::ReturnValueRegister, toBoolean, - Assembler::PointerToValue(source)); + Assembler::PointerToValue(source)); + + isZero.link(_as); + intDone.link(_as); + boolDone.link(_as); _as->storeBool(Assembler::ReturnValueRegister, target); + break; } } @@ -1720,9 +1743,6 @@ QT_END_NAMESPACE bool InstructionSelection::visitCJumpDouble(IR::AluOp op, IR::Expr *left, IR::Expr *right, IR::BasicBlock *iftrue, IR::BasicBlock *iffalse) { - if (!isPregOrConst(left) || !isPregOrConst(right)) - return false; - if (_as->nextBlock() == iftrue) { Assembler::Jump target = _as->branchDouble(true, op, left, right); _as->addPatch(iffalse, target); @@ -1737,9 +1757,6 @@ bool InstructionSelection::visitCJumpDouble(IR::AluOp op, IR::Expr *left, IR::Ex bool InstructionSelection::visitCJumpSInt32(IR::AluOp op, IR::Expr *left, IR::Expr *right, IR::BasicBlock *iftrue, IR::BasicBlock *iffalse) { - if (!isPregOrConst(left) || !isPregOrConst(right)) - return false; - if (_as->nextBlock() == iftrue) { Assembler::Jump target = _as->branchInt32(true, op, left, right); _as->addPatch(iffalse, target); diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index a4a96a96a7..b473e96286 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -612,8 +612,8 @@ QVariant QJSValue::toVariant() const if (Object *o = val->as<Object>()) return o->engine()->toVariant(*val, /*typeHint*/ -1, /*createJSValueForObjects*/ false); - if (val->isString()) - return QVariant(val->stringValue()->toQString()); + if (String *s = val->stringValue()) + return QVariant(s->toQString()); if (val->isBoolean()) return QVariant(val->booleanValue()); if (val->isNumber()) { @@ -885,14 +885,14 @@ QJSValue& QJSValue::operator=(const QJSValue& other) static bool js_equal(const QString &string, const QV4::Value &value) { - if (value.isString()) - return string == value.stringValue()->toQString(); + if (String *s = value.stringValue()) + return string == s->toQString(); if (value.isNumber()) return RuntimeHelpers::stringToNumber(string) == value.asDouble(); if (value.isBoolean()) return RuntimeHelpers::stringToNumber(string) == double(value.booleanValue()); - if (value.isObject()) { - Scope scope(value.objectValue()->engine()); + if (Object *o = value.objectValue()) { + Scope scope(o->engine()); ScopedValue p(scope, RuntimeHelpers::toPrimitive(value, PREFERREDTYPE_HINT)); return js_equal(string, p); } @@ -979,8 +979,8 @@ bool QJSValue::strictlyEquals(const QJSValue& other) const return *variant == *QJSValuePrivate::getVariant(&other); if (variant->type() == QVariant::Map || variant->type() == QVariant::List) return false; - if (ov->isString()) - return variant->toString() == ov->stringValue()->toQString(); + if (String *s = ov->stringValue()) + return variant->toString() == s->toQString(); return false; } if (!ov) diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index dcc04cbd54..0c55200c64 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -27,6 +27,7 @@ SOURCES += \ $$PWD/qv4numberobject.cpp \ $$PWD/qv4object.cpp \ $$PWD/qv4objectproto.cpp \ + $$PWD/qv4qmlcontext.cpp \ $$PWD/qv4regexpobject.cpp \ $$PWD/qv4stringobject.cpp \ $$PWD/qv4variantobject.cpp \ @@ -48,7 +49,6 @@ HEADERS += \ $$PWD/qv4global_p.h \ $$PWD/qv4engine_p.h \ $$PWD/qv4context_p.h \ - $$PWD/qv4context_p_p.h \ $$PWD/qv4math_p.h \ $$PWD/qv4persistent_p.h \ $$PWD/qv4debugging_p.h \ @@ -73,6 +73,7 @@ HEADERS += \ $$PWD/qv4numberobject_p.h \ $$PWD/qv4object_p.h \ $$PWD/qv4objectproto_p.h \ + $$PWD/qv4qmlcontext_p.h \ $$PWD/qv4regexpobject_p.h \ $$PWD/qv4stringobject_p.h \ $$PWD/qv4variantobject_p.h \ diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 0dfdf25158..5a190d6690 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -39,7 +39,8 @@ #include <qv4argumentsobject_p.h> #include <qv4alloca_p.h> #include <qv4scopedvalue_p.h> -#include "qv4string_p.h" +#include <qv4string_p.h> +#include <qv4function_p.h> using namespace QV4; @@ -56,8 +57,6 @@ void Heap::ArgumentsObject::init(QV4::CallContext *context) Scope scope(v4); Scoped<QV4::ArgumentsObject> args(scope, this); - args->setArrayType(Heap::ArrayData::Complex); - if (context->d()->strictMode) { Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(context->d()->engine->id_caller())); @@ -83,7 +82,7 @@ void ArgumentsObject::fullyCreate() return; uint argCount = context()->callData->argc; - uint numAccessors = qMin(context()->function->formalParameterCount(), argCount); + uint numAccessors = qMin(context()->formalParameterCount(), argCount); ArrayData::realloc(this, Heap::ArrayData::Sparse, argCount, true); context()->engine->requireArgumentsAccessors(numAccessors); @@ -110,7 +109,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con ScopedProperty map(scope); PropertyAttributes mapAttrs; bool isMapped = false; - uint numAccessors = qMin((int)context()->function->formalParameterCount(), context()->callData->argc); + uint numAccessors = qMin((int)context()->formalParameterCount(), context()->callData->argc); if (pd && index < (uint)numAccessors) isMapped = arrayData()->attributes(index).isAccessor() && pd->getter() == context()->engine->argumentsAccessors[index].getter(); @@ -193,7 +192,7 @@ PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index) if (args->fullyCreated()) return Object::queryIndexed(m, index); - uint numAccessors = qMin((int)args->context()->function->formalParameterCount(), args->context()->callData->argc); + uint numAccessors = qMin((int)args->context()->formalParameterCount(), args->context()->callData->argc); uint argCount = args->context()->callData->argc; if (index >= argCount) return PropertyAttributes(); @@ -245,3 +244,11 @@ void ArgumentsObject::markObjects(Heap::Base *that, ExecutionEngine *e) Object::markObjects(that, e); } + +uint ArgumentsObject::getLength(const Managed *m) +{ + const ArgumentsObject *a = static_cast<const ArgumentsObject *>(m); + if (a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->isInteger()) + return a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->integerValue(); + return Primitive::toUInt32(a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->doubleValue()); +} diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index 37a8d0a94a..0a2ea3b42a 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -132,8 +132,10 @@ struct ArgumentsObject: Object { static bool deleteIndexedProperty(Managed *m, uint index); static PropertyAttributes queryIndexed(const Managed *m, uint index); static void markObjects(Heap::Base *that, ExecutionEngine *e); + static uint getLength(const Managed *m); void fullyCreate(); + }; } diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 390a5e7d7a..544d39339b 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -39,7 +39,7 @@ #include <QString> #include "qv4debugging_p.h" -#include <qv4context_p_p.h> +#include <qv4context_p.h> #include <qv4object_p.h> #include <qv4objectproto_p.h> #include <private/qv4mm_p.h> @@ -47,6 +47,9 @@ #include "qv4function_p.h" #include "qv4errorobject_p.h" #include "qv4string_p.h" +#include "qv4qmlcontext_p.h" +#include "qv4profiling_p.h" +#include <private/qqmljavascriptexpression_p.h> using namespace QV4; @@ -55,29 +58,31 @@ DEFINE_MANAGED_VTABLE(CallContext); DEFINE_MANAGED_VTABLE(WithContext); DEFINE_MANAGED_VTABLE(CatchContext); DEFINE_MANAGED_VTABLE(GlobalContext); -DEFINE_MANAGED_VTABLE(QmlContext); -Heap::CallContext *ExecutionContext::newCallContext(const FunctionObject *function, CallData *callData) -{ - Q_ASSERT(function->function()); +/* Function *f, int argc */ +#define requiredMemoryForExecutionContect(f, argc) \ + ((sizeof(CallContext::Data) + 7) & ~7) + \ + sizeof(Value) * (f->compiledFunction->nLocals + qMax((uint)argc, f->nFormals)) + sizeof(CallData) +Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData *callData) +{ Heap::CallContext *c = d()->engine->memoryManager->allocManaged<CallContext>( requiredMemoryForExecutionContect(function, callData->argc)); c->init(d()->engine, Heap::ExecutionContext::Type_CallContext); - c->function = function->d(); + c->v4Function = function; - c->strictMode = function->strictMode(); - c->outer = function->scope(); + c->strictMode = function->isStrict(); + c->outer = this->d(); c->activation = 0; - c->compilationUnit = function->function()->compilationUnit; + c->compilationUnit = function->compilationUnit; c->lookups = c->compilationUnit->runtimeLookups; c->constantTable = c->compilationUnit->constants; c->locals = (Value *)((quintptr(c + 1) + 7) & ~7); - const CompiledData::Function *compiledFunction = function->function()->compiledFunction; + const CompiledData::Function *compiledFunction = function->compiledFunction; int nLocals = compiledFunction->nLocals; if (nLocals) std::fill(c->locals, c->locals + nLocals, Primitive::undefinedValue()); @@ -102,20 +107,6 @@ Heap::CatchContext *ExecutionContext::newCatchContext(Heap::String *exceptionVar return d()->engine->memoryManager->alloc<CatchContext>(d(), exceptionVarName, e); } -Heap::QmlContext *ExecutionContext::newQmlContext(QmlContextWrapper *qml) -{ - Heap::QmlContext *c = d()->engine->memoryManager->alloc<QmlContext>(this, qml); - return c; -} - -Heap::QmlContext *ExecutionContext::newQmlContext(QQmlContextData *context, QObject *scopeObject) -{ - Scope scope(this); - Scoped<QmlContextWrapper> qml(scope, QmlContextWrapper::qmlScope(scope.engine, context, scopeObject)); - Heap::QmlContext *c = d()->engine->memoryManager->alloc<QmlContext>(this, qml); - return c; -} - void ExecutionContext::createMutableBinding(String *name, bool deletable) { Scope scope(this); @@ -182,38 +173,25 @@ void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionV this->exceptionValue = exceptionValue; } -void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml) -{ - Heap::ExecutionContext::init(outerContext->engine(), Heap::ExecutionContext::Type_QmlContext); - outer = outerContext->d(); - strictMode = false; - callData = outer->callData; - lookups = outer->lookups; - constantTable = outer->constantTable; - compilationUnit = outer->compilationUnit; - - this->qml = qml->d(); -} - Identifier * const *CallContext::formals() const { - return (d()->function && d()->function->function) ? d()->function->function->internalClass->nameMap.constData() : 0; + return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() : 0; } unsigned int CallContext::formalCount() const { - return d()->function ? d()->function->formalParameterCount() : 0; + return d()->v4Function ? d()->v4Function->nFormals : 0; } Identifier * const *CallContext::variables() const { - return (d()->function && d()->function->function) ? d()->function->function->internalClass->nameMap.constData() + d()->function->formalParameterCount() : 0; + return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() + d()->v4Function->nFormals : 0; } unsigned int CallContext::variableCount() const { - return d()->function ? d()->function->varCount() : 0; + return d()->v4Function ? d()->v4Function->compiledFunction->nLocals : 0; } @@ -247,9 +225,8 @@ bool ExecutionContext::deleteProperty(String *name) case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - ScopedFunctionObject f(scope, c->function); - if (f->needsActivation() || hasWith) { - uint index = f->function()->internalClass->find(name); + if (c->v4Function && (c->v4Function->needsActivation() || hasWith)) { + uint index = c->v4Function->internalClass->find(name); if (index < UINT_MAX) // ### throw in strict mode? return false; @@ -272,7 +249,8 @@ bool ExecutionContext::deleteProperty(String *name) bool CallContext::needsOwnArguments() const { - return d()->function->needsActivation() || argc() < static_cast<int>(d()->function->formalParameterCount()); + QV4::Function *f = d()->v4Function; + return (f && f->needsActivation()) || (argc() < (f ? static_cast<int>(f->nFormals) : 0)); } void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine) @@ -304,14 +282,16 @@ void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine) break; case Heap::ExecutionContext::Type_CallContext: { QV4::Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx); + Q_ASSERT(c->v4Function); ctx->callData->thisObject.mark(engine); - for (int arg = 0; arg < qMax(ctx->callData->argc, (int)c->function->formalParameterCount()); ++arg) + for (int arg = 0; arg < qMax(ctx->callData->argc, (int)c->v4Function->nFormals); ++arg) ctx->callData->args[arg].mark(engine); - for (unsigned local = 0, lastLocal = c->function->varCount(); local < lastLocal; ++local) + for (unsigned local = 0, lastLocal = c->v4Function->compiledFunction->nLocals; local < lastLocal; ++local) c->locals[local].mark(engine); if (c->activation) c->activation->mark(engine); - c->function->mark(engine); + if (c->function) + c->function->mark(engine); break; } case Heap::ExecutionContext::Type_QmlContext: { @@ -322,6 +302,51 @@ void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine) } } +// Do a standard call with this execution context as the outer scope +void ExecutionContext::call(Scope &scope, CallData *callData, Function *function, const FunctionObject *f) +{ + ExecutionContextSaver ctxSaver(scope); + + Scoped<CallContext> ctx(scope, newCallContext(function, callData)); + if (f) + ctx->d()->function = f->d(); + scope.engine->pushContext(ctx); + + scope.result = Q_V4_PROFILE(scope.engine, function); + + if (function->hasQmlDependencies) + QQmlPropertyCapture::registerQmlDependencies(function->compiledFunction, scope); +} + +// Do a simple, fast call with this execution context as the outer scope +void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Function *function) +{ + Q_ASSERT(function->canUseSimpleFunction()); + + ExecutionContextSaver ctxSaver(scope); + + CallContext::Data ctx = CallContext::Data::createOnStack(scope.engine); + + ctx.strictMode = function->isStrict(); + ctx.callData = callData; + ctx.v4Function = function; + ctx.compilationUnit = function->compilationUnit; + ctx.lookups = function->compilationUnit->runtimeLookups; + ctx.constantTable = function->compilationUnit->constants; + ctx.outer = this->d(); + ctx.locals = scope.alloc(function->compiledFunction->nLocals); + for (int i = callData->argc; i < (int)function->nFormals; ++i) + callData->args[i] = Encode::undefined(); + + scope.engine->pushContext(&ctx); + Q_ASSERT(scope.engine->current == &ctx); + + scope.result = Q_V4_PROFILE(scope.engine, function); + + if (function->hasQmlDependencies) + QQmlPropertyCapture::registerQmlDependencies(function->compiledFunction, scope); +} + void ExecutionContext::setProperty(String *name, const Value &value) { Scope scope(this); @@ -354,13 +379,13 @@ void ExecutionContext::setProperty(String *name, const Value &value) case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - if (c->function->function) { - uint index = c->function->function->internalClass->find(name); + if (c->v4Function) { + uint index = c->v4Function->internalClass->find(name); if (index < UINT_MAX) { - if (index < c->function->formalParameterCount()) { - c->callData->args[c->function->formalParameterCount() - index - 1] = value; + if (index < c->v4Function->nFormals) { + c->callData->args[c->v4Function->nFormals - index - 1] = value; } else { - index -= c->function->formalParameterCount(); + index -= c->v4Function->nFormals; c->locals[index] = value; } return; @@ -435,13 +460,12 @@ ReturnedValue ExecutionContext::getProperty(String *name) case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - ScopedFunctionObject f(scope, c->function); - if (f->function() && (f->needsActivation() || hasWith || hasCatchScope)) { - uint index = f->function()->internalClass->find(name); + if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { + uint index = c->v4Function->internalClass->find(name); if (index < UINT_MAX) { - if (index < c->function->formalParameterCount()) - return c->callData->args[c->function->formalParameterCount() - index - 1].asReturnedValue(); - return c->locals[index - c->function->formalParameterCount()].asReturnedValue(); + if (index < c->v4Function->nFormals) + return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); + return c->locals[index - c->v4Function->nFormals].asReturnedValue(); } } ScopedObject activation(scope, c->activation); @@ -451,9 +475,9 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (hasProperty) return v->asReturnedValue(); } - if (f->function() && f->function()->isNamedExpression() - && name->equals(ScopedString(scope, f->function()->name()))) - return f.asReturnedValue(); + if (c->function && c->v4Function->isNamedExpression() + && name->equals(ScopedString(scope, c->v4Function->name()))) + return c->function->asReturnedValue(); break; } case Heap::ExecutionContext::Type_QmlContext: { @@ -514,13 +538,12 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - ScopedFunctionObject f(scope, c->function); - if (f->function() && (f->needsActivation() || hasWith || hasCatchScope)) { - uint index = f->function()->internalClass->find(name); + if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { + uint index = c->v4Function->internalClass->find(name); if (index < UINT_MAX) { - if (index < c->function->formalParameterCount()) - return c->callData->args[c->function->formalParameterCount() - index - 1].asReturnedValue(); - return c->locals[index - c->function->formalParameterCount()].asReturnedValue(); + if (index < c->v4Function->nFormals) + return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); + return c->locals[index - c->v4Function->nFormals].asReturnedValue(); } } ScopedObject activation(scope, c->activation); @@ -530,9 +553,9 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) if (hasProperty) return v->asReturnedValue(); } - if (f->function() && f->function()->isNamedExpression() - && name->equals(ScopedString(scope, f->function()->name()))) - return f.asReturnedValue(); + if (c->function && c->v4Function->isNamedExpression() + && name->equals(ScopedString(scope, c->v4Function->name()))) + return c->function->asReturnedValue(); break; } case Heap::ExecutionContext::Type_QmlContext: { @@ -551,13 +574,13 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) return engine()->throwReferenceError(n); } -Heap::FunctionObject *ExecutionContext::getFunctionObject() const +Function *ExecutionContext::getFunction() const { Scope scope(d()->engine); ScopedContext it(scope, this->d()); for (; it; it = it->d()->outer) { if (const CallContext *callCtx = it->asCallContext()) - return callCtx->d()->function; + return callCtx->d()->v4Function; else if (it->asCatchContext() || it->asWithContext()) continue; // look in the parent context for a FunctionObject else diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 0b42288ccc..c985fdb24d 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -55,8 +55,8 @@ QT_BEGIN_NAMESPACE -class QQmlContextData; class QObject; +class QQmlContextData; namespace QV4 { @@ -65,11 +65,13 @@ struct CompilationUnit; struct Function; } -struct QmlContextWrapper; +struct Function; struct Identifier; struct CallContext; struct CatchContext; struct WithContext; +struct QmlContext; +struct QmlContextWrapper; struct CallData { @@ -91,6 +93,8 @@ struct CallData namespace Heap { +struct QmlContext; + struct ExecutionContext : Base { enum ContextType { Type_GlobalContext = 0x1, @@ -137,11 +141,15 @@ struct CallContext : ExecutionContext { { ExecutionContext::init(engine, t); function = 0; + v4Function = 0; locals = 0; activation = 0; } + inline unsigned int formalParameterCount() const; + Pointer<FunctionObject> function; + QV4::Function *v4Function; Value *locals; Pointer<Object> activation; }; @@ -177,14 +185,6 @@ struct WithContext : ExecutionContext { }; V4_ASSERT_IS_TRIVIAL(WithContext) -struct QmlContextWrapper; - -struct QmlContext : ExecutionContext { - void init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml); - - Pointer<QmlContextWrapper> qml; -}; - } struct Q_QML_EXPORT ExecutionContext : public Managed @@ -198,11 +198,9 @@ struct Q_QML_EXPORT ExecutionContext : public Managed ExecutionEngine *engine() const { return d()->engine; } - Heap::CallContext *newCallContext(const FunctionObject *f, CallData *callData); + Heap::CallContext *newCallContext(Function *f, CallData *callData); Heap::WithContext *newWithContext(Heap::Object *with); Heap::CatchContext *newCatchContext(Heap::String *exceptionVarName, ReturnedValue exceptionValue); - Heap::QmlContext *newQmlContext(QmlContextWrapper *qml); - Heap::QmlContext *newQmlContext(QQmlContextData *context, QObject *scopeObject); void createMutableBinding(String *name, bool deletable); @@ -216,7 +214,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed inline const CatchContext *asCatchContext() const; inline const WithContext *asWithContext() const; - Heap::FunctionObject *getFunctionObject() const; + Function *getFunction() const; static void markObjects(Heap::Base *m, ExecutionEngine *e); @@ -232,6 +230,9 @@ struct Q_QML_EXPORT ExecutionContext : public Managed ReturnedValue argument(int i) const { return d()->callData->argument(i); } + + void call(Scope &scope, CallData *callData, QV4::Function *function, const QV4::FunctionObject *f = 0); + void simpleCall(Scope &scope, CallData *callData, QV4::Function *function); }; struct Q_QML_EXPORT CallContext : public ExecutionContext @@ -244,11 +245,11 @@ struct Q_QML_EXPORT CallContext : public ExecutionContext Identifier * const *variables() const; unsigned int variableCount() const; - inline ReturnedValue argument(int i); + inline ReturnedValue argument(int i) const; bool needsOwnArguments() const; }; -inline ReturnedValue CallContext::argument(int i) { +inline ReturnedValue CallContext::argument(int i) const { return i < argc() ? args()[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue(); } @@ -268,16 +269,6 @@ struct WithContext : public ExecutionContext V4_MANAGED(WithContext, ExecutionContext) }; -struct Q_QML_EXPORT QmlContext : public ExecutionContext -{ - V4_MANAGED(QmlContext, ExecutionContext) - - QObject *qmlScope() const; - QQmlContextData *qmlContext() const; - - void takeContextOwnership(); -}; - inline CallContext *ExecutionContext::asCallContext() { return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<CallContext *>(this) : 0; @@ -308,10 +299,6 @@ inline Heap::CallContext Heap::CallContext::createOnStack(ExecutionEngine *v4) return ctxt; } -/* Function *f, int argc */ -#define requiredMemoryForExecutionContect(f, argc) \ - ((sizeof(CallContext::Data) + 7) & ~7) + sizeof(Value) * (f->varCount() + qMax((uint)argc, f->formalParameterCount())) + sizeof(CallData) - } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4context_p_p.h b/src/qml/jsruntime/qv4context_p_p.h deleted file mode 100644 index ca8dc0b518..0000000000 --- a/src/qml/jsruntime/qv4context_p_p.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ -#ifndef QV4CONTEXT_P_P_H -#define QV4CONTEXT_P_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -// This header defines a couple of inlinable methods. -// These implementation cannot be put in qv4context_p.h, because they rely on the -// QQmlContextWrapper, which in turn is a QV4::Object subclass (so it includes qv4object_p.h), -// which includes qv4engine_p.h, that needs to include qv4context_p.h - -#include "qv4context_p.h" -#include "private/qqmlcontextwrapper_p.h" - -QT_BEGIN_NAMESPACE - -namespace QV4 { - -QObject *QmlContext::qmlScope() const -{ - return d()->qml->scopeObject; -} - -QQmlContextData *QmlContext::qmlContext() const -{ - return *d()->qml->context; -} - -void QmlContext::takeContextOwnership() { - d()->qml->ownsContext = true; -} - -} // QV4 namespace - -QT_END_NAMESPACE - -#endif // QV4CONTEXT_P_P_H diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 4f3138a452..8cc6a25fea 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -689,8 +689,8 @@ void DateCtor::construct(const Managed *, Scope &scope, CallData *callData) } else { arg = RuntimeHelpers::toPrimitive(arg, PREFERREDTYPE_HINT); - if (arg->isString()) - t = ParseString(arg->stringValue()->toQString()); + if (String *s = arg->stringValue()) + t = ParseString(s->toQString()); else t = TimeClip(arg->toNumber()); } @@ -1319,14 +1319,17 @@ ReturnedValue DatePrototype::method_toISOString(CallContext *ctx) ReturnedValue DatePrototype::method_toJSON(CallContext *ctx) { Scope scope(ctx); - ScopedValue O(scope, RuntimeHelpers::toObject(scope.engine, ctx->thisObject())); + ScopedObject O(scope, ctx->thisObject().toObject(scope.engine)); + if (scope.hasException()) + return Encode::undefined(); + ScopedValue tv(scope, RuntimeHelpers::toPrimitive(O, NUMBER_HINT)); if (tv->isNumber() && !std::isfinite(tv->toNumber())) return Encode::null(); ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toISOString"))); - ScopedValue v(scope, O->objectValue()->get(s)); + ScopedValue v(scope, O->get(s)); FunctionObject *toIso = v->as<FunctionObject>(); if (!toIso) diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index 2d0648396e..835f6adbe0 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -101,7 +101,7 @@ struct DateObject: Object { template<> inline const DateObject *Value::as() const { - return isManaged() && m() && m()->vtable()->type == Managed::Type_DateObject ? static_cast<const DateObject *>(this) : 0; + return isManaged() && m()->vtable()->type == Managed::Type_DateObject ? static_cast<const DateObject *>(this) : 0; } struct DateCtor: FunctionObject diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index a9284f2e69..2b90b43eab 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ #include <qv4engine_p.h> -#include <qv4context_p.h> +#include <qv4qmlcontext_p.h> #include <qv4value_p.h> #include <qv4object_p.h> #include <qv4objectproto_p.h> @@ -71,7 +71,6 @@ #include "qv4typedarray_p.h" #include <private/qv8engine_p.h> #include <private/qjsvalue_p.h> -#include <private/qqmlcontextwrapper_p.h> #include <private/qqmltypewrapper_p.h> #include <private/qqmlvaluetypewrapper_p.h> #include <private/qqmlvaluetype_p.h> @@ -282,10 +281,10 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) jsObjects[FunctionProto] = memoryManager->allocObject<FunctionPrototype>(functionProtoClass, objectPrototype()); functionClass = emptyClass->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); - simpleScriptFunctionClass = functionClass->addMember(id_name(), Attr_ReadOnly, &index); - Q_ASSERT(index == Heap::SimpleScriptFunction::Index_Name); - simpleScriptFunctionClass = simpleScriptFunctionClass->addMember(id_length(), Attr_ReadOnly, &index); - Q_ASSERT(index == Heap::SimpleScriptFunction::Index_Length); + scriptFunctionClass = functionClass->addMember(id_name(), Attr_ReadOnly, &index); + Q_ASSERT(index == Heap::ScriptFunction::Index_Name); + scriptFunctionClass = scriptFunctionClass->addMember(id_length(), Attr_ReadOnly, &index); + Q_ASSERT(index == Heap::ScriptFunction::Index_Length); protoClass = emptyClass->addMember(id_constructor(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor); @@ -714,6 +713,27 @@ Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o) return obj->d(); } +Heap::QmlContext *ExecutionEngine::qmlContext() const +{ + Heap::ExecutionContext *ctx = current; + + // get the correct context when we're within a builtin function + if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer) + ctx = parentContext(currentContext)->d(); + + if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !ctx->outer) + return 0; + + while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext) + ctx = ctx->outer; + + Q_ASSERT(ctx); + if (ctx->type != Heap::ExecutionContext::Type_QmlContext) + return 0; + + return static_cast<Heap::QmlContext *>(ctx); +} + QObject *ExecutionEngine::qmlScopeObject() const { Heap::QmlContext *ctx = qmlContext(); @@ -760,21 +780,17 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const QVector<StackFrame> stack; ExecutionContext *c = currentContext; - ScopedFunctionObject function(scope); while (c && frameLimit) { - function = c->getFunctionObject(); + QV4::Function *function = c->getFunction(); if (function) { StackFrame frame; - if (const Function *f = function->function()) - frame.source = f->sourceFile(); + frame.source = function->sourceFile(); name = function->name(); frame.function = name->toQString(); - frame.line = -1; - frame.column = -1; - if (function->function()) - // line numbers can be negative for places where you can't set a real breakpoint - frame.line = qAbs(c->d()->lineNumber); + // line numbers can be negative for places where you can't set a real breakpoint + frame.line = qAbs(c->d()->lineNumber); + frame.column = -1; stack.append(frame); --frameLimit; @@ -850,9 +866,8 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) ExecutionContext *c = currentContext; while (c) { CallContext *callCtx = c->asCallContext(); - if (callCtx && callCtx->d()->function) { - if (callCtx->d()->function->function) - base.setUrl(callCtx->d()->function->function->sourceFile()); + if (callCtx && callCtx->d()->v4Function) { + base.setUrl(callCtx->d()->v4Function->sourceFile()); break; } c = parentContext(c); @@ -1151,8 +1166,8 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return value.integerValue(); if (value.isNumber()) return value.asDouble(); - if (value.isString()) { - const QString &str = value.toQString(); + if (String *s = value.stringValue()) { + const QString &str = s->toQString(); // QChars are stored as a strings if (typeHint == QVariant::Char && str.size() == 1) return str.at(0); @@ -1591,8 +1606,8 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value->toInt32()); return true; case QMetaType::QChar: - if (value->isString()) { - QString str = value->stringValue()->toQString(); + if (String *s = value->stringValue()) { + QString str = s->toQString(); *reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0); } else { *reinterpret_cast<QChar*>(data) = QChar(ushort(value->toUInt16())); @@ -1704,10 +1719,10 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) // We have T t, T* is requested, so return &t. *reinterpret_cast<void* *>(data) = var.data(); return true; - } else if (value->isObject()) { + } else if (Object *o = value->objectValue()) { // Look in the prototype chain. QV4::Scope scope(this); - QV4::ScopedObject proto(scope, value->objectValue()->prototype()); + QV4::ScopedObject proto(scope, o->prototype()); while (proto) { bool canCast = false; if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) { diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 25d6fc1970..1c20ad30aa 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -128,7 +128,8 @@ public: --jsStackTop; return jsStackTop->heapObject(); } - Value *jsAlloca(int nValues) { + + QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) { Value *ptr = jsStackTop; jsStackTop = ptr + nValues; for (int i = 0; i < nValues; ++i) @@ -254,7 +255,7 @@ public: InternalClass *stringClass; InternalClass *functionClass; - InternalClass *simpleScriptFunctionClass; + InternalClass *scriptFunctionClass; InternalClass *protoClass; InternalClass *regExpExecArrayClass; @@ -547,27 +548,6 @@ inline ExecutionContext *ExecutionEngine::parentContext(ExecutionContext *contex return o ? context - o : 0; } -inline Heap::QmlContext *ExecutionEngine::qmlContext() const -{ - Heap::ExecutionContext *ctx = current; - - // get the correct context when we're within a builtin function - if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer) - ctx = parentContext(currentContext)->d(); - - if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !ctx->outer) - return 0; - - while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext) - ctx = ctx->outer; - - Q_ASSERT(ctx); - if (ctx->type != Heap::ExecutionContext::Type_QmlContext) - return 0; - - return static_cast<Heap::QmlContext *>(ctx); -} - inline void Heap::Base::mark(QV4::ExecutionEngine *engine) { @@ -583,9 +563,6 @@ void Heap::Base::mark(QV4::ExecutionEngine *engine) inline void Value::mark(ExecutionEngine *e) { - if (!isManaged()) - return; - Heap::Base *o = heapObject(); if (o) o->mark(e); diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 42a6e0b4b1..2b3ab25e2d 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -178,7 +178,7 @@ struct ErrorObject: Object { template<> inline const ErrorObject *Value::as() const { - return isManaged() && m() && m()->vtable()->isErrorObject ? reinterpret_cast<const ErrorObject *>(this) : 0; + return isManaged() && m()->vtable()->isErrorObject ? reinterpret_cast<const ErrorObject *>(this) : 0; } struct EvalErrorObject: ErrorObject { diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index caabee322a..358c2d079c 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -55,6 +55,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, , compilationUnit(unit) , code(codePtr) , codeData(0) + , hasQmlDependencies(function->hasQmlDependencies()) { Q_UNUSED(engine); @@ -83,6 +84,9 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable); activationRequired = compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject)); + + canUseSimpleCall = !needsActivation() && !(compiledFunction->flags & CompiledData::Function::HasCatchOrWith) && + !(compiledFunction->nFormals > QV4::Global::ReservedArgumentCount) && !isNamedExpression(); } Function::~Function() diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index aeef9ad61b..54d0528c42 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -51,7 +51,9 @@ // #include "qv4global_p.h" +#include <private/qqmlglobal_p.h> #include <private/qv4compileddata_p.h> +#include <private/qv4context_p.h> QT_BEGIN_NAMESPACE @@ -68,6 +70,8 @@ struct Q_QML_EXPORT Function { InternalClass *internalClass; uint nFormals; bool activationRequired; + bool hasQmlDependencies; + bool canUseSimpleCall; Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function, ReturnedValue (*codePtr)(ExecutionEngine *, const uchar *)); @@ -88,8 +92,22 @@ struct Q_QML_EXPORT Function { inline bool needsActivation() const { return activationRequired; } + inline bool canUseSimpleFunction() const { return canUseSimpleCall; } + + QQmlSourceLocation sourceLocation() const + { + return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column); + } + }; + +inline unsigned int Heap::CallContext::formalParameterCount() const +{ + return v4Function ? v4Function->nFormals : 0; +} + + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 2cc58b74a6..64f7b98618 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -47,6 +47,7 @@ #include "qv4arrayobject_p.h" #include "qv4scopedvalue_p.h" +#include "qv4argumentsobject_p.h" #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> @@ -81,7 +82,8 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function, bool createProto) { Object::init(); - function = nullptr; + this->function = function; + function->compilationUnit->addref(); this->scope = scope->d(); Scope s(scope->engine()); ScopedString name(s, function->name()); @@ -91,46 +93,9 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function void Heap::FunctionObject::init(QV4::ExecutionContext *scope, const QString &name, bool createProto) { - Object::init(); - function = nullptr; - this->scope = scope->d(); - Scope s(scope->engine()); - ScopedFunctionObject f(s, this); - ScopedString n(s, s.engine->newString(name)); - f->init(n, createProto); -} - -void Heap::FunctionObject::init(ExecutionContext *scope, const QString &name, bool createProto) -{ - Object::init(); - function = nullptr; - this->scope = scope; - Scope s(scope->engine); - ScopedFunctionObject f(s, this); - ScopedString n(s, s.engine->newString(name)); - f->init(n, createProto); -} - -void Heap::FunctionObject::init(QV4::ExecutionContext *scope, const ReturnedValue name) -{ - Object::init(); - function = nullptr; - this->scope = scope->d(); - Scope s(scope); - ScopedFunctionObject f(s, this); - ScopedString n(s, name); - f->init(n, false); -} - -void Heap::FunctionObject::init(ExecutionContext *scope, const ReturnedValue name) -{ - Object::init(); - function = nullptr; - this->scope = scope; - Scope s(scope->engine); - ScopedFunctionObject f(s, this); - ScopedString n(s, name); - f->init(n, false); + Scope valueScope(scope); + ScopedString s(valueScope, valueScope.engine->newString(name)); + init(scope, s, createProto); } void Heap::FunctionObject::init() @@ -165,8 +130,8 @@ void FunctionObject::init(String *n, bool createProto) *propertyData(Heap::FunctionObject::Index_Prototype) = Encode::undefined(); } - ScopedValue v(s, n); - defineReadonlyProperty(s.engine->id_name(), v); + if (n) + defineReadonlyProperty(s.engine->id_name(), *n); } ReturnedValue FunctionObject::name() const @@ -193,34 +158,11 @@ void FunctionObject::markObjects(Heap::Base *that, ExecutionEngine *e) Object::markObjects(that, e); } -Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function, bool createProto) +Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function) { - if (function->needsActivation() || - function->compiledFunction->flags & CompiledData::Function::HasCatchOrWith || - function->compiledFunction->nFormals > QV4::Global::ReservedArgumentCount || - function->isNamedExpression()) - return scope->d()->engine->memoryManager->allocObject<ScriptFunction>(scope, function); - return scope->d()->engine->memoryManager->allocObject<SimpleScriptFunction>(scope, function, createProto); + return scope->d()->engine->memoryManager->allocObject<ScriptFunction>(scope, function); } -Heap::FunctionObject *FunctionObject::createQmlFunction(QQmlContextData *qmlContext, QObject *scopeObject, Function *runtimeFunction, const QList<QByteArray> &signalParameters, QString *error) -{ - ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(qmlContext->engine); - QV4::Scope valueScope(engine); - ExecutionContext *global = valueScope.engine->rootContext(); - QV4::Scoped<QmlContext> wrapperContext(valueScope, global->newQmlContext(qmlContext, scopeObject)); - - if (!signalParameters.isEmpty()) { - if (error) - QQmlPropertyCache::signalParameterStringForJS(engine, signalParameters, error); - runtimeFunction->updateInternalClass(engine, signalParameters); - } - - QV4::ScopedFunctionObject function(valueScope, QV4::FunctionObject::createScriptFunction(wrapperContext, runtimeFunction)); - return function->d(); -} - - bool FunctionObject::isBinding() const { return d()->vtable() == QQmlBindingFunction::staticVTable(); @@ -233,14 +175,7 @@ bool FunctionObject::isBoundFunction() const QQmlSourceLocation FunctionObject::sourceLocation() const { - if (isBinding()) { - Q_ASSERT(as<const QV4::QQmlBindingFunction>()); - return *static_cast<QV4::Heap::QQmlBindingFunction *>(d())->bindingLocation; - } - QV4::Function *function = d()->function; - Q_ASSERT(function); - - return QQmlSourceLocation(function->sourceFile(), function->compiledFunction->location.line, function->compiledFunction->location.column); + return d()->function->sourceLocation(); } DEFINE_OBJECT_VTABLE(FunctionCtor); @@ -346,11 +281,11 @@ ReturnedValue FunctionPrototype::method_toString(CallContext *ctx) ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) { - Scope scope(ctx); - ScopedFunctionObject o(scope, ctx->thisObject().as<FunctionObject>()); + FunctionObject *o = ctx->thisObject().as<FunctionObject>(); if (!o) return ctx->engine()->throwTypeError(); + Scope scope(ctx); ScopedValue arg(scope, ctx->argument(1)); ScopedObject arr(scope, arg); @@ -367,17 +302,24 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) ScopedCallData callData(scope, len); if (len) { - if (arr->arrayType() != Heap::ArrayData::Simple || arr->protoHasArray()) { - for (quint32 i = 0; i < len; ++i) - callData->args[i] = arr->getIndexed(i); - } else { - uint alen = arr->arrayData() ? arr->arrayData()->len : 0; + if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast<ArgumentsObject>()->fullyCreated()) { + QV4::ArgumentsObject *a = arr->cast<ArgumentsObject>(); + int l = qMin(len, (uint)a->d()->context->callData->argc); + memcpy(callData->args, a->d()->context->callData->args, l*sizeof(Value)); + for (quint32 i = l; i < len; ++i) + callData->args[i] = Primitive::undefinedValue(); + } else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) { + auto sad = static_cast<Heap::SimpleArrayData *>(arr->arrayData()); + uint alen = sad ? sad->len : 0; if (alen > len) alen = len; for (uint i = 0; i < alen; ++i) - callData->args[i] = static_cast<Heap::SimpleArrayData *>(arr->arrayData())->data(i); + callData->args[i] = sad->data(i); for (quint32 i = alen; i < len; ++i) callData->args[i] = Primitive::undefinedValue(); + } else { + for (quint32 i = 0; i < len; ++i) + callData->args[i] = arr->getIndexed(i); } } @@ -388,12 +330,11 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) ReturnedValue FunctionPrototype::method_call(CallContext *ctx) { - Scope scope(ctx); - - ScopedFunctionObject o(scope, ctx->thisObject().as<FunctionObject>()); + FunctionObject *o = ctx->thisObject().as<FunctionObject>(); if (!o) return ctx->engine()->throwTypeError(); + Scope scope(ctx); ScopedCallData callData(scope, ctx->argc() ? ctx->argc() - 1 : 0); if (ctx->argc()) { for (int i = 1; i < ctx->argc(); ++i) @@ -407,11 +348,11 @@ ReturnedValue FunctionPrototype::method_call(CallContext *ctx) ReturnedValue FunctionPrototype::method_bind(CallContext *ctx) { - Scope scope(ctx); - ScopedFunctionObject target(scope, ctx->thisObject()); + FunctionObject *target = ctx->thisObject().as<FunctionObject>(); if (!target) return ctx->engine()->throwTypeError(); + Scope scope(ctx); ScopedValue boundThis(scope, ctx->argument(0)); Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)0); if (ctx->argc() > 1) { @@ -426,15 +367,10 @@ ReturnedValue FunctionPrototype::method_bind(CallContext *ctx) DEFINE_OBJECT_VTABLE(ScriptFunction); -void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function) -{ - Heap::SimpleScriptFunction::init(scope, function, true); -} - void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *callData) { ExecutionEngine *v4 = scope.engine; - if (v4->hasException) { + if (Q_UNLIKELY(v4->hasException)) { scope.result = Encode::undefined(); return; } @@ -447,17 +383,18 @@ void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *call InternalClass *ic = v4->emptyClass; ScopedObject proto(scope, f->protoForConstructor()); ScopedObject obj(scope, v4->newObject(ic, proto)); - callData->thisObject = obj.asReturnedValue(); - Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData)); - v4->pushContext(ctx); - scope.result = Q_V4_PROFILE(v4, f->function()); + QV4::Function *v4Function = f->function(); + Q_ASSERT(v4Function); - if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); + ScopedContext c(scope, f->scope()); + if (v4Function->canUseSimpleCall) + c->simpleCall(scope, callData, v4Function); + else + c->call(scope, callData, v4Function, f); - if (v4->hasException) { + if (Q_UNLIKELY(v4->hasException)) { scope.result = Encode::undefined(); } else if (!scope.result.isObject()) { scope.result = obj.asReturnedValue(); @@ -467,27 +404,25 @@ void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *call void ScriptFunction::call(const Managed *that, Scope &scope, CallData *callData) { ExecutionEngine *v4 = scope.engine; - if (v4->hasException) { + if (Q_UNLIKELY(v4->hasException)) { scope.result = Encode::undefined(); return; } CHECK_STACK_LIMITS(v4, scope); - ExecutionContextSaver ctxSaver(scope); - Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); - Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData)); - v4->pushContext(ctx); - scope.result = Q_V4_PROFILE(v4, f->function()); + QV4::Function *v4Function = f->function(); + Q_ASSERT(v4Function); - if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); + ScopedContext c(scope, f->scope()); + if (v4Function->canUseSimpleCall) + c->simpleCall(scope, callData, v4Function); + else + c->call(scope, callData, v4Function, f); } -DEFINE_OBJECT_VTABLE(SimpleScriptFunction); - -void Heap::SimpleScriptFunction::init(QV4::ExecutionContext *scope, Function *function, bool createProto) +void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function) { FunctionObject::init(); this->scope = scope->d(); @@ -500,16 +435,10 @@ void Heap::SimpleScriptFunction::init(QV4::ExecutionContext *scope, Function *fu Scope s(scope); ScopedFunctionObject f(s, this); - if (createProto) { - ScopedString name(s, function->name()); - f->init(name, createProto); - f->defineReadonlyProperty(scope->d()->engine->id_length(), Primitive::fromInt32(f->formalParameterCount())); - } else { - Q_ASSERT(internalClass && internalClass->find(s.engine->id_length()) == Index_Length); - Q_ASSERT(internalClass && internalClass->find(s.engine->id_name()) == Index_Name); - *propertyData(Index_Name) = function->name(); - *propertyData(Index_Length) = Primitive::fromInt32(f->formalParameterCount()); - } + ScopedString name(s, function->name()); + f->init(name, true); + Q_ASSERT(internalClass && internalClass->find(s.engine->id_length()) == Index_Length); + *propertyData(Index_Length) = Primitive::fromInt32(f->formalParameterCount()); if (scope->d()->strictMode) { ScopedProperty pd(s); @@ -520,89 +449,12 @@ void Heap::SimpleScriptFunction::init(QV4::ExecutionContext *scope, Function *fu } } -void SimpleScriptFunction::construct(const Managed *that, Scope &scope, CallData *callData) -{ - ExecutionEngine *v4 = scope.engine; - if (v4->hasException) { - scope.result = Encode::undefined(); - return; - } - CHECK_STACK_LIMITS(v4, scope); - - ExecutionContextSaver ctxSaver(scope); - - Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); - - InternalClass *ic = scope.engine->emptyClass; - ScopedObject proto(scope, f->protoForConstructor()); - callData->thisObject = v4->newObject(ic, proto); - - CallContext::Data ctx = CallContext::Data::createOnStack(v4); - ctx.strictMode = f->strictMode(); - ctx.callData = callData; - ctx.function = f->d(); - ctx.compilationUnit = f->function()->compilationUnit; - ctx.lookups = ctx.compilationUnit->runtimeLookups; - ctx.constantTable = ctx.compilationUnit->constants; - ctx.outer = f->scope(); - ctx.locals = scope.alloc(f->varCount()); - for (int i = callData->argc; i < (int)f->formalParameterCount(); ++i) - callData->args[i] = Encode::undefined(); - v4->pushContext(&ctx); - Q_ASSERT(v4->current == &ctx); - - scope.result = Q_V4_PROFILE(v4, f->function()); - - if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); - - if (v4->hasException) { - scope.result = Encode::undefined(); - } else if (!scope.result.isObject()) { - scope.result = callData->thisObject; - } -} - -void SimpleScriptFunction::call(const Managed *that, Scope &scope, CallData *callData) -{ - ExecutionEngine *v4 = scope.engine; - if (v4->hasException) { - scope.result = Encode::undefined(); - return; - } - CHECK_STACK_LIMITS(v4, scope); - - ExecutionContextSaver ctxSaver(scope); - - Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); - - CallContext::Data ctx = CallContext::Data::createOnStack(v4); - ctx.strictMode = f->strictMode(); - ctx.callData = callData; - ctx.function = f->d(); - ctx.compilationUnit = f->function()->compilationUnit; - ctx.lookups = ctx.compilationUnit->runtimeLookups; - ctx.constantTable = ctx.compilationUnit->constants; - ctx.outer = f->scope(); - ctx.locals = scope.alloc(f->varCount()); - for (int i = callData->argc; i < (int)f->formalParameterCount(); ++i) - callData->args[i] = Encode::undefined(); - v4->pushContext(&ctx); - Q_ASSERT(v4->current == &ctx); - - scope.result = Q_V4_PROFILE(v4, f->function()); - - if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); -} - -Heap::Object *SimpleScriptFunction::protoForConstructor() +Heap::Object *ScriptFunction::protoForConstructor() const { - Scope scope(engine()); - ScopedObject p(scope, protoProperty()); - if (p) - return p->d(); - return scope.engine->objectPrototype()->d(); + const Object *o = d()->protoProperty(); + if (o) + return o->d(); + return engine()->objectPrototype()->d(); } diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index e58b83e2c3..a02e89e883 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -69,12 +69,9 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { Index_ProtoConstructor = 0 }; - void init(QV4::ExecutionContext *scope, QV4::String *name, bool createProto = false); + void init(QV4::ExecutionContext *scope, QV4::String *name = 0, bool createProto = false); void init(QV4::ExecutionContext *scope, QV4::Function *function, bool createProto = false); - void init(QV4::ExecutionContext *scope, const QString &name = QString(), bool createProto = false); - void init(ExecutionContext *scope, const QString &name = QString(), bool createProto = false); - void init(QV4::ExecutionContext *scope, const ReturnedValue name); - void init(ExecutionContext *scope, const ReturnedValue name); + void init(QV4::ExecutionContext *scope, const QString &name, bool createProto = false); void init(); void destroy(); @@ -82,6 +79,8 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; } bool needsActivation() const { return function ? function->needsActivation() : false; } + const QV4::Object *protoProperty() const { return propertyData(Index_Prototype)->cast<QV4::Object>(); } + Pointer<ExecutionContext> scope; Function *function; }; @@ -105,15 +104,11 @@ struct IndexedBuiltinFunction : FunctionObject { uint index; }; -struct SimpleScriptFunction : FunctionObject { +struct ScriptFunction : FunctionObject { enum { Index_Name = FunctionObject::Index_Prototype + 1, Index_Length }; - void init(QV4::ExecutionContext *scope, Function *function, bool createProto); -}; - -struct ScriptFunction : SimpleScriptFunction { void init(QV4::ExecutionContext *scope, Function *function); }; @@ -150,11 +145,7 @@ struct Q_QML_EXPORT FunctionObject: Object { static void construct(const Managed *that, Scope &scope, CallData *); static void call(const Managed *that, Scope &scope, CallData *d); - static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true); - static Heap::FunctionObject *createQmlFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction, - const QList<QByteArray> &signalParameters = QList<QByteArray>(), QString *error = 0); - - ReturnedValue protoProperty() { return propertyData(Heap::FunctionObject::Index_Prototype)->asReturnedValue(); } + static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function); bool needsActivation() const { return d()->needsActivation(); } bool strictMode() const { return d()->function ? d()->function->isStrict() : false; } @@ -168,7 +159,7 @@ struct Q_QML_EXPORT FunctionObject: Object { template<> inline const FunctionObject *Value::as() const { - return isManaged() && m() && m()->vtable()->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : 0; + return isManaged() && m()->vtable()->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : 0; } @@ -225,21 +216,14 @@ void Heap::IndexedBuiltinFunction::init(QV4::ExecutionContext *scope, uint index } -struct SimpleScriptFunction: FunctionObject { - V4_OBJECT2(SimpleScriptFunction, FunctionObject) - V4_INTERNALCLASS(simpleScriptFunctionClass) - - static void construct(const Managed *, Scope &scope, CallData *callData); - static void call(const Managed *that, Scope &scope, CallData *callData); - - Heap::Object *protoForConstructor(); -}; - -struct ScriptFunction: SimpleScriptFunction { +struct ScriptFunction : FunctionObject { V4_OBJECT2(ScriptFunction, FunctionObject) + V4_INTERNALCLASS(scriptFunctionClass) static void construct(const Managed *, Scope &scope, CallData *callData); static void call(const Managed *that, Scope &scope, CallData *callData); + + Heap::Object *protoForConstructor() const; }; diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 184375a9b6..c37ad1668d 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -58,6 +58,12 @@ #include <QtCore/qglobal.h> #include <QString> +#ifdef QT_NO_DEBUG +#define QML_NEARLY_ALWAYS_INLINE Q_ALWAYS_INLINE +#else +#define QML_NEARLY_ALWAYS_INLINE inline +#endif + #ifdef V4_BOOTSTRAP #include <private/qtqmldevtoolsglobal_p.h> #else diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index feb0d90d26..af92ce1ad8 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -357,12 +357,13 @@ void EvalFunction::evalCall(Scope &scope, CallData *callData, bool directCall) c ctx = v4->pushGlobalContext(); } - if (!callData->args[0].isString()) { + String *scode = callData->args[0].stringValue(); + if (!scode) { scope.result = callData->args[0].asReturnedValue(); return; } - const QString code = callData->args[0].stringValue()->toQString(); + const QString code = scode->toQString(); bool inheritContext = !ctx->d()->strictMode; Script script(ctx, code, QStringLiteral("eval code")); diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index be8057e9f5..1d393cf0aa 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -53,7 +53,6 @@ #include <private/qv4functionobject_p.h> #include <private/qv4script_p.h> #include <private/qv4context_p.h> -#include <private/qqmlcontextwrapper_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 94a6e4daa1..d79e6242ba 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -727,8 +727,8 @@ QString Stringify::Str(const QString &key, const Value &v) return QStringLiteral("null"); if (scope.result.isBoolean()) return scope.result.booleanValue() ? QStringLiteral("true") : QStringLiteral("false"); - if (scope.result.isString()) - return quote(scope.result.stringValue()->toQString()); + if (String *s = scope.result.stringValue()) + return quote(s->toQString()); if (scope.result.isNumber()) { double d = scope.result.toNumber(); @@ -917,7 +917,7 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx) Value *v = stringify.propertyList + i; *v = o->getIndexed(i); if (v->as<NumberObject>() || v->as<StringObject>() || v->isNumber()) - *v = RuntimeHelpers::toString(scope.engine, *v); + *v = v->toString(scope.engine); if (!v->isString()) { v->setM(0); } else { @@ -940,8 +940,8 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx) if (s->isNumber()) { stringify.gap = QString(qMin(10, (int)s->toInteger()), ' '); - } else if (s->isString()) { - stringify.gap = s->stringValue()->toQString().left(10); + } else if (String *str = s->stringValue()) { + stringify.gap = str->toQString().left(10); } @@ -982,8 +982,8 @@ QJsonValue JsonObject::toJsonValue(const Value &value, V4ObjectSet &visitedObjec return QJsonValue(QJsonValue::Null); else if (value.isUndefined()) return QJsonValue(QJsonValue::Undefined); - else if (value.isString()) - return QJsonValue(value.toQString()); + else if (String *s = value.stringValue()) + return QJsonValue(s->toQString()); Q_ASSERT(value.isObject()); Scope scope(value.as<Object>()->engine()); diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 84755a6402..52ed449664 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -118,7 +118,8 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs ReturnedValue Lookup::indexedGetterGeneric(Lookup *l, const Value &object, const Value &index) { - if (object.isObject() && index.asArrayIndex() < UINT_MAX) { + uint idx; + if (object.isObject() && index.asArrayIndex(idx)) { l->indexedGetter = indexedGetterObjectInt; return indexedGetterObjectInt(l, object, index); } @@ -129,11 +130,12 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons { Q_UNUSED(l); Scope scope(l->engine); - uint idx = index.asArrayIndex(); + uint idx = 0; + bool isInt = index.asArrayIndex(idx); ScopedObject o(scope, object); if (!o) { - if (idx < UINT_MAX) { + if (isInt) { if (const String *str = object.as<String>()) { if (idx >= (uint)str->toQString().length()) { return Encode::undefined(); @@ -153,7 +155,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons return Encode::undefined(); } - if (idx < UINT_MAX) { + if (isInt) { if (o->d()->arrayData && !o->d()->arrayData->attrs) { ScopedValue v(scope, Scoped<ArrayData>(scope, o->arrayData())->get(idx)); if (!v->isEmpty()) @@ -173,16 +175,19 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, const Value &index) { - uint idx = index.asArrayIndex(); - if (idx == UINT_MAX || !object.isObject()) - return indexedGetterFallback(l, object, index); - - Object *o = object.objectValue(); - if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { - Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); - if (idx < s->len) - if (!s->data(idx).isEmpty()) - return s->data(idx).asReturnedValue(); + uint idx; + if (index.asArrayIndex(idx)) { + if (Heap::Base *b = object.heapObject()) { + if (b->vtable()->isObject) { + Heap::Object *o = static_cast<Heap::Object *>(b); + if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) { + Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>(); + if (idx < s->len) + if (!s->data(idx).isEmpty()) + return s->data(idx).asReturnedValue(); + } + } + } } return indexedGetterFallback(l, object, index); @@ -190,9 +195,9 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con void Lookup::indexedSetterGeneric(Lookup *l, const Value &object, const Value &index, const Value &v) { - if (object.isObject()) { - Object *o = object.objectValue(); - if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple && index.asArrayIndex() < UINT_MAX) { + if (Object *o = object.objectValue()) { + uint idx; + if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple && index.asArrayIndex(idx)) { l->indexedSetter = indexedSetterObjectInt; indexedSetterObjectInt(l, object, index, v); return; @@ -208,8 +213,8 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value & if (scope.engine->hasException) return; - uint idx = index.asArrayIndex(); - if (idx < UINT_MAX) { + uint idx; + if (index.asArrayIndex(idx)) { if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (idx < s->len) { @@ -227,18 +232,19 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value & void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value &index, const Value &v) { - uint idx = index.asArrayIndex(); - if (idx == UINT_MAX || !object.isObject()) { - indexedSetterGeneric(l, object, index, v); - return; - } - - Object *o = object.objectValue(); - if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { - Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); - if (idx < s->len) { - s->data(idx) = v; - return; + uint idx; + if (index.asArrayIndex(idx)) { + if (Heap::Base *b = object.heapObject()) { + if (b->vtable()->isObject) { + Heap::Object *o = static_cast<Heap::Object *>(b); + if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) { + Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>(); + if (idx < s->len) { + s->data(idx) = v; + return; + } + } + } } } indexedSetterFallback(l, object, index, v); @@ -345,11 +351,11 @@ ReturnedValue Lookup::getterFallback(Lookup *l, ExecutionEngine *engine, const V ReturnedValue Lookup::getter0(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Object *o = object.objectValue(); - if (l->classList[0] == o->internalClass()) + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass) return o->propertyData(l->index)->asReturnedValue(); } return getterTwoClasses(l, engine, object); @@ -357,25 +363,24 @@ ReturnedValue Lookup::getter0(Lookup *l, ExecutionEngine *engine, const Value &o ReturnedValue Lookup::getter1(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Object *o = object.objectValue(); - if (l->classList[0] == o->internalClass() && - l->classList[1] == o->prototype()->internalClass) - return o->prototype()->propertyData(l->index)->asReturnedValue(); + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass && l->classList[1] == o->prototype->internalClass) + return o->prototype->propertyData(l->index)->asReturnedValue(); } return getterTwoClasses(l, engine, object); } ReturnedValue Lookup::getter2(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Object *o = object.objectValue(); - if (l->classList[0] == o->internalClass()) { - Heap::Object *p = o->prototype(); + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass) { + Heap::Object *p = o->prototype; if (l->classList[1] == p->internalClass) { p = p->prototype; if (l->classList[2] == p->internalClass) @@ -389,13 +394,13 @@ ReturnedValue Lookup::getter2(Lookup *l, ExecutionEngine *engine, const Value &o ReturnedValue Lookup::getter0getter0(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Object *o = object.objectValue(); - if (l->classList[0] == o->internalClass()) + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass) return o->propertyData(l->index)->asReturnedValue(); - if (l->classList[2] == o->internalClass()) + if (l->classList[2] == o->internalClass) return o->propertyData(l->index2)->asReturnedValue(); } l->getter = getterFallback; @@ -404,15 +409,14 @@ ReturnedValue Lookup::getter0getter0(Lookup *l, ExecutionEngine *engine, const V ReturnedValue Lookup::getter0getter1(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Object *o = object.objectValue(); - if (l->classList[0] == o->internalClass()) + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass) return o->propertyData(l->index)->asReturnedValue(); - if (l->classList[2] == o->internalClass() && - l->classList[3] == o->prototype()->internalClass) - return o->prototype()->propertyData(l->index2)->asReturnedValue(); + if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype->internalClass) + return o->prototype->propertyData(l->index2)->asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, engine, object); @@ -420,16 +424,16 @@ ReturnedValue Lookup::getter0getter1(Lookup *l, ExecutionEngine *engine, const V ReturnedValue Lookup::getter1getter1(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Object *o = object.objectValue(); - if (l->classList[0] == o->internalClass() && - l->classList[1] == o->prototype()->internalClass) - return o->prototype()->propertyData(l->index)->asReturnedValue(); - if (l->classList[2] == o->internalClass() && - l->classList[3] == o->prototype()->internalClass) - return o->prototype()->propertyData(l->index2)->asReturnedValue(); + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass && + l->classList[1] == o->prototype->internalClass) + return o->prototype->propertyData(l->index)->asReturnedValue(); + if (l->classList[2] == o->internalClass && + l->classList[3] == o->prototype->internalClass) + return o->prototype->propertyData(l->index2)->asReturnedValue(); return getterFallback(l, engine, object); } l->getter = getterFallback; @@ -439,12 +443,12 @@ ReturnedValue Lookup::getter1getter1(Lookup *l, ExecutionEngine *engine, const V ReturnedValue Lookup::getterAccessor0(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Object *o = object.objectValue(); - if (l->classList[0] == o->internalClass()) { - Scope scope(o->engine()); + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass) { + Scope scope(o->internalClass->engine); ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -461,10 +465,10 @@ ReturnedValue Lookup::getterAccessor0(Lookup *l, ExecutionEngine *engine, const ReturnedValue Lookup::getterAccessor1(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Heap::Object *o = object.objectValue()->d(); + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { if (l->classList[0] == o->internalClass && l->classList[1] == o->prototype->internalClass) { Scope scope(o->internalClass->engine); @@ -484,10 +488,10 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, ExecutionEngine *engine, const ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Heap::Object *o = object.objectValue()->d(); + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { if (l->classList[0] == o->internalClass) { o = o->prototype; if (l->classList[1] == o->internalClass) { diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 28b255bd9a..5c764e7ff0 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -206,6 +206,18 @@ public: bool markBit() const { return d()->isMarked(); } static void destroy(Heap::Base *) {} + + Q_ALWAYS_INLINE Heap::Base *heapObject() const { + return m(); + } + + template<typename T> inline T *cast() { + return static_cast<T *>(this); + } + template<typename T> inline const T *cast() const { + return static_cast<const T *>(this); + } + private: friend class MemoryManager; friend struct Identifiers; @@ -215,14 +227,12 @@ private: template<> inline const Managed *Value::as() const { - if (isManaged()) - return managed(); - return 0; + return managed(); } template<> inline const Object *Value::as() const { - return isManaged() && m() && m()->vtable()->isObject ? objectValue() : 0; + return objectValue(); } } diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index 5646a44891..d5f75415cc 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -52,30 +52,16 @@ void MemberData::markObjects(Heap::Base *that, ExecutionEngine *e) m->data[i].mark(e); } -static Heap::MemberData *reallocateHelper(ExecutionEngine *e, Heap::MemberData *old, uint n) +Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberData *old) { + Q_ASSERT(!old || old->size < n); + uint alloc = sizeof(Heap::MemberData) + (n)*sizeof(Value); - Scope scope(e); - Scoped<MemberData> newMemberData(scope, e->memoryManager->allocManaged<MemberData>(alloc)); + Heap::MemberData *m = e->memoryManager->allocManaged<MemberData>(alloc); if (old) - memcpy(newMemberData->d_unchecked(), old, sizeof(Heap::MemberData) + old->size * sizeof(Value)); + memcpy(m, old, sizeof(Heap::MemberData) + old->size * sizeof(Value)); else - newMemberData->d_unchecked()->init(); - newMemberData->d()->size = n; - return newMemberData->d(); -} - -Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n) -{ - return reallocateHelper(e, 0, n); -} - -Heap::MemberData *MemberData::reallocate(ExecutionEngine *e, Heap::MemberData *old, uint n) -{ - uint s = old ? old->size : 0; - if (n < s) - return old; - - // n is multiplied by two to leave room for growth - return reallocateHelper(e, old, qMax((uint)4, 2*n)); + m->init(); + m->size = n; + return m; } diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index 969eee3619..5c89dfe8ec 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -79,8 +79,7 @@ struct MemberData : Managed Value *data() { return d()->data; } inline uint size() const { return d()->size; } - static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n); - static Heap::MemberData *reallocate(QV4::ExecutionEngine *e, Heap::MemberData *old, uint n); + static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = 0); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index 1733df34ae..5b5aa29d55 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -283,7 +283,7 @@ ReturnedValue NumberPrototype::method_toPrecision(CallContext *ctx) return Encode::undefined(); if (!ctx->argc() || ctx->args()[0].isUndefined()) - return RuntimeHelpers::toString(scope.engine, v); + return Encode(v->toString(scope.engine)); int precision = ctx->args()[0].toInt32(); if (precision < 1 || precision > 21) { diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 00e6d230da..8acca16dd0 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -61,7 +61,9 @@ DEFINE_OBJECT_VTABLE(Object); void Object::setInternalClass(InternalClass *ic) { d()->internalClass = ic; - ensureMemberData(); + if ((ic->size > d()->inlineMemberSize && !d()->memberData) || + (d()->memberData && d()->memberData->size < ic->size - d()->inlineMemberSize)) + d()->memberData = MemberData::allocate(ic->engine, ic->size - d()->inlineMemberSize, d()->memberData); } void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) const @@ -225,13 +227,6 @@ void Object::markObjects(Heap::Base *that, ExecutionEngine *e) o->prototype->mark(e); } -void Object::ensureMemberData() -{ - QV4::InternalClass *ic = internalClass(); - if (ic->size > d()->inlineMemberSize) - d()->memberData = MemberData::reallocate(ic->engine, d()->memberData, ic->size - d()->inlineMemberSize); -} - void Object::insertMember(String *s, const Property *p, PropertyAttributes attributes) { uint idx; diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 00a004ef5f..6c679deb10 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -367,8 +367,6 @@ protected: static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); static uint getLength(const Managed *m); - void ensureMemberData(); - private: ReturnedValue internalGet(String *name, bool *hasProperty) const; ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const; @@ -500,7 +498,7 @@ inline void Object::arraySet(uint index, const Value &value) template<> inline const ArrayObject *Value::as() const { - return isManaged() && m() && m()->vtable()->type == Managed::Type_ArrayObject ? static_cast<const ArrayObject *>(this) : 0; + return isManaged() && m()->vtable()->type == Managed::Type_ArrayObject ? static_cast<const ArrayObject *>(this) : 0; } #ifndef V4_BOOTSTRAP diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index 7943a13ac0..59115dfe21 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -70,15 +70,16 @@ void ObjectIterator::next(Value *name, uint *index, Property *pd, PropertyAttrib ScopedString n(scope); while (1) { - if (!current->as<Object>()) + Object *co = current->objectValue(); + if (!co) break; while (1) { - current->as<Object>()->advanceIterator(this, name, index, pd, attrs); + co->advanceIterator(this, name, index, pd, attrs); if (attrs->isEmpty()) break; // check the property is not already defined earlier in the proto chain - if (current->heapObject() != object->heapObject()) { + if (co->heapObject() != object->heapObject()) { o = object->as<Object>(); n = *name; bool shadowed = false; @@ -97,7 +98,7 @@ void ObjectIterator::next(Value *name, uint *index, Property *pd, PropertyAttrib } if (flags & WithProtoChain) - current->setM(current->objectValue()->prototype()); + current->setM(co->prototype()); else current->setM(0); @@ -109,7 +110,8 @@ void ObjectIterator::next(Value *name, uint *index, Property *pd, PropertyAttrib ReturnedValue ObjectIterator::nextPropertyName(Value *value) { - if (!object->as<Object>()) + Object *o = object->objectValue(); + if (!o) return Encode::null(); PropertyAttributes attrs; @@ -121,7 +123,7 @@ ReturnedValue ObjectIterator::nextPropertyName(Value *value) if (attrs.isEmpty()) return Encode::null(); - *value = object->objectValue()->getValue(p->value, attrs); + *value = o->getValue(p->value, attrs); if (!!name) return name->asReturnedValue(); @@ -131,7 +133,8 @@ ReturnedValue ObjectIterator::nextPropertyName(Value *value) ReturnedValue ObjectIterator::nextPropertyNameAsString(Value *value) { - if (!object->as<Object>()) + Object *o = object->objectValue(); + if (!o) return Encode::null(); PropertyAttributes attrs; @@ -143,7 +146,7 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString(Value *value) if (attrs.isEmpty()) return Encode::null(); - *value = object->objectValue()->getValue(p->value, attrs); + *value = o->getValue(p->value, attrs); if (!!name) return name->asReturnedValue(); diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 6020c48250..8191083544 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -62,26 +62,24 @@ void Heap::ObjectCtor::init(QV4::ExecutionContext *scope) void ObjectCtor::construct(const Managed *that, Scope &scope, CallData *callData) { const ObjectCtor *ctor = static_cast<const ObjectCtor *>(that); - ExecutionEngine *v4 = ctor->engine(); if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) { - ScopedObject obj(scope, v4->newObject()); - ScopedObject proto(scope, ctor->get(v4->id_prototype())); + ScopedObject obj(scope, scope.engine->newObject()); + ScopedObject proto(scope, ctor->get(scope.engine->id_prototype())); if (!!proto) obj->setPrototype(proto); scope.result = obj.asReturnedValue(); } else { - scope.result = RuntimeHelpers::toObject(scope.engine, callData->args[0]); + scope.result = callData->args[0].toObject(scope.engine); } } -void ObjectCtor::call(const Managed *m, Scope &scope, CallData *callData) +void ObjectCtor::call(const Managed *, Scope &scope, CallData *callData) { - const ObjectCtor *ctor = static_cast<const ObjectCtor *>(m); - ExecutionEngine *v4 = ctor->engine(); + ExecutionEngine *v4 = scope.engine; if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) { scope.result = v4->newObject()->asReturnedValue(); } else { - scope.result = RuntimeHelpers::toObject(v4, callData->args[0]); + scope.result = callData->args[0].toObject(v4); } } @@ -398,7 +396,7 @@ ReturnedValue ObjectPrototype::method_toString(CallContext *ctx) } else if (ctx->thisObject().isNull()) { return ctx->d()->engine->newString(QStringLiteral("[object Null]"))->asReturnedValue(); } else { - ScopedObject obj(scope, RuntimeHelpers::toObject(scope.engine, ctx->thisObject())); + ScopedObject obj(scope, ctx->thisObject().toObject(scope.engine)); QString className = obj->className(); return ctx->d()->engine->newString(QStringLiteral("[object %1]").arg(className))->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index e06cb64a61..f75ac4d33a 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -86,7 +86,7 @@ QT_END_NAMESPACE engine->profiler()->trackDealloc(size, type) : false) #define Q_V4_PROFILE(engine, function)\ - (engine->profiler() &&\ + (Q_UNLIKELY(engine->profiler()) &&\ (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureFunctionCall)) ?\ Profiling::FunctionCallProfiler::profileCall(engine->profiler(), engine, function) :\ function->code(engine, function->codeData)) @@ -158,12 +158,11 @@ public: FunctionCall &operator=(const FunctionCall &other) { if (&other != this) { - if (m_function) - m_function->compilationUnit->release(); + other.m_function->compilationUnit->addref(); + m_function->compilationUnit->release(); m_function = other.m_function; m_start = other.m_start; m_end = other.m_end; - m_function->compilationUnit->addref(); } return *this; } diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h index 50e8f0ae7f..5069d7690b 100644 --- a/src/qml/jsruntime/qv4property_p.h +++ b/src/qml/jsruntime/qv4property_p.h @@ -87,8 +87,8 @@ struct Property { inline bool isSubset(const PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const; inline void merge(PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs); - inline Heap::FunctionObject *getter() const { return value.isManaged() ? reinterpret_cast<Heap::FunctionObject *>(value.heapObject()) : 0; } - inline Heap::FunctionObject *setter() const { return set.isManaged() ? reinterpret_cast<Heap::FunctionObject *>(set.heapObject()) : 0; } + inline Heap::FunctionObject *getter() const { return reinterpret_cast<Heap::FunctionObject *>(value.heapObject()); } + inline Heap::FunctionObject *setter() const { return reinterpret_cast<Heap::FunctionObject *>(set.heapObject()); } inline void setGetter(FunctionObject *g) { value = reinterpret_cast<Managed *>(g); } inline void setSetter(FunctionObject *s) { set = (s ? reinterpret_cast<Managed *>(s) : 0); } diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index 2418003519..889f4ea288 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ -#include "qqmlcontextwrapper_p.h" +#include "qv4qmlcontext_p.h" #include <private/qv8engine_p.h> #include <private/qqmlengine_p.h> @@ -60,6 +60,7 @@ QT_BEGIN_NAMESPACE using namespace QV4; DEFINE_OBJECT_VTABLE(QmlContextWrapper); +DEFINE_MANAGED_VTABLE(QmlContext); void Heap::QmlContextWrapper::init(QQmlContextData *context, QObject *scopeObject, bool ownsContext) { @@ -80,29 +81,6 @@ void Heap::QmlContextWrapper::destroy() Object::destroy(); } -ReturnedValue QmlContextWrapper::qmlScope(ExecutionEngine *v4, QQmlContextData *ctxt, QObject *scope) -{ - Scope valueScope(v4); - - Scoped<QmlContextWrapper> w(valueScope, v4->memoryManager->allocObject<QmlContextWrapper>(ctxt, scope)); - return w.asReturnedValue(); -} - -ReturnedValue QmlContextWrapper::urlScope(ExecutionEngine *v4, const QUrl &url) -{ - Scope scope(v4); - - QQmlContextData *context = new QQmlContextData; - context->baseUrl = url; - context->baseUrlString = url.toString(); - context->isInternal = true; - context->isJSContext = true; - - Scoped<QmlContextWrapper> w(scope, v4->memoryManager->allocObject<QmlContextWrapper>(context, (QObject*)0, true)); - w->d()->isNullWrapper = true; - return w.asReturnedValue(); -} - ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QmlContextWrapper>()); @@ -320,4 +298,49 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) Object::put(m, name, value); } +void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml) +{ + Heap::ExecutionContext::init(outerContext->engine(), Heap::ExecutionContext::Type_QmlContext); + outer = outerContext->d(); + strictMode = false; + callData = outer->callData; + lookups = outer->lookups; + constantTable = outer->constantTable; + compilationUnit = outer->compilationUnit; + + this->qml = qml->d(); +} + +Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, const QUrl &source, Value *sendFunction) +{ + Scope scope(parent); + + QQmlContextData *context = new QQmlContextData; + context->baseUrl = source; + context->baseUrlString = source.toString(); + context->isInternal = true; + context->isJSContext = true; + + Scoped<QmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QmlContextWrapper>(context, (QObject*)0, true)); + qml->d()->isNullWrapper = true; + + qml->setReadOnly(false); + QV4::ScopedObject api(scope, scope.engine->newObject()); + api->put(QV4::ScopedString(scope, scope.engine->newString(QStringLiteral("sendMessage"))), *sendFunction); + qml->QV4::Object::put(QV4::ScopedString(scope, scope.engine->newString(QStringLiteral("WorkerScript"))), api); + qml->setReadOnly(true); + + Heap::QmlContext *c = parent->d()->engine->memoryManager->alloc<QmlContext>(parent, qml); + return c; +} + +Heap::QmlContext *QmlContext::create(ExecutionContext *parent, QQmlContextData *context, QObject *scopeObject) +{ + Scope scope(parent); + + Scoped<QmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QmlContextWrapper>(context, scopeObject)); + Heap::QmlContext *c = parent->d()->engine->memoryManager->alloc<QmlContext>(parent, qml); + return c; +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index 126ffecf0d..9aec7467da 100644 --- a/src/qml/qml/qqmlcontextwrapper_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef QQMLCONTEXTWRAPPER_P_H -#define QQMLCONTEXTWRAPPER_P_H +#ifndef QV4QMLCONTEXT_P_H +#define QV4QMLCONTEXT_P_H // // W A R N I N G @@ -55,12 +55,15 @@ #include <private/qtqmlglobal_p.h> #include <private/qv4object_p.h> +#include <private/qv4context_p.h> #include <private/qqmlcontext_p.h> QT_BEGIN_NAMESPACE namespace QV4 { +struct QmlContextWrapper; + namespace Heap { struct QmlContextWrapper : Object { @@ -74,6 +77,12 @@ struct QmlContextWrapper : Object { QQmlQPointer<QObject> scopeObject; }; +struct QmlContext : ExecutionContext { + void init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml); + + Pointer<QmlContextWrapper> qml; +}; + } struct Q_QML_EXPORT QmlContextWrapper : Object @@ -81,9 +90,6 @@ struct Q_QML_EXPORT QmlContextWrapper : Object V4_OBJECT2(QmlContextWrapper, Object) V4_NEEDS_DESTROY - static ReturnedValue qmlScope(ExecutionEngine *e, QQmlContextData *ctxt, QObject *scope); - static ReturnedValue urlScope(ExecutionEngine *v4, const QUrl &); - void takeContextOwnership() { d()->ownsContext = true; } @@ -97,9 +103,28 @@ struct Q_QML_EXPORT QmlContextWrapper : Object static void put(Managed *m, String *name, const Value &value); }; +struct Q_QML_EXPORT QmlContext : public ExecutionContext +{ + V4_MANAGED(QmlContext, ExecutionContext) + + static Heap::QmlContext *createWorkerContext(QV4::ExecutionContext *parent, const QUrl &source, Value *sendFunction); + static Heap::QmlContext *create(QV4::ExecutionContext *parent, QQmlContextData *context, QObject *scopeObject); + + QObject *qmlScope() const { + return d()->qml->scopeObject; + } + QQmlContextData *qmlContext() const { + return *d()->qml->context; + } + + void takeContextOwnership() { + d()->qml->ownsContext = true; + } +}; + } QT_END_NAMESPACE -#endif // QV8CONTEXTWRAPPER_P_H +#endif diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index d91965a350..5f66b56a42 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -48,7 +48,6 @@ #include <private/qqmlglobal_p.h> #include <private/qqmltypewrapper_p.h> #include <private/qqmlvaluetypewrapper_p.h> -#include <private/qqmlcontextwrapper_p.h> #include <private/qqmllistwrapper_p.h> #include <private/qqmlbuiltinfunctions_p.h> #include <private/qv8engine_p.h> @@ -392,9 +391,10 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP QQmlContextData *callingQmlContext = scope.engine->callingQmlContext(); QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); - bindingFunction->initBindingLocation(); - newBinding = QQmlBinding::create(property, value, object, callingQmlContext); + QV4::ScopedContext ctx(scope, bindingFunction->scope()); + newBinding = QQmlBinding::create(property, bindingFunction->function(), object, callingQmlContext, ctx); + newBinding->setSourceLocation(bindingFunction->currentLocation()); newBinding->setTarget(object, *property, nullptr); } } @@ -493,8 +493,7 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP ReturnedValue QObjectWrapper::wrap_slowPath(ExecutionEngine *engine, QObject *object) { - if (QQmlData::wasDeleted(object)) - return QV4::Encode::null(); + Q_ASSERT(!QQmlData::wasDeleted(object)); QQmlData *ddata = QQmlData::get(object, true); if (!ddata) diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 504f6a69b8..c7c4f4dd77 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -206,14 +206,15 @@ private: inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object) { - if (Q_LIKELY(!QQmlData::wasDeleted(object))) { - QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object)); - if (Q_LIKELY(priv->declarativeData)) { - auto ddata = static_cast<QQmlData *>(priv->declarativeData); - if (Q_LIKELY(ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isUndefined())) { - // We own the JS object - return ddata->jsWrapper.value(); - } + if (Q_UNLIKELY(QQmlData::wasDeleted(object))) + return QV4::Encode::null(); + + QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object)); + if (Q_LIKELY(priv->declarativeData)) { + auto ddata = static_cast<QQmlData *>(priv->declarativeData); + if (Q_LIKELY(ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isUndefined())) { + // We own the JS object + return ddata->jsWrapper.value(); } } diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 4022d98c3f..218695624b 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -262,12 +262,12 @@ void RegExpCtor::construct(const Managed *, Scope &scope, CallData *callData) bool ignoreCase = false; bool multiLine = false; if (!f->isUndefined()) { - f = RuntimeHelpers::toString(scope.engine, f); + ScopedString s(scope, f->toString(scope.engine)); if (scope.hasException()) { scope.result = Encode::undefined(); return; } - QString str = f->stringValue()->toQString(); + QString str = s->toQString(); for (int i = 0; i < str.length(); ++i) { if (str.at(i) == QLatin1Char('g') && !global) { global = true; @@ -356,10 +356,10 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) return ctx->engine()->throwTypeError(); ScopedValue arg(scope, ctx->argument(0)); - arg = RuntimeHelpers::toString(scope.engine, arg); + ScopedString str(scope, arg->toString(scope.engine)); if (scope.hasException()) return Encode::undefined(); - QString s = arg->stringValue()->toQString(); + QString s = str->toQString(); int offset = r->global() ? r->lastIndexProperty()->toInt32() : 0; if (offset < 0 || offset > s.length()) { @@ -391,11 +391,11 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) } array->setArrayLengthUnchecked(len); *array->propertyData(Index_ArrayIndex) = Primitive::fromInt32(result); - *array->propertyData(Index_ArrayInput) = arg; + *array->propertyData(Index_ArrayInput) = str; RegExpCtor::Data *dd = regExpCtor->d(); dd->lastMatch = array; - dd->lastInput = arg->stringValue()->d(); + dd->lastInput = str->d(); dd->lastMatchStart = matchOffsets[0]; dd->lastMatchEnd = matchOffsets[1]; diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 2026ecdfde..57ad181030 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -53,7 +53,7 @@ #include "qv4numberobject_p.h" #include "private/qlocale_tools_p.h" #include "qv4scopedvalue_p.h" -#include <private/qqmlcontextwrapper_p.h> +#include <private/qv4qmlcontext_p.h> #include <private/qqmltypewrapper_p.h> #include <private/qqmlengine_p.h> #include <private/qqmljavascriptexpression_p.h> @@ -345,28 +345,29 @@ ReturnedValue Runtime::method_deleteName(ExecutionEngine *engine, int nameIndex) QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &left, const Value &right) { - Scope scope(engine); - ScopedFunctionObject f(scope, right.as<FunctionObject>()); - if (!f) + const FunctionObject *function = right.as<FunctionObject>(); + if (!function) return engine->throwTypeError(); - if (f->isBoundFunction()) - f = static_cast<BoundFunction *>(f.getPointer())->target(); + Heap::FunctionObject *f = function->d(); + if (function->isBoundFunction()) + f = function->cast<BoundFunction>()->target(); - ScopedObject v(scope, left.as<Object>()); - if (!v) + const Object *o = left.as<Object>(); + if (!o) return Encode(false); + Heap::Object *v = o->d(); - ScopedObject o(scope, f->protoProperty()); + o = f->protoProperty(); if (!o) return engine->throwTypeError(); while (v) { - v = v->prototype(); + v = v->prototype; if (!v) break; - else if (o->d() == v->d()) + else if (o->d() == v) return Encode(true); } @@ -375,13 +376,14 @@ QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Val QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left, const Value &right) { - if (!right.isObject()) + Object *ro = right.objectValue(); + if (!ro) return engine->throwTypeError(); Scope scope(engine); ScopedString s(scope, left.toString(engine)); if (scope.hasException()) return Encode::undefined(); - bool r = right.objectValue()->hasProperty(s); + bool r = ro->hasProperty(s); return Encode(r); } @@ -492,8 +494,8 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, const Val else return engine->id_false()->d(); case Value::Managed_Type: - if (value.isString()) - return value.stringValue()->d(); + if (String *s = value.stringValue()) + return s->d(); { Scope scope(engine); ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value, STRING_HINT)); @@ -523,8 +525,8 @@ static Heap::String *convert_to_string_add(ExecutionEngine *engine, const Value else return engine->id_false()->d(); case Value::Managed_Type: - if (value.isString()) - return value.stringValue()->d(); + if (String *s = value.stringValue()) + return s->d(); { Scope scope(engine); ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value, PREFERREDTYPE_HINT)); @@ -543,19 +545,25 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Valu ScopedValue pleft(scope, RuntimeHelpers::toPrimitive(left, PREFERREDTYPE_HINT)); ScopedValue pright(scope, RuntimeHelpers::toPrimitive(right, PREFERREDTYPE_HINT)); - if (pleft->isString() || pright->isString()) { - if (!pleft->isString()) + String *sleft = pleft->stringValue(); + String *sright = pright->stringValue(); + if (sleft || sright) { + if (!sleft) { pleft = convert_to_string_add(engine, pleft); - if (!pright->isString()) + sleft = static_cast<String *>(pleft.ptr); + } + if (!sright) { pright = convert_to_string_add(engine, pright); + sright = static_cast<String *>(pright.ptr); + } if (scope.engine->hasException) return Encode::undefined(); - if (!pleft->stringValue()->d()->length()) - return pright->asReturnedValue(); - if (!pright->stringValue()->d()->length()) - return pleft->asReturnedValue(); + if (!sleft->d()->length()) + return sright->asReturnedValue(); + if (!sright->d()->length()) + return sleft->asReturnedValue(); MemoryManager *mm = engine->memoryManager; - return (mm->alloc<String>(mm, pleft->stringValue()->d(), pright->stringValue()->d()))->asReturnedValue(); + return (mm->alloc<String>(mm, sleft->d(), sright->d()))->asReturnedValue(); } double x = RuntimeHelpers::toNumber(pleft); double y = RuntimeHelpers::toNumber(pright); @@ -566,31 +574,28 @@ QV4::ReturnedValue Runtime::method_addString(ExecutionEngine *engine, const Valu { Q_ASSERT(left.isString() || right.isString()); - if (left.isString() && right.isString()) { - if (!left.stringValue()->d()->length()) - return right.asReturnedValue(); - if (!right.stringValue()->d()->length()) - return left.asReturnedValue(); - MemoryManager *mm = engine->memoryManager; - return (mm->alloc<String>(mm, left.stringValue()->d(), right.stringValue()->d()))->asReturnedValue(); - } - Scope scope(engine); ScopedValue pleft(scope, left); ScopedValue pright(scope, right); + String *sleft = pleft->stringValue(); + String *sright = pright->stringValue(); - if (!pleft->isString()) - pleft = convert_to_string_add(engine, left); - if (!pright->isString()) - pright = convert_to_string_add(engine, right); + if (!sleft) { + pleft = convert_to_string_add(engine, pleft); + sleft = static_cast<String *>(pleft.ptr); + } + if (!sright) { + pright = convert_to_string_add(engine, pright); + sright = static_cast<String *>(pright.ptr); + } if (scope.engine->hasException) return Encode::undefined(); - if (!pleft->stringValue()->d()->length()) + if (!sleft->d()->length()) return pright->asReturnedValue(); - if (!pright->stringValue()->d()->length()) + if (!sright->d()->length()) return pleft->asReturnedValue(); MemoryManager *mm = engine->memoryManager; - return (mm->alloc<String>(mm, pleft->stringValue()->d(), pright->stringValue()->d()))->asReturnedValue(); + return (mm->alloc<String>(mm, sleft->d(), sright->d()))->asReturnedValue(); } void Runtime::method_setProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value) @@ -750,13 +755,15 @@ uint RuntimeHelpers::equalHelper(const Value &x, const Value &y) #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else - if ((x.isNumber() || x.isString()) && y.isObject()) { - Scope scope(y.objectValue()->engine()); - ScopedValue py(scope, RuntimeHelpers::toPrimitive(y, PREFERREDTYPE_HINT)); + Object *xo = x.objectValue(); + Object *yo = y.objectValue(); + if (yo && (x.isNumber() || x.isString())) { + Scope scope(yo->engine()); + ScopedValue py(scope, RuntimeHelpers::objectDefaultValue(yo, PREFERREDTYPE_HINT)); return Runtime::method_compareEqual(x, py); - } else if (x.isObject() && (y.isNumber() || y.isString())) { - Scope scope(x.objectValue()->engine()); - ScopedValue px(scope, RuntimeHelpers::toPrimitive(x, PREFERREDTYPE_HINT)); + } else if (xo && (y.isNumber() || y.isString())) { + Scope scope(xo->engine()); + ScopedValue px(scope, RuntimeHelpers::objectDefaultValue(xo, PREFERREDTYPE_HINT)); return Runtime::method_compareEqual(px, y); } #endif @@ -787,23 +794,27 @@ QV4::Bool Runtime::method_compareGreaterThan(const Value &l, const Value &r) return l.integerValue() > r.integerValue(); if (l.isNumber() && r.isNumber()) return l.asDouble() > r.asDouble(); - if (l.isString() && r.isString()) { + String *sl = l.stringValue(); + String *sr = r.stringValue(); + if (sl && sr) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); return false; #else - return r.stringValue()->compare(l.stringValue()); + return sr->compare(sl); #endif } - if (l.isObject() || r.isObject()) { + Object *ro = r.objectValue(); + Object *lo = l.objectValue(); + if (ro || lo) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else - QV4::ExecutionEngine *e = (l.isObject() ? l.objectValue() : r.objectValue())->engine(); + QV4::ExecutionEngine *e = (lo ? lo : ro)->engine(); QV4::Scope scope(e); - QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT)); - QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT)); + QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); + QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); return Runtime::method_compareGreaterThan(pl, pr); #endif } @@ -820,23 +831,27 @@ QV4::Bool Runtime::method_compareLessThan(const Value &l, const Value &r) return l.integerValue() < r.integerValue(); if (l.isNumber() && r.isNumber()) return l.asDouble() < r.asDouble(); - if (l.isString() && r.isString()) { + String *sl = l.stringValue(); + String *sr = r.stringValue(); + if (sl && sr) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); return false; #else - return l.stringValue()->compare(r.stringValue()); + return sl->compare(sr); #endif } - if (l.isObject() || r.isObject()) { + Object *ro = r.objectValue(); + Object *lo = l.objectValue(); + if (ro || lo) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else - QV4::ExecutionEngine *e = (l.isObject() ? l.objectValue() : r.objectValue())->engine(); + QV4::ExecutionEngine *e = (lo ? lo : ro)->engine(); QV4::Scope scope(e); - QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT)); - QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT)); + QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); + QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); return Runtime::method_compareLessThan(pl, pr); #endif } @@ -853,23 +868,27 @@ QV4::Bool Runtime::method_compareGreaterEqual(const Value &l, const Value &r) return l.integerValue() >= r.integerValue(); if (l.isNumber() && r.isNumber()) return l.asDouble() >= r.asDouble(); - if (l.isString() && r.isString()) { + String *sl = l.stringValue(); + String *sr = r.stringValue(); + if (sl && sr) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); return false; #else - return !l.stringValue()->compare(r.stringValue()); + return !sl->compare(sr); #endif } - if (l.isObject() || r.isObject()) { + Object *ro = r.objectValue(); + Object *lo = l.objectValue(); + if (ro || lo) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else - QV4::ExecutionEngine *e = (l.isObject() ? l.objectValue() : r.objectValue())->engine(); + QV4::ExecutionEngine *e = (lo ? lo : ro)->engine(); QV4::Scope scope(e); - QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT)); - QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT)); + QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); + QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); return Runtime::method_compareGreaterEqual(pl, pr); #endif } @@ -886,23 +905,27 @@ QV4::Bool Runtime::method_compareLessEqual(const Value &l, const Value &r) return l.integerValue() <= r.integerValue(); if (l.isNumber() && r.isNumber()) return l.asDouble() <= r.asDouble(); - if (l.isString() && r.isString()) { + String *sl = l.stringValue(); + String *sr = r.stringValue(); + if (sl && sr) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); return false; #else - return !r.stringValue()->compare(l.stringValue()); + return !sr->compare(sl); #endif } - if (l.isObject() || r.isObject()) { + Object *ro = r.objectValue(); + Object *lo = l.objectValue(); + if (ro || lo) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else - QV4::ExecutionEngine *e = (l.isObject() ? l.objectValue() : r.objectValue())->engine(); + QV4::ExecutionEngine *e = (lo ? lo : ro)->engine(); QV4::Scope scope(e); - QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT)); - QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT)); + QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); + QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); return Runtime::method_compareLessEqual(pl, pr); #endif } @@ -1045,13 +1068,13 @@ ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, uint i Lookup *l = engine->current->lookups + index; Value v; v = l->getter(l, engine, callData->thisObject); - if (v.isObject()) { + Object *o = v.objectValue(); + if (Q_LIKELY(o)) { Scope scope(engine); - v.objectValue()->call(scope, callData); + o->call(scope, callData); return scope.result.asReturnedValue(); - } else { - return engine->throwTypeError(); } + return engine->throwTypeError(); } ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, const Value &index, CallData *callData) @@ -1074,12 +1097,12 @@ ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, const Value & ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &func, CallData *callData) { - if (!func.isObject()) - return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow())); - - Scope scope(engine); - func.objectValue()->call(scope, callData); - return scope.result.asReturnedValue(); + if (Object *o = func.objectValue()) { + Scope scope(engine); + o->call(scope, callData); + return scope.result.asReturnedValue(); + } + return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow())); } @@ -1149,14 +1172,13 @@ ReturnedValue Runtime::method_constructPropertyLookup(ExecutionEngine *engine, u Lookup *l = engine->current->lookups + index; Value v; v = l->getter(l, engine, callData->thisObject); - if (v.isObject()) { + Object *o = v.objectValue(); + if (Q_LIKELY(o)) { Scope scope(engine); - ScopedValue result(scope); - v.objectValue()->construct(scope, callData); + o->construct(scope, callData); return scope.result.asReturnedValue(); - } else { - return engine->throwTypeError(); } + return engine->throwTypeError(); } @@ -1367,29 +1389,6 @@ QV4::ReturnedValue Runtime::method_decrement(const Value &value) } } -#ifndef V4_BOOTSTRAP - -QV4::ReturnedValue RuntimeHelpers::toString(ExecutionEngine *engine, const Value &value) -{ - if (value.isString()) - return value.asReturnedValue(); - return RuntimeHelpers::convertToString(engine, value)->asReturnedValue(); -} - -QV4::ReturnedValue RuntimeHelpers::toObject(ExecutionEngine *engine, const Value &value) -{ - if (value.isObject()) - return value.asReturnedValue(); - - Heap::Object *o = RuntimeHelpers::convertToObject(engine, value); - if (!o) // type error - return Encode::undefined(); - - return Encode(o); -} - -#endif // V4_BOOTSTRAP - ReturnedValue Runtime::method_toDouble(const Value &value) { TRACE1(value); diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index a32b3f1663..0d787714cf 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -106,10 +106,7 @@ struct Q_QML_PRIVATE_EXPORT RuntimeHelpers { static double toNumber(const Value &value); static void numberToString(QString *result, double num, int radix = 10); - static ReturnedValue toString(ExecutionEngine *engine, const Value &value); static Heap::String *convertToString(ExecutionEngine *engine, const Value &value); - - static ReturnedValue toObject(ExecutionEngine *engine, const Value &value); static Heap::Object *convertToObject(ExecutionEngine *engine, const Value &value); static Bool equalHelper(const Value &x, const Value &y); diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 5022d7c3bc..4e627e003f 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -97,7 +97,7 @@ struct Scope { engine->jsStackTop = mark; } - Value *alloc(int nValues) const { + QML_NEARLY_ALWAYS_INLINE Value *alloc(int nValues) const { return engine->jsAlloca(nValues); } @@ -189,63 +189,70 @@ struct Scoped { enum ConvertType { Convert }; - inline void setPointer(const Managed *p) { + QML_NEARLY_ALWAYS_INLINE void setPointer(const Managed *p) { ptr->setM(p ? p->m() : 0); } - Scoped(const Scope &scope) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope) { ptr = scope.engine->jsAlloca(1); } - Scoped(const Scope &scope, const Value &v) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v) { ptr = scope.engine->jsAlloca(1); setPointer(v.as<T>()); } - Scoped(const Scope &scope, Heap::Base *o) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, Heap::Base *o) { Value v; v = o; ptr = scope.engine->jsAlloca(1); setPointer(v.as<T>()); } - Scoped(const Scope &scope, const ScopedValue &v) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ScopedValue &v) { ptr = scope.engine->jsAlloca(1); setPointer(v.ptr->as<T>()); } - Scoped(const Scope &scope, const Value &v, ConvertType) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v, ConvertType) { ptr = scope.engine->jsAlloca(1); ptr->setRawValue(value_convert<T>(scope.engine, v)); } - Scoped(const Scope &scope, const Value *v) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value *v) { ptr = scope.engine->jsAlloca(1); setPointer(v ? v->as<T>() : 0); } - Scoped(const Scope &scope, T *t) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, T *t) { ptr = scope.engine->jsAlloca(1); setPointer(t); } - Scoped(const Scope &scope, typename T::Data *t) + + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const T *t) + { + ptr = scope.engine->jsAlloca(1); + setPointer(t); + } + + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, typename T::Data *t) { ptr = scope.engine->jsAlloca(1); *ptr = t; } - Scoped(const Scope &scope, const ReturnedValue &v) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v) { ptr = scope.engine->jsAlloca(1); setPointer(QV4::Value::fromReturnedValue(v).as<T>()); } - Scoped(const Scope &scope, const ReturnedValue &v, ConvertType) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v, ConvertType) { ptr = scope.engine->jsAlloca(1); ptr->setRawValue(value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v))); @@ -291,11 +298,11 @@ struct Scoped } T *operator->() { - return ptr->cast<T>(); + return getPointer(); } const T *operator->() const { - return ptr->cast<T>(); + return getPointer(); } bool operator!() const { @@ -306,14 +313,19 @@ struct Scoped } T *getPointer() { - return ptr->cast<T>(); + return reinterpret_cast<T *>(ptr); + } + + const T *getPointer() const { + return reinterpret_cast<T *>(ptr); } + Value *getRef() { return ptr; } - ReturnedValue asReturnedValue() const { - return ptr->m() ? ptr->rawValue() : Encode::undefined(); + QML_NEARLY_ALWAYS_INLINE ReturnedValue asReturnedValue() const { + return ptr->rawValue(); } Value *ptr; @@ -358,8 +370,6 @@ struct ScopedProperty ScopedProperty(Scope &scope) { property = reinterpret_cast<Property*>(scope.alloc(sizeof(Property) / sizeof(Value))); - property->value = Encode::undefined(); - property->set = Encode::undefined(); } Property *operator->() { return property; } diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 787047806a..5d7df9a9d7 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -54,71 +54,12 @@ #include <private/qv4profiling_p.h> #include <qv4jsir_p.h> #include <qv4codegen_p.h> -#include <private/qqmlcontextwrapper_p.h> #include <QtCore/QDebug> #include <QtCore/QString> -QT_BEGIN_NAMESPACE - -namespace QV4 { -namespace Heap { - -struct QmlBindingWrapper : FunctionObject { - void init(QV4::QmlContext *scope, Function *f); -}; - -} - -struct QmlBindingWrapper : FunctionObject { - V4_OBJECT2(QmlBindingWrapper, FunctionObject) - - static void call(const Managed *that, Scope &scope, CallData *callData); -}; - -} - -QT_END_NAMESPACE - using namespace QV4; -DEFINE_OBJECT_VTABLE(QmlBindingWrapper); - -void Heap::QmlBindingWrapper::init(QV4::QmlContext *scope, Function *f) -{ - Heap::FunctionObject::init(scope, scope->d()->engine->id_eval(), /*createProto = */ false); - - Q_ASSERT(scope->inUse()); - - function = f; - if (function) - function->compilationUnit->addref(); -} - -void QmlBindingWrapper::call(const Managed *that, Scope &scope, CallData *callData) -{ - const QmlBindingWrapper *This = static_cast<const QmlBindingWrapper *>(that); - ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); - if (v4->hasException) { - scope.result = Encode::undefined(); - return; - } - CHECK_STACK_LIMITS(v4, scope); - - ExecutionContextSaver ctxSaver(scope); - - QV4::Function *f = This->function(); - if (!f) { - scope.result = QV4::Encode::undefined(); - return; - } - - Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(This, callData)); - v4->pushContext(ctx); - - scope.result = Q_V4_PROFILE(v4, f); -} - Script::Script(ExecutionEngine *v4, QmlContext *qml, CompiledData::CompilationUnit *compilationUnit) : line(0), column(0), scope(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false) , compilationUnit(compilationUnit), vmFunction(0), parseAsBinding(true) @@ -229,10 +170,12 @@ ReturnedValue Script::run() return Q_V4_PROFILE(engine, vmFunction); } else { Scoped<QmlContext> qml(valueScope, qmlContext.value()); - ScopedFunctionObject f(valueScope, engine->memoryManager->allocObject<QmlBindingWrapper>(qml, vmFunction)); ScopedCallData callData(valueScope); callData->thisObject = Primitive::undefinedValue(); - f->call(valueScope, callData); + if (vmFunction->canUseSimpleFunction()) + qml->simpleCall(valueScope, callData, vmFunction); + else + qml->call(valueScope, callData, vmFunction); return valueScope.result.asReturnedValue(); } } @@ -301,17 +244,6 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(IR::Module return isel->compile(/*generate unit data*/false); } -ReturnedValue Script::qmlBinding() -{ - if (!parsed) - parse(); - ExecutionEngine *v4 = scope->engine(); - Scope valueScope(v4); - Scoped<QmlContext> qml(valueScope, qmlContext.value()); - ScopedObject v(valueScope, v4->memoryManager->allocObject<QmlBindingWrapper>(qml, vmFunction)); - return v.asReturnedValue(); -} - QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext) { QV4::Scope scope(engine); diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index 2e87a7692b..f96f0254a5 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -53,7 +53,7 @@ #include "qv4global_p.h" #include "qv4engine_p.h" #include "qv4functionobject_p.h" -#include "qv4context_p.h" +#include "qv4qmlcontext_p.h" #include <QQmlError> @@ -136,7 +136,6 @@ struct Q_QML_EXPORT Script { void parse(); ReturnedValue run(); - ReturnedValue qmlBinding(); Function *function(); diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index 23ec3349b9..4890a85724 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -267,7 +267,7 @@ public: template<> inline const String *Value::as() const { - return isManaged() && m() && m()->vtable()->isString ? static_cast<const String *>(this) : 0; + return isManaged() && m()->vtable()->isString ? static_cast<const String *>(this) : 0; } #ifndef V4_BOOTSTRAP diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 829ada0c1a..6fbf1c3c85 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -218,8 +218,8 @@ static QString getThisString(ExecutionContext *ctx) { Scope scope(ctx); ScopedValue t(scope, ctx->thisObject()); - if (t->isString()) - return t->stringValue()->toQString(); + if (String *s = t->stringValue()) + return s->toQString(); if (StringObject *thisString = t->as<StringObject>()) return thisString->d()->string->toQString(); if (t->isUndefined() || t->isNull()) { @@ -282,13 +282,13 @@ ReturnedValue StringPrototype::method_concat(CallContext *context) if (scope.engine->hasException) return Encode::undefined(); - ScopedValue v(scope); + ScopedString s(scope); for (int i = 0; i < context->argc(); ++i) { - v = RuntimeHelpers::toString(scope.engine, context->args()[i]); + s = context->args()[i].toString(scope.engine); if (scope.hasException()) return Encode::undefined(); - Q_ASSERT(v->isString()); - value += v->stringValue()->toQString(); + Q_ASSERT(s->isString()); + value += s->toQString(); } return context->d()->engine->newString(value)->asReturnedValue(); diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index 95c95b1974..e34ac9c764 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -77,24 +77,24 @@ int Value::toUInt16() const bool Value::toBoolean() const { - switch (type()) { - case Value::Undefined_Type: - case Value::Null_Type: + if (isInteger() || isBoolean()) + return static_cast<bool>(int_32()); + + if (isUndefined() || isNull()) return false; - case Value::Boolean_Type: - case Value::Integer_Type: - return (bool)int_32(); - case Value::Managed_Type: + + if (isManaged()) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else - if (isString()) - return stringValue()->toQString().length() > 0; + if (String *s = stringValue()) + return s->toQString().length() > 0; #endif return true; - default: // double - return doubleValue() && !std::isnan(doubleValue()); } + + // double + return doubleValue() && !std::isnan(doubleValue()); } double Value::toInteger() const @@ -114,8 +114,8 @@ double Value::toNumberImpl() const #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else - if (isString()) - return RuntimeHelpers::stringToNumber(stringValue()->toQString()); + if (String *s = stringValue()) + return RuntimeHelpers::stringToNumber(s->toQString()); { Q_ASSERT(isObject()); Scope scope(objectValue()->engine()); @@ -150,8 +150,8 @@ QString Value::toQStringNoThrow() const else return QStringLiteral("false"); case Value::Managed_Type: - if (isString()) - return stringValue()->toQString(); + if (String *s = stringValue()) + return s->toQString(); { Q_ASSERT(isObject()); Scope scope(objectValue()->engine()); @@ -203,8 +203,8 @@ QString Value::toQString() const else return QStringLiteral("false"); case Value::Managed_Type: - if (isString()) - return stringValue()->toQString(); + if (String *s = stringValue()) + return s->toQString(); { Q_ASSERT(isObject()); Scope scope(objectValue()->engine()); @@ -228,8 +228,10 @@ QString Value::toQString() const bool Value::sameValue(Value other) const { if (_val == other._val) return true; - if (isString() && other.isString()) - return stringValue()->isEqualTo(other.stringValue()); + String *s = stringValue(); + String *os = other.stringValue(); + if (s && os) + return s->isEqualTo(os); if (isInteger() && other.isDouble()) return int_32() ? (double(int_32()) == other.doubleValue()) : (other._val == 0); if (isDouble() && other.isInteger()) @@ -298,15 +300,15 @@ double Primitive::toInteger(double number) #ifndef V4_BOOTSTRAP Heap::String *Value::toString(ExecutionEngine *e) const { - if (isString()) - return stringValue()->d(); + if (String *s = stringValue()) + return s->d(); return RuntimeHelpers::convertToString(e, *this); } Heap::Object *Value::toObject(ExecutionEngine *e) const { - if (isObject()) - return objectValue()->d(); + if (Object *o = objectValue()) + return o->d(); return RuntimeHelpers::convertToObject(e, *this); } @@ -330,8 +332,8 @@ uint Value::asArrayLength(bool *ok) const } return idx; } - if (isString()) - return stringValue()->toUInt(ok); + if (String *s = stringValue()) + return s->toUInt(ok); uint idx = toUInt32(); double d = toNumber(); diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 6d5cff4ecc..816b8fb11b 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -160,9 +160,9 @@ private: quint64 _val; public: - Q_ALWAYS_INLINE quint64 &rawValueRef() { return _val; } - Q_ALWAYS_INLINE quint64 rawValue() const { return _val; } - Q_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; } + QML_NEARLY_ALWAYS_INLINE quint64 &rawValueRef() { return _val; } + QML_NEARLY_ALWAYS_INLINE quint64 rawValue() const { return _val; } + QML_NEARLY_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; } #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN static inline int valueOffset() { return 0; } @@ -171,23 +171,23 @@ public: static inline int valueOffset() { return 4; } static inline int tagOffset() { return 0; } #endif - Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; } - Q_ALWAYS_INLINE quint32 value() const { return _val & quint64(~quint32(0)); } - Q_ALWAYS_INLINE quint32 tag() const { return _val >> 32; } + QML_NEARLY_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; } + QML_NEARLY_ALWAYS_INLINE quint32 value() const { return _val & quint64(~quint32(0)); } + QML_NEARLY_ALWAYS_INLINE quint32 tag() const { return _val >> 32; } #if defined(QV4_USE_64_BIT_VALUE_ENCODING) - Q_ALWAYS_INLINE Heap::Base *m() const + QML_NEARLY_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; memcpy(&b, &_val, 8); return b; } - Q_ALWAYS_INLINE void setM(Heap::Base *b) + QML_NEARLY_ALWAYS_INLINE void setM(Heap::Base *b) { memcpy(&_val, &b, 8); } #else // !QV4_USE_64_BIT_VALUE_ENCODING - Q_ALWAYS_INLINE Heap::Base *m() const + QML_NEARLY_ALWAYS_INLINE Heap::Base *m() const { Q_STATIC_ASSERT(sizeof(Heap::Base*) == sizeof(quint32)); Heap::Base *b; @@ -195,7 +195,7 @@ public: memcpy(&b, &v, 4); return b; } - Q_ALWAYS_INLINE void setM(Heap::Base *b) + QML_NEARLY_ALWAYS_INLINE void setM(Heap::Base *b) { quint32 v; memcpy(&v, &b, 4); @@ -203,32 +203,32 @@ public: } #endif - Q_ALWAYS_INLINE int int_32() const + QML_NEARLY_ALWAYS_INLINE int int_32() const { return int(value()); } - Q_ALWAYS_INLINE void setInt_32(int i) + QML_NEARLY_ALWAYS_INLINE void setInt_32(int i) { setTagValue(Integer_Type_Internal, quint32(i)); } - Q_ALWAYS_INLINE uint uint_32() const { return value(); } + QML_NEARLY_ALWAYS_INLINE uint uint_32() const { return value(); } - Q_ALWAYS_INLINE void setEmpty() + QML_NEARLY_ALWAYS_INLINE void setEmpty() { setTagValue(Empty_Type_Internal, value()); } - Q_ALWAYS_INLINE void setEmpty(int i) + QML_NEARLY_ALWAYS_INLINE void setEmpty(int i) { setTagValue(Empty_Type_Internal, quint32(i)); } - Q_ALWAYS_INLINE void setEmpty(quint32 i) + QML_NEARLY_ALWAYS_INLINE void setEmpty(quint32 i) { setTagValue(Empty_Type_Internal, i); } - Q_ALWAYS_INLINE quint32 emptyValue() + QML_NEARLY_ALWAYS_INLINE quint32 emptyValue() { Q_ASSERT(isEmpty()); return quint32(value()); @@ -302,6 +302,7 @@ public: inline bool isUndefined() const { return _val == 0; } inline bool isDouble() const { return (_val >> IsDouble_Shift); } inline bool isManaged() const { return !isUndefined() && ((_val >> IsManagedOrUndefined_Shift) == 0); } + inline bool isManagedOrUndefined() const { return ((_val >> IsManagedOrUndefined_Shift) == 0); } inline bool integerCompatible() const { return (_val >> IsIntegerConvertible_Shift) == 3; @@ -317,6 +318,7 @@ public: inline bool isUndefined() const { return tag() == Managed_Type_Internal && value() == 0; } inline bool isDouble() const { return (tag() & NotDouble_Mask) != NotDouble_Mask; } inline bool isManaged() const { return tag() == Managed_Type_Internal && !isUndefined(); } + inline bool isManagedOrUndefined() const { return tag() == Managed_Type_Internal; } inline bool integerCompatible() const { return (tag() & ConvertibleToInt) == ConvertibleToInt; } static inline bool integerCompatible(Value a, Value b) { return ((a.tag() & b.tag()) & ConvertibleToInt) == ConvertibleToInt; @@ -326,7 +328,7 @@ public: } inline bool isNaN() const { return (tag() & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; } #endif - Q_ALWAYS_INLINE double doubleValue() const { + QML_NEARLY_ALWAYS_INLINE double doubleValue() const { Q_ASSERT(isDouble()); double d; quint64 v = _val; @@ -336,7 +338,7 @@ public: memcpy(&d, &v, 8); return d; } - Q_ALWAYS_INLINE void setDouble(double d) { + QML_NEARLY_ALWAYS_INLINE void setDouble(double d) { memcpy(&_val, &d, 8); #ifdef QV4_USE_64_BIT_VALUE_ENCODING _val ^= NaNEncodeMask; @@ -371,23 +373,23 @@ public: return int_32(); } - Q_ALWAYS_INLINE String *stringValue() const { + QML_NEARLY_ALWAYS_INLINE String *stringValue() const { if (!isString()) return nullptr; - return m() ? reinterpret_cast<String*>(const_cast<Value *>(this)) : 0; + return reinterpret_cast<String*>(const_cast<Value *>(this)); } - Q_ALWAYS_INLINE Object *objectValue() const { + QML_NEARLY_ALWAYS_INLINE Object *objectValue() const { if (!isObject()) return nullptr; - return m() ? reinterpret_cast<Object*>(const_cast<Value *>(this)) : 0; + return reinterpret_cast<Object*>(const_cast<Value *>(this)); } - Q_ALWAYS_INLINE Managed *managed() const { + QML_NEARLY_ALWAYS_INLINE Managed *managed() const { if (!isManaged()) return nullptr; - return m() ? reinterpret_cast<Managed*>(const_cast<Value *>(this)) : 0; + return reinterpret_cast<Managed*>(const_cast<Value *>(this)); } - Q_ALWAYS_INLINE Heap::Base *heapObject() const { - return isManaged() ? m() : nullptr; + QML_NEARLY_ALWAYS_INLINE Heap::Base *heapObject() const { + return isManagedOrUndefined() ? m() : nullptr; } static inline Value fromHeapObject(Heap::Base *m) @@ -420,7 +422,7 @@ public: template <typename T> const T *as() const { - if (!m() || !isManaged()) + if (!isManaged()) return 0; Q_ASSERT(m()->vtable()); @@ -451,6 +453,7 @@ public: } inline uint asArrayIndex() const; + inline bool asArrayIndex(uint &idx) const; #ifndef V4_BOOTSTRAP uint asArrayLength(bool *ok) const; #endif @@ -485,15 +488,13 @@ V4_ASSERT_IS_TRIVIAL(Value) inline bool Value::isString() const { - if (!isManaged()) - return false; - return m() && m()->vtable()->isString; + Heap::Base *b = heapObject(); + return b && b->vtable()->isString; } inline bool Value::isObject() const { - if (!isManaged()) - return false; - return m() && m()->vtable()->isObject; + Heap::Base *b = heapObject(); + return b && b->vtable()->isObject; } inline bool Value::isPrimitive() const @@ -531,6 +532,20 @@ inline uint Value::asArrayIndex() const return UINT_MAX; return idx; } + +inline bool Value::asArrayIndex(uint &idx) const +{ + if (!isDouble()) { + if (isInteger() && int_32() >= 0) { + idx = (uint)int_32(); + return true; + } + return false; + } + double d = doubleValue(); + idx = (uint)d; + return (idx == d); +} #endif inline diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index b19c36a5bd..622359a7d9 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -169,10 +169,8 @@ static Breakpoint qt_v4LastStop; static QV4::Function *qt_v4ExtractFunction(QV4::ExecutionContext *context) { - QV4::Scope scope(context->engine()); - QV4::ScopedFunctionObject function(scope, context->getFunctionObject()); - if (function) - return function->function(); + if (QV4::Function *function = context->getFunction()) + return function; else return context->d()->engine->globalCode; } diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 6ef2380561..606d3ec162 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -421,11 +421,9 @@ void MemoryManager::mark() // managed objects in the loop down there doesn't make then end up as leftovers // on the stack and thus always get collected. for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) { - if (!(*it).isManaged()) + QObjectWrapper *qobjectWrapper = (*it).as<QObjectWrapper>(); + if (!qobjectWrapper) continue; - if (!(*it).as<QObjectWrapper>()) - continue; - QObjectWrapper *qobjectWrapper = static_cast<QObjectWrapper*>((*it).managed()); QObject *qobject = qobjectWrapper->object(); if (!qobject) continue; @@ -453,10 +451,8 @@ void MemoryManager::mark() void MemoryManager::sweep(bool lastSweep) { for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) { - if (!(*it).isManaged()) - continue; Managed *m = (*it).managed(); - if (m->markBit()) + if (!m || m->markBit()) continue; // we need to call destroyObject on qobjectwrappers now, so that they can emit the destroyed // signal before we start sweeping the heap @@ -469,10 +465,8 @@ void MemoryManager::sweep(bool lastSweep) // onDestruction handlers may have accessed other QObject wrappers and reset their value, so ensure // that they are all set to undefined. for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) { - if (!(*it).isManaged()) - continue; - Managed *m = (*it).as<Managed>(); - if (m->markBit()) + Managed *m = (*it).managed(); + if (!m || m->markBit()) continue; (*it) = Primitive::undefinedValue(); } diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri index 8d8da3742d..412dc6cba2 100644 --- a/src/qml/qml/qml.pri +++ b/src/qml/qml/qml.pri @@ -42,7 +42,6 @@ SOURCES += \ $$PWD/qqmlabstracturlinterceptor.cpp \ $$PWD/qqmlapplicationengine.cpp \ $$PWD/qqmllistwrapper.cpp \ - $$PWD/qqmlcontextwrapper.cpp \ $$PWD/qqmlvaluetypewrapper.cpp \ $$PWD/qqmltypewrapper.cpp \ $$PWD/qqmlfileselector.cpp \ @@ -113,8 +112,6 @@ HEADERS += \ $$PWD/qqmlapplicationengine_p.h \ $$PWD/qqmlapplicationengine.h \ $$PWD/qqmllistwrapper_p.h \ - $$PWD/qqmlcontextwrapper_p.h \ - $$PWD/qqmlvaluetypewrapper_p.h \ $$PWD/qqmltypewrapper_p.h \ $$PWD/qqmlfileselector_p.h \ $$PWD/qqmlfileselector.h \ diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp index fef2da753b..21a1a13687 100644 --- a/src/qml/qml/qqmlapplicationengine.cpp +++ b/src/qml/qml/qqmlapplicationengine.cpp @@ -58,7 +58,7 @@ QQmlApplicationEnginePrivate::~QQmlApplicationEnginePrivate() void QQmlApplicationEnginePrivate::cleanUp() { qDeleteAll(objects); -#ifndef QT_NO_TRANSLATION +#if QT_CONFIG(translation) qDeleteAll(translators); #endif } @@ -70,7 +70,7 @@ void QQmlApplicationEnginePrivate::init() q, SLOT(_q_finishLoad(QObject*))); q->connect(q, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit())); q->connect(q, &QQmlApplicationEngine::exit, QCoreApplication::instance(), &QCoreApplication::exit); -#ifndef QT_NO_TRANSLATION +#if QT_CONFIG(translation) QTranslator* qtTranslator = new QTranslator; if (qtTranslator->load(QLatin1String("qt_") + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) QCoreApplication::installTranslator(qtTranslator); @@ -82,7 +82,7 @@ void QQmlApplicationEnginePrivate::init() void QQmlApplicationEnginePrivate::loadTranslations(const QUrl &rootFile) { -#ifndef QT_NO_TRANSLATION +#if QT_CONFIG(translation) if (rootFile.scheme() != QLatin1String("file") && rootFile.scheme() != QLatin1String("qrc")) return; diff --git a/src/qml/qml/qqmlapplicationengine_p.h b/src/qml/qml/qqmlapplicationengine_p.h index e1d1b4a7bb..8c342a43a9 100644 --- a/src/qml/qml/qqmlapplicationengine_p.h +++ b/src/qml/qml/qqmlapplicationengine_p.h @@ -78,7 +78,7 @@ public: QSignalMapper statusMapper; QObject *appObj; -#ifndef QT_NO_TRANSLATIONS +#if QT_CONFIG(translation) QList<QTranslator *> translators; #endif }; diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index e7e0cfc42e..7505c47a25 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -46,7 +46,6 @@ #include <private/qqmlprofiler_p.h> #include <private/qqmlexpression_p.h> #include <private/qqmlscriptstring_p.h> -#include <private/qqmlcontextwrapper_p.h> #include <private/qqmlbuiltinfunctions_p.h> #include <private/qqmlvmemetaobject_p.h> #include <private/qqmlvaluetypewrapper_p.h> @@ -58,18 +57,6 @@ QT_BEGIN_NAMESPACE -QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj, QQmlContext *ctxt) -{ - QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property); - b->setNotifyOnValueChanged(true); - b->QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt)); - b->setScopeObject(obj); - - b->createQmlBinding(b->context(), obj, str, QString(), 0); - - return b; -} - QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt) { QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property); @@ -98,7 +85,9 @@ QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QQmlScr QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(b->context()->engine)->v4engine(); if (runtimeFunction) { - b->m_function.set(v4, QV4::FunctionObject::createQmlFunction(ctxtdata, b->scopeObject(), runtimeFunction)); + QV4::Scope scope(v4); + QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxtdata, b->scopeObject())); + b->setupFunction(qmlContext, runtimeFunction); } else { QString code = scriptPrivate->script; b->createQmlBinding(b->context(), b->scopeObject(), code, url, scriptPrivate->lineNumber); @@ -107,26 +96,11 @@ QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QQmlScr return b; } -QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj, QQmlContextData *ctxt) -{ - QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property); - - b->setNotifyOnValueChanged(true); - b->QQmlJavaScriptExpression::setContext(ctxt); - b->setScopeObject(obj); - - b->createQmlBinding(ctxt, obj, str, QString(), 0); - - return b; -} - QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj, - QQmlContextData *ctxt, const QString &url, quint16 lineNumber, - quint16 columnNumber) + QQmlContextData *ctxt, const QString &url, quint16 lineNumber) { QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property); - Q_UNUSED(columnNumber); b->setNotifyOnValueChanged(true); b->QQmlJavaScriptExpression::setContext(ctxt); b->setScopeObject(obj); @@ -136,7 +110,8 @@ QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString return b; } -QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QV4::Value &functionPtr, QObject *obj, QQmlContextData *ctxt) +QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, QV4::Function *function, + QObject *obj, QQmlContextData *ctxt, QV4::ExecutionContext *scope) { QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property); @@ -144,7 +119,8 @@ QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QV4::Va b->QQmlJavaScriptExpression::setContext(ctxt); b->setScopeObject(obj); - b->m_function.set(functionPtr.as<QV4::Object>()->engine(), functionPtr); + Q_ASSERT(scope); + b->setupFunction(scope, function); return b; } @@ -183,14 +159,12 @@ void QQmlBinding::update(QQmlPropertyData::WriteFlags flags) QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); QV4::Scope scope(ep->v4engine()); - QV4::ScopedFunctionObject f(scope, m_function.value()); - Q_ASSERT(f); if (canUseAccessor()) flags.setFlag(QQmlPropertyData::BypassInterceptor); - QQmlBindingProfiler prof(ep->profiler, this, f); - doUpdate(watcher, flags, scope, f); + QQmlBindingProfiler prof(ep->profiler, function()); + doUpdate(watcher, flags, scope); if (!watcher.wasDeleted()) setUpdatingFlag(false); @@ -205,8 +179,7 @@ class QQmlBindingBinding: public QQmlBinding { protected: void doUpdate(const DeleteWatcher &, - QQmlPropertyData::WriteFlags flags, QV4::Scope &, - const QV4::ScopedFunctionObject &) Q_DECL_OVERRIDE Q_DECL_FINAL + QQmlPropertyData::WriteFlags flags, QV4::Scope &) Q_DECL_OVERRIDE Q_DECL_FINAL { Q_ASSERT(!m_targetIndex.hasValueTypeIndex()); QQmlPropertyData *pd = nullptr; @@ -222,8 +195,7 @@ class QQmlNonbindingBinding: public QQmlBinding { protected: void doUpdate(const DeleteWatcher &watcher, - QQmlPropertyData::WriteFlags flags, QV4::Scope &scope, - const QV4::ScopedFunctionObject &f) Q_DECL_OVERRIDE Q_DECL_FINAL + QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) Q_DECL_OVERRIDE Q_DECL_FINAL { auto ep = QQmlEnginePrivate::get(scope.engine); ep->referenceScarceResources(); @@ -240,7 +212,7 @@ protected: if (!watcher.wasDeleted()) { if (error) { - delayedError()->setErrorLocation(f->sourceLocation()); + delayedError()->setErrorLocation(sourceLocation()); delayedError()->setErrorObject(m_target.data()); } @@ -450,14 +422,10 @@ QVariant QQmlBinding::evaluate() QString QQmlBinding::expressionIdentifier() { - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); - QV4::Scope scope(ep->v4engine()); - QV4::ScopedValue f(scope, m_function.value()); - QV4::Function *function = f->as<QV4::FunctionObject>()->function(); - - QString url = function->sourceFile(); - quint16 lineNumber = function->compiledFunction->location.line; - quint16 columnNumber = function->compiledFunction->location.column; + auto f = function(); + QString url = f->sourceFile(); + quint16 lineNumber = f->compiledFunction->location.line; + quint16 columnNumber = f->compiledFunction->location.column; return url + QString::asprintf(":%u:%u", uint(lineNumber), uint(columnNumber)); } @@ -488,9 +456,7 @@ void QQmlBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags) QString QQmlBinding::expression() const { - QV4::Scope scope(QQmlEnginePrivate::get(context()->engine)->v4engine()); - QV4::ScopedValue v(scope, m_function.value()); - return v->toQStringNoThrow(); + return QStringLiteral("function() { [code] }"); } void QQmlBinding::setTarget(const QQmlProperty &prop) diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index 6d42a8ea8a..af95bbb5db 100644 --- a/src/qml/qml/qqmlbinding_p.h +++ b/src/qml/qml/qqmlbinding_p.h @@ -72,12 +72,11 @@ class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlJavaScriptExpression, { friend class QQmlAbstractBinding; public: - static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContext *); static QQmlBinding *create(const QQmlPropertyData *, const QQmlScriptString &, QObject *, QQmlContext *); - static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContextData *); static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContextData *, - const QString &url, quint16 lineNumber, quint16 columnNumber); - static QQmlBinding *create(const QQmlPropertyData *, const QV4::Value &, QObject *, QQmlContextData *); + const QString &url = QString(), quint16 lineNumber = 0); + static QQmlBinding *create(const QQmlPropertyData *property, QV4::Function *function, + QObject *obj, QQmlContextData *ctxt, QV4::ExecutionContext *scope); ~QQmlBinding(); void setTarget(const QQmlProperty &); @@ -103,8 +102,7 @@ public: protected: virtual void doUpdate(const DeleteWatcher &watcher, - QQmlPropertyData::WriteFlags flags, QV4::Scope &scope, - const QV4::ScopedFunctionObject &f) = 0; + QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) = 0; void getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const; int getPropertyType() const; diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 4e63790290..c4af82133a 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -98,20 +98,20 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, function += parameterString; function += QLatin1String(") { ") + expression + QLatin1String(" })"); - m_function.set(v4, evalFunction(context(), scopeObject(), function, fileName, line)); - - if (m_function.isNullOrUndefined()) - return; // could not evaluate function. Not valid. - + QV4::Scope valueScope(v4); + QV4::ScopedFunctionObject f(valueScope, evalFunction(context(), scopeObject(), function, fileName, line)); + QV4::ScopedContext context(valueScope, f->scope()); + setupFunction(context, f->function()); } -QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, const QV4::Value &function) +QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scopeObject, + QV4::Function *function, QV4::ExecutionContext *scope) : QQmlJavaScriptExpression(), m_index(index), m_target(target) { - m_function.set(function.as<QV4::Object>()->engine(), function); - init(ctxt, scope); + setupFunction(scope, function); + init(ctxt, scopeObject); } QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction) @@ -122,14 +122,22 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, // It's important to call init first, because m_index gets remapped in case of cloned signals. init(ctxt, scope); - QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index); - QString error; QV4::ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(ctxt->engine); - m_function.set(engine, QV4::FunctionObject::createQmlFunction(ctxt, scope, runtimeFunction, signal.parameterNames(), &error)); - if (!error.isEmpty()) { - qmlInfo(scopeObject()) << error; - m_function.clear(); + + QList<QByteArray> signalParameters = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).parameterNames(); + if (!signalParameters.isEmpty()) { + QString error; + QQmlPropertyCache::signalParameterStringForJS(engine, signalParameters, &error); + if (!error.isEmpty()) { + qmlInfo(scopeObject()) << error; + return; + } + runtimeFunction->updateInternalClass(engine, signalParameters); } + + QV4::Scope valueScope(engine); + QV4::Scoped<QV4::QmlContext> qmlContext(valueScope, QV4::QmlContext::create(engine->rootContext(), ctxt, scope)); + setupFunction(qmlContext, runtimeFunction); } void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope) @@ -157,41 +165,13 @@ void QQmlBoundSignalExpression::expressionChanged() // bound signals do not notify on change. } -QQmlSourceLocation QQmlBoundSignalExpression::sourceLocation() const -{ - QV4::Function *f = function(); - if (f) { - QQmlSourceLocation loc; - loc.sourceFile = f->sourceFile(); - loc.line = f->compiledFunction->location.line; - loc.column = f->compiledFunction->location.column; - return loc; - } - return QQmlSourceLocation(); -} - QString QQmlBoundSignalExpression::expression() const { - if (expressionFunctionValid()) { - Q_ASSERT (context() && engine()); - QV4::Scope scope(QQmlEnginePrivate::get(engine())->v4engine()); - QV4::ScopedValue v(scope, m_function.value()); - return v->toQStringNoThrow(); - } + if (expressionFunctionValid()) + return QStringLiteral("function() { [code] }"); return QString(); } -QV4::Function *QQmlBoundSignalExpression::function() const -{ - if (expressionFunctionValid()) { - Q_ASSERT (context() && engine()); - QV4::Scope scope(QQmlEnginePrivate::get(engine())->v4engine()); - QV4::ScopedFunctionObject v(scope, m_function.value()); - return v ? v->function() : 0; - } - return 0; -} - // Parts of this function mirror code in QQmlExpressionPrivate::value() and v8value(). // Changes made here may need to be made there and vice versa. void QQmlBoundSignalExpression::evaluate(void **a) diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h index 10c59b07c1..173c0f7288 100644 --- a/src/qml/qml/qqmlboundsignal_p.h +++ b/src/qml/qml/qqmlboundsignal_p.h @@ -73,7 +73,7 @@ public: const QString ¶meterString = QString()); QQmlBoundSignalExpression(QObject *target, int index, - QQmlContextData *ctxt, QObject *scope, const QV4::Value &function); + QQmlContextData *ctxt, QObject *scopeObject, QV4::Function *function, QV4::ExecutionContext *scope); QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction); @@ -86,9 +86,7 @@ public: void evaluate(void **a); void evaluate(const QList<QVariant> &args); - QQmlSourceLocation sourceLocation() const; QString expression() const; - QV4::Function *function() const; QObject *target() const { return m_target; } QQmlEngine *engine() const { return context() ? context()->engine : 0; } @@ -98,7 +96,7 @@ private: void init(QQmlContextData *ctxt, QObject *scope); - bool expressionFunctionValid() const { return !m_function.isNullOrUndefined(); } + bool expressionFunctionValid() const { return function() != 0; } int m_index; QObject *m_target; diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp index d10a8c7718..7552e1e82b 100644 --- a/src/qml/qml/qqmldelayedcallqueue.cpp +++ b/src/qml/qml/qqmldelayedcallqueue.cpp @@ -43,7 +43,6 @@ #include <private/qqmljavascriptexpression_p.h> #include <private/qv4value_p.h> #include <private/qv4qobjectwrapper_p.h> -#include <private/qqmlcontextwrapper_p.h> #include <QQmlError> diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp index b309550ca8..0a6c7b4960 100644 --- a/src/qml/qml/qqmlerror.cpp +++ b/src/qml/qml/qqmlerror.cpp @@ -285,7 +285,7 @@ QDebug operator<<(QDebug debug, const QQmlError &error) if (f.open(QIODevice::ReadOnly)) { QByteArray data = f.readAll(); QTextStream stream(data, QIODevice::ReadOnly); -#ifndef QT_NO_TEXTCODEC +#if QT_CONFIG(textcodec) stream.setCodec("UTF-8"); #endif const QString code = stream.readAll(); diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index 6afbd05e3e..94b1eaab52 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -75,7 +75,9 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, QV4::Function *runtimeFu { expressionFunctionValid = true; QV4::ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(ctxt->engine); - m_function.set(engine, QV4::FunctionObject::createQmlFunction(ctxt, me, runtimeFunction)); + QV4::Scope scope(engine); + QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(engine->rootContext(), ctxt, me)); + setupFunction(qmlContext, runtimeFunction); QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(me); diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp index 722527a546..f967dacd34 100644 --- a/src/qml/qml/qqmlglobal.cpp +++ b/src/qml/qml/qqmlglobal.cpp @@ -326,7 +326,6 @@ QObject *QQmlGuiProvider::application(QObject *) { return new QQmlApplication(); QStringList QQmlGuiProvider::fontFamilies() { return QStringList(); } bool QQmlGuiProvider::openUrlExternally(QUrl &) { return false; } -#ifndef QT_NO_IM QObject *QQmlGuiProvider::inputMethod() { // We don't have any input method code by default @@ -335,7 +334,6 @@ QObject *QQmlGuiProvider::inputMethod() QQmlEngine::setObjectOwnership(o, QQmlEngine::JavaScriptOwnership); return o; } -#endif QObject *QQmlGuiProvider::styleHints() { diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h index 0f5cf3a392..707814e781 100644 --- a/src/qml/qml/qqmlglobal_p.h +++ b/src/qml/qml/qqmlglobal_p.h @@ -307,9 +307,7 @@ class Q_QML_PRIVATE_EXPORT QQmlGuiProvider public: virtual ~QQmlGuiProvider(); virtual QObject *application(QObject *parent); -#ifndef QT_NO_IM virtual QObject *inputMethod(); -#endif virtual QObject *styleHints(); virtual QStringList fontFamilies(); virtual bool openUrlExternally(QUrl &); diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 98e2f9eefd..f2cbf5a94f 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -176,7 +176,7 @@ QQmlType *getTypeForUrl(const QString &urlString, const QHashedStringRef& typeNa } // namespace -#ifndef QT_NO_LIBRARY +#if QT_CONFIG(library) struct RegisteredPlugin { QString uri; QPluginLoader* loader; @@ -301,7 +301,7 @@ public: const QString &uri, const QString &url, int vmaj, int vmin, QV4::CompiledData::Import::ImportType type, QList<QQmlError> *errors, bool lowPrecedence = false); -#ifndef QT_NO_LIBRARY +#if QT_CONFIG(library) bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris, const QString &qmldirPath, QList<QQmlError> *errors); #endif @@ -897,7 +897,7 @@ static QStringList versionUriList(const QString &uri, int vmaj, int vmin) return result; } -#ifndef QT_NO_LIBRARY +#if QT_CONFIG(library) /*! Get all static plugins that are QML plugins and has a meta data URI that matches with one of \a versionUris, which is a list of all possible versioned URI combinations - see versionUriList() @@ -960,7 +960,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, const QQmlTypeLoader::QmldirContent *qmldir, QList<QQmlError> *errors) { -#if !defined(QT_NO_LIBRARY) +#if QT_CONFIG(library) Q_ASSERT(qmldir); if (qmlImportTrace()) @@ -1087,7 +1087,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, } return false; -#endif // QT_NO_LIBRARY +#endif // library return true; } @@ -1948,7 +1948,7 @@ bool QQmlImportDatabase::registerPluginTypes(QObject *instance, const QString &b bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &basePath, const QString &uri, const QString &typeNamespace, int vmaj, QList<QQmlError> *errors) { -#ifndef QT_NO_LIBRARY +#if QT_CONFIG(library) // Dynamic plugins are differentiated by their filepath. For static plugins we // don't have that information so we use their address as key instead. const QString uniquePluginID = QString::asprintf("%p", instance); @@ -2001,7 +2001,7 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QString &uri, const QString &typeNamespace, int vmaj, QList<QQmlError> *errors) { -#ifndef QT_NO_LIBRARY +#if QT_CONFIG(library) QFileInfo fileInfo(filePath); const QString absoluteFilePath = fileInfo.absoluteFilePath(); diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 8020bdb2be..17cccc0bbd 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -48,6 +48,7 @@ #include <private/qv4scopedvalue_p.h> #include <private/qqmlglobal_p.h> #include <private/qv4qobjectwrapper_p.h> +#include <private/qqmlbuiltinfunctions_p.h> QT_BEGIN_NAMESPACE @@ -94,7 +95,9 @@ QQmlJavaScriptExpression::QQmlJavaScriptExpression() : m_error(0), m_context(0), m_prevExpression(0), - m_nextExpression(0) + m_nextExpression(0), + m_v4Function(0), + m_sourceLocation(0) { } @@ -110,6 +113,8 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression() clearPermanentGuards(); if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion. m_scopeObject.asT2()->_s = 0; + + delete m_sourceLocation; } void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v) @@ -128,6 +133,22 @@ void QQmlJavaScriptExpression::resetNotifyOnValueChanged() setNotifyOnValueChanged(false); } +QQmlSourceLocation QQmlJavaScriptExpression::sourceLocation() const +{ + if (m_sourceLocation) + return *m_sourceLocation; + if (m_v4Function) + return m_v4Function->sourceLocation(); + return QQmlSourceLocation(); +} + +void QQmlJavaScriptExpression::setSourceLocation(const QQmlSourceLocation &location) +{ + if (m_sourceLocation) + delete m_sourceLocation; + m_sourceLocation = new QQmlSourceLocation(location); +} + void QQmlJavaScriptExpression::setContext(QQmlContextData *context) { if (m_prevExpression) { @@ -149,6 +170,11 @@ void QQmlJavaScriptExpression::setContext(QQmlContextData *context) } } +QV4::Function *QQmlJavaScriptExpression::function() const +{ + return m_v4Function; +} + void QQmlJavaScriptExpression::refresh() { } @@ -159,8 +185,8 @@ void QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefin { Q_ASSERT(m_context && m_context->engine); - QV4::Value *f = m_function.valueRef(); - if (!f || f->isUndefined()) { + QV4::Function *v4Function = function(); + if (!v4Function) { if (isUndefined) *isUndefined = true; return; @@ -191,7 +217,13 @@ void QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefin callData->thisObject = value; } - f->as<QV4::FunctionObject>()->call(scope, callData); + QV4::ExecutionContext *outer = static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef()); + if (v4Function->canUseSimpleFunction()) { + outer->simpleCall(scope, callData, v4Function); + } else { + outer->call(scope, callData, v4Function); + } + if (scope.hasException()) { if (watcher.wasDeleted()) scope.engine->catchException(); // ignore exception @@ -374,7 +406,7 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObje QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine()); QV4::Scope scope(v4); - QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->rootContext()->newQmlContext(ctxt, scopeObject)); + QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxt, scopeObject)); QV4::Script script(v4, qmlContext, code, filename, line); QV4::ScopedValue result(scope); script.parse(); @@ -404,12 +436,9 @@ void QQmlJavaScriptExpression::createQmlBinding(QQmlContextData *ctxt, QObject * QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine()); QV4::Scope scope(v4); - QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->rootContext()->newQmlContext(ctxt, qmlScope)); + QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxt, qmlScope)); QV4::Script script(v4, qmlContext, code, filename, line); - QV4::ScopedValue result(scope); script.parse(); - if (!v4->hasException) - result = script.qmlBinding(); if (v4->hasException) { QQmlError error = v4->catchExceptionAsQmlError(); if (error.description().isEmpty()) @@ -420,11 +449,19 @@ void QQmlJavaScriptExpression::createQmlBinding(QQmlContextData *ctxt, QObject * error.setUrl(QUrl::fromLocalFile(filename)); error.setObject(qmlScope); ep->warning(error); - result = QV4::Encode::undefined(); + return; } - m_function.set(v4, result); + setupFunction(qmlContext, script.vmFunction); } +void QQmlJavaScriptExpression::setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f) +{ + if (!qmlContext || !f) + return; + m_qmlScope.set(qmlContext->engine(), *qmlContext); + m_v4Function = f; + m_compilationUnit = m_v4Function->compilationUnit; +} void QQmlJavaScriptExpression::clearActiveGuards() { diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 5f9cffb56d..0724038382 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -113,11 +113,16 @@ public: inline QObject *scopeObject() const; inline void setScopeObject(QObject *v); + QQmlSourceLocation sourceLocation() const; + void setSourceLocation(const QQmlSourceLocation &location); + bool isValid() const { return context() != 0; } QQmlContextData *context() const { return m_context; } void setContext(QQmlContextData *context); + QV4::Function *function() const; + virtual void refresh(); class DeleteWatcher { @@ -154,6 +159,8 @@ protected: } } + void setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f); + private: friend class QQmlContextData; friend class QQmlPropertyCapture; @@ -173,8 +180,10 @@ private: QQmlJavaScriptExpression *m_nextExpression; bool m_permanentDependenciesRegistered = false; -protected: - QV4::PersistentValue m_function; + QV4::PersistentValue m_qmlScope; + QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compilationUnit; + QV4::Function *m_v4Function; + QQmlSourceLocation *m_sourceLocation; // used for Qt.binding() created functions }; class QQmlPropertyCapture diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index 6f66475aa5..3876e774c3 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -107,8 +107,8 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::CallContext *ct QLocale::FormatType enumFormat = QLocale::LongFormat; QString formattedDt; if (ctx->argc() == 2) { - if (ctx->args()[1].isString()) { - QString format = ctx->args()[1].stringValue()->toQString(); + if (String *s = ctx->args()[1].stringValue()) { + QString format = s->toQString(); formattedDt = r->d()->locale->toString(dt, format); } else if (ctx->args()[1].isNumber()) { quint32 intFormat = ctx->args()[1].toNumber(); @@ -152,8 +152,8 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleTimeString(QV4::CallContext QLocale::FormatType enumFormat = QLocale::LongFormat; QString formattedTime; if (ctx->argc() == 2) { - if (ctx->args()[1].isString()) { - QString format = ctx->args()[1].stringValue()->toQString(); + if (String *s = ctx->args()[1].stringValue()) { + QString format = s->toQString(); formattedTime = r->d()->locale->toString(time, format); } else if (ctx->args()[1].isNumber()) { quint32 intFormat = ctx->args()[1].toNumber(); @@ -197,8 +197,8 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleDateString(QV4::CallContext QLocale::FormatType enumFormat = QLocale::LongFormat; QString formattedDate; if (ctx->argc() == 2) { - if (ctx->args()[1].isString()) { - QString format = ctx->args()[1].stringValue()->toQString(); + if (String *s = ctx->args()[1].stringValue()) { + QString format = s->toQString(); formattedDate = r->d()->locale->toString(date, format); } else if (ctx->args()[1].isNumber()) { quint32 intFormat = ctx->args()[1].toNumber(); @@ -217,11 +217,13 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleDateString(QV4::CallContext QV4::ReturnedValue QQmlDateExtension::method_fromLocaleString(QV4::CallContext *ctx) { QV4::ExecutionEngine * const engine = ctx->d()->engine; - if (ctx->argc() == 1 && ctx->args()[0].isString()) { - QLocale locale; - QString dateString = ctx->args()[0].stringValue()->toQString(); - QDateTime dt = locale.toDateTime(dateString); - return QV4::Encode(engine->newDateObject(dt)); + if (ctx->argc() == 1) { + if (String *s = ctx->args()[0].stringValue()) { + QLocale locale; + QString dateString = s->toQString(); + QDateTime dt = locale.toDateTime(dateString); + return QV4::Encode(engine->newDateObject(dt)); + } } QV4::Scope scope(ctx); @@ -235,8 +237,8 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleString(QV4::CallContext * QDateTime dt; QString dateString = ctx->args()[1].toQStringNoThrow(); if (ctx->argc() == 3) { - if (ctx->args()[2].isString()) { - QString format = ctx->args()[2].stringValue()->toQString(); + if (String *s = ctx->args()[2].stringValue()) { + QString format = s->toQString(); dt = r->d()->locale->toDateTime(dateString, format); } else if (ctx->args()[2].isNumber()) { quint32 intFormat = ctx->args()[2].toNumber(); @@ -256,13 +258,15 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallConte { QV4::ExecutionEngine * const engine = ctx->d()->engine; - if (ctx->argc() == 1 && ctx->args()[0].isString()) { - QLocale locale; - QString timeString = ctx->args()[0].stringValue()->toQString(); - QTime time = locale.toTime(timeString); - QDateTime dt = QDateTime::currentDateTime(); - dt.setTime(time); - return QV4::Encode(engine->newDateObject(dt)); + if (ctx->argc() == 1) { + if (String *s = ctx->args()[0].stringValue()) { + QLocale locale; + QString timeString = s->toQString(); + QTime time = locale.toTime(timeString); + QDateTime dt = QDateTime::currentDateTime(); + dt.setTime(time); + return QV4::Encode(engine->newDateObject(dt)); + } } if (ctx->argc() < 1 || ctx->argc() > 3 || !isLocaleObject(ctx->args()[0])) @@ -276,8 +280,8 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallConte QTime tm; QString dateString = ctx->args()[1].toQStringNoThrow(); if (ctx->argc() == 3) { - if (ctx->args()[2].isString()) { - QString format = ctx->args()[2].stringValue()->toQString(); + if (String *s = ctx->args()[2].stringValue()) { + QString format = s->toQString(); tm = r->d()->locale->toTime(dateString, format); } else if (ctx->args()[2].isNumber()) { quint32 intFormat = ctx->args()[2].toNumber(); @@ -303,11 +307,13 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleDateString(QV4::CallConte { QV4::ExecutionEngine * const engine = ctx->d()->engine; - if (ctx->argc() == 1 && ctx->args()[0].isString()) { - QLocale locale; - QString dateString = ctx->args()[0].stringValue()->toQString(); - QDate date = locale.toDate(dateString); - return QV4::Encode(engine->newDateObject(QDateTime(date))); + if (ctx->argc() == 1) { + if (String *s = ctx->args()[0].stringValue()) { + QLocale locale; + QString dateString = s->toQString(); + QDate date = locale.toDate(dateString); + return QV4::Encode(engine->newDateObject(QDateTime(date))); + } } if (ctx->argc() < 1 || ctx->argc() > 3 || !isLocaleObject(ctx->args()[0])) @@ -321,8 +327,8 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleDateString(QV4::CallConte QDate dt; QString dateString = ctx->args()[1].toQStringNoThrow(); if (ctx->argc() == 3) { - if (ctx->args()[2].isString()) { - QString format = ctx->args()[2].stringValue()->toQString(); + if (String *s = ctx->args()[2].stringValue()) { + QString format = s->toQString(); dt = r->d()->locale->toDate(dateString, format); } else if (ctx->args()[2].isNumber()) { quint32 intFormat = ctx->args()[2].toNumber(); diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index ce0f4b798a..51964a7d11 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -1158,7 +1158,7 @@ void qmlClearTypeRegistrations() // Declared in qqml.h data->uriToModule.clear(); QQmlEnginePrivate::baseModulesUninitialized = true; //So the engine re-registers its types -#ifndef QT_NO_LIBRARY +#if QT_CONFIG(library) qmlClearEnginePlugins(); #endif } diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 004e18576b..2e2a3fb303 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -44,7 +44,6 @@ #include <private/qv4function_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4qobjectwrapper_p.h> -#include <private/qqmlcontextwrapper_p.h> #include <private/qqmlbinding_p.h> #include <private/qqmlstringconverters_p.h> #include <private/qqmlboundsignal_p.h> @@ -402,7 +401,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const } } break; -#ifndef QT_NO_DATESTRING +#if QT_CONFIG(datestring) case QVariant::Date: { bool ok = false; QDate value = QQmlStringConverters::dateFromString(binding->valueAsString(qmlUnit), &ok); @@ -430,7 +429,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const property->writeProperty(_qobject, &value, propertyWriteFlags); } break; -#endif // QT_NO_DATESTRING +#endif // datestring case QVariant::Point: { bool ok = false; QPoint value = QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok).toPoint(); @@ -793,14 +792,13 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; QV4::Scope scope(v4); - QV4::ScopedContext qmlContext(scope, currentQmlContext()); - QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::createScriptFunction(qmlContext, runtimeFunction, /*createProto*/ false)); + QV4::Scoped<QV4::QmlContext> qmlContext(scope, currentQmlContext()); if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) { int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex()); QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine); QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_bindingTarget, signalIndex, - context, _scopeObject, function); + context, _scopeObject, runtimeFunction, qmlContext); bs->takeExpression(expr); } else { @@ -810,13 +808,14 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con // the result is written to a value type virtual property, that contains the sub-index // of the "x" property. QQmlBinding *qmlBinding; + const QQmlPropertyData *prop = property; + const QQmlPropertyData *subprop = nullptr; if (_valueTypeProperty) { - qmlBinding = QQmlBinding::create(_valueTypeProperty, function, _scopeObject, context); - qmlBinding->setTarget(_bindingTarget, *_valueTypeProperty, property); - } else { - qmlBinding = QQmlBinding::create(property, function, _scopeObject, context); - qmlBinding->setTarget(_bindingTarget, *property, nullptr); + prop = _valueTypeProperty; + subprop = property; } + qmlBinding = QQmlBinding::create(prop, runtimeFunction, _scopeObject, context, qmlContext); + qmlBinding->setTarget(_bindingTarget, *prop, subprop); sharedState->allCreatedBindings.push(QQmlAbstractBinding::Ptr(qmlBinding)); @@ -1017,7 +1016,7 @@ void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::O QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext() { if (!_qmlContext->isManaged()) - _qmlContext->setM(v4->rootContext()->newQmlContext(context, _scopeObject)); + _qmlContext->setM(QV4::QmlContext::create(v4->rootContext(), context, _scopeObject)); return _qmlContext->d(); } diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h index 2565ec0ce6..53062a2f13 100644 --- a/src/qml/qml/qqmlproperty_p.h +++ b/src/qml/qml/qqmlproperty_p.h @@ -115,30 +115,26 @@ public: }; Q_DECLARE_FLAGS(BindingFlags, BindingFlag) - static void setBinding(QQmlAbstractBinding *binding, BindingFlags flags = None, QQmlPropertyData::WriteFlags writeFlags = QQmlPropertyData::DontRemoveBinding); + static void setBinding(QQmlAbstractBinding *binding, BindingFlags flags = None, + QQmlPropertyData::WriteFlags writeFlags = QQmlPropertyData::DontRemoveBinding); static void removeBinding(const QQmlProperty &that); static void removeBinding(QObject *o, QQmlPropertyIndex index); static void removeBinding(QQmlAbstractBinding *b); static QQmlAbstractBinding *binding(QObject *, QQmlPropertyIndex index); - static QQmlProperty restore(QObject *, const QQmlPropertyData &, const QQmlPropertyData *, - QQmlContextData *); + static QQmlProperty restore(QObject *, const QQmlPropertyData &, const QQmlPropertyData *, QQmlContextData *); int signalIndex() const; - static inline QQmlPropertyPrivate *get(const QQmlProperty &p) { - return p.d; - } + static inline QQmlPropertyPrivate *get(const QQmlProperty &p) { return p.d; } // "Public" (to QML) methods static QQmlAbstractBinding *binding(const QQmlProperty &that); static void setBinding(const QQmlProperty &that, QQmlAbstractBinding *); static QQmlBoundSignalExpression *signalExpression(const QQmlProperty &that); - static void setSignalExpression(const QQmlProperty &that, - QQmlBoundSignalExpression *); - static void takeSignalExpression(const QQmlProperty &that, - QQmlBoundSignalExpression *); + static void setSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *); + static void takeSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *); static bool write(const QQmlProperty &that, const QVariant &, QQmlPropertyData::WriteFlags); static QQmlPropertyIndex propertyIndex(const QQmlProperty &that); static QMetaMethod findSignalByName(const QMetaObject *mo, const QByteArray &); diff --git a/src/qml/qml/qqmlstringconverters.cpp b/src/qml/qml/qqmlstringconverters.cpp index d2b3577a1f..e53f90b45b 100644 --- a/src/qml/qml/qqmlstringconverters.cpp +++ b/src/qml/qml/qqmlstringconverters.cpp @@ -71,14 +71,14 @@ QVariant QQmlStringConverters::variantFromString(const QString &s, int preferred return QVariant(int(qRound(s.toDouble(ok)))); case QMetaType::UInt: return QVariant(uint(qRound(s.toDouble(ok)))); -#ifndef QT_NO_DATESTRING +#if QT_CONFIG(datestring) case QMetaType::QDate: return QVariant::fromValue(dateFromString(s, ok)); case QMetaType::QTime: return QVariant::fromValue(timeFromString(s, ok)); case QMetaType::QDateTime: return QVariant::fromValue(dateTimeFromString(s, ok)); -#endif // QT_NO_DATESTRING +#endif // datestring case QMetaType::QPointF: return QVariant::fromValue(pointFFromString(s, ok)); case QMetaType::QPoint: @@ -106,7 +106,7 @@ unsigned QQmlStringConverters::rgbaFromString(const QString &s, bool *ok) return QQml_colorProvider()->rgbaFromString(s, ok); } -#ifndef QT_NO_DATESTRING +#if QT_CONFIG(datestring) QDate QQmlStringConverters::dateFromString(const QString &s, bool *ok) { QDate d = QDate::fromString(s, Qt::ISODate); @@ -130,7 +130,7 @@ QDateTime QQmlStringConverters::dateTimeFromString(const QString &s, bool *ok) d.setTimeSpec(Qt::UTC); return d; } -#endif // QT_NO_DATESTRING +#endif // datestring //expects input of "x,y" QPointF QQmlStringConverters::pointFFromString(const QString &s, bool *ok) @@ -229,7 +229,7 @@ bool QQmlStringConverters::createFromString(int type, const QString &s, void *da *p = uint(qRound(s.toDouble(&ok))); return ok; } -#ifndef QT_NO_DATESTRING +#if QT_CONFIG(datestring) case QMetaType::QDate: { Q_ASSERT(n >= sizeof(QDate)); @@ -251,7 +251,7 @@ bool QQmlStringConverters::createFromString(int type, const QString &s, void *da *p = dateTimeFromString(s, &ok); return ok; } -#endif // QT_NO_DATESTRING +#endif // datestring case QMetaType::QPointF: { Q_ASSERT(n >= sizeof(QPointF)); diff --git a/src/qml/qml/qqmlstringconverters_p.h b/src/qml/qml/qqmlstringconverters_p.h index b67cefaf35..af344e3344 100644 --- a/src/qml/qml/qqmlstringconverters_p.h +++ b/src/qml/qml/qqmlstringconverters_p.h @@ -72,7 +72,7 @@ namespace QQmlStringConverters Q_QML_PRIVATE_EXPORT QVariant colorFromString(const QString &, bool *ok = 0); Q_QML_PRIVATE_EXPORT unsigned rgbaFromString(const QString &, bool *ok = 0); -#ifndef QT_NO_DATESTRING +#if QT_CONFIG(datestring) Q_QML_PRIVATE_EXPORT QDate dateFromString(const QString &, bool *ok = 0); Q_QML_PRIVATE_EXPORT QTime timeFromString(const QString &, bool *ok = 0); Q_QML_PRIVATE_EXPORT QDateTime dateTimeFromString(const QString &, bool *ok = 0); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 09b9dcf452..7ad18c8efb 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -39,7 +39,6 @@ #include "qqmltypeloader_p.h" #include "qqmlabstracturlinterceptor.h" -#include "qqmlcontextwrapper_p.h" #include "qqmlexpression_p.h" #include <private/qqmlengine_p.h> @@ -2833,7 +2832,7 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent return QV4::Encode::undefined(); } - QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->rootContext()->newQmlContext(ctxt, 0)); + QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxt, 0)); qmlContext->takeContextOwnership(); m_program->qmlContext.set(scope.engine, qmlContext); diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 5c3ad6b2a6..fd1e9cc2be 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -38,7 +38,6 @@ ****************************************************************************/ #include "qqmltypewrapper_p.h" -#include <private/qqmlcontextwrapper_p.h> #include <private/qv8engine_p.h> #include <private/qqmlengine_p.h> diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index be93baf9f6..bbef62186a 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -43,7 +43,6 @@ #include <private/qqmlvaluetype_p.h> #include <private/qqmlbinding_p.h> #include <private/qqmlglobal_p.h> -#include <private/qqmlcontextwrapper_p.h> #include <private/qqmlbuiltinfunctions_p.h> #include <private/qv4engine_p.h> @@ -454,9 +453,10 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) cacheData.setCoreIndex(reference->d()->property); QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); - bindingFunction->initBindingLocation(); - QQmlBinding *newBinding = QQmlBinding::create(&cacheData, value, reference->d()->object, context); + QV4::ScopedContext ctx(scope, bindingFunction->scope()); + QQmlBinding *newBinding = QQmlBinding::create(&cacheData, bindingFunction->function(), reference->d()->object, context, ctx); + newBinding->setSourceLocation(bindingFunction->currentLocation()); newBinding->setTarget(reference->d()->object, cacheData, pd); QQmlPropertyPrivate::setBinding(newBinding); return; diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index 01c4f476d6..72d4ab7e8f 100644 --- a/src/qml/qml/qqmlvme.cpp +++ b/src/qml/qml/qqmlvme.cpp @@ -62,7 +62,6 @@ #include "qqmlpropertyvalueinterceptor_p.h" #include "qqmlvaluetypeproxybinding_p.h" #include "qqmlexpression_p.h" -#include "qqmlcontextwrapper_p.h" #include <QStack> #include <QPointF> diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index b08a0e5087..d2cbb99b6a 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -489,9 +489,9 @@ QString QQmlVMEMetaObject::readPropertyAsString(int id) QV4::Scope scope(cache->engine); QV4::ScopedValue sv(scope, *(md->data() + id)); - if (!sv->isString()) - return QString(); - return sv->stringValue()->toQString(); + if (QV4::String *s = sv->stringValue()) + return s->toQString(); + return QString(); } QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id) diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 10b1cbcfd4..47751aa2c6 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -50,7 +50,6 @@ #include <private/qv4domerrors_p.h> #include <private/qv4engine_p.h> #include <private/qv4functionobject_p.h> -#include <private/qqmlcontextwrapper_p.h> #include <private/qv4scopedvalue_p.h> #include <QtCore/qobject.h> @@ -70,7 +69,7 @@ using namespace QV4; -#if !defined(QT_NO_XMLSTREAMREADER) && QT_CONFIG(qml_network) +#if QT_CONFIG(xmlstreamreader) && QT_CONFIG(qml_network) #define V4THROW_REFERENCE(string) { \ ScopedObject error(scope, ctx->engine()->newReferenceErrorObject(QStringLiteral(string))); \ @@ -1068,7 +1067,7 @@ private: QByteArray m_mime; QByteArray m_charset; QTextCodec *m_textCodec; -#ifndef QT_NO_TEXTCODEC +#if QT_CONFIG(textcodec) QTextCodec* findTextCodec() const; #endif void readEncoding(); @@ -1510,7 +1509,7 @@ QV4::ReturnedValue QQmlXMLHttpRequest::xmlResponseBody(QV4::ExecutionEngine* eng return m_parsedDocument.value(); } -#ifndef QT_NO_TEXTCODEC +#if QT_CONFIG(textcodec) QTextCodec* QQmlXMLHttpRequest::findTextCodec() const { QTextCodec *codec = 0; @@ -1539,7 +1538,7 @@ QTextCodec* QQmlXMLHttpRequest::findTextCodec() const QString QQmlXMLHttpRequest::responseBody() { -#ifndef QT_NO_TEXTCODEC +#if QT_CONFIG(textcodec) if (!m_textCodec) m_textCodec = findTextCodec(); if (m_textCodec) @@ -2056,6 +2055,6 @@ void *qt_add_qmlxmlhttprequest(ExecutionEngine *v4) QT_END_NAMESPACE -#endif // QT_NO_XMLSTREAMREADER && qml_network +#endif // xmlstreamreader && qml_network #include <qqmlxmlhttprequest.moc> diff --git a/src/qml/qml/qqmlxmlhttprequest_p.h b/src/qml/qml/qqmlxmlhttprequest_p.h index fdb6194537..f2836d8301 100644 --- a/src/qml/qml/qqmlxmlhttprequest_p.h +++ b/src/qml/qml/qqmlxmlhttprequest_p.h @@ -55,7 +55,7 @@ #include <QtCore/qglobal.h> #include <private/qqmlglobal_p.h> -#if !defined(QT_NO_XMLSTREAMREADER) && QT_CONFIG(qml_network) +#if QT_CONFIG(xmlstreamreader) && QT_CONFIG(qml_network) QT_BEGIN_NAMESPACE @@ -64,7 +64,7 @@ void qt_rem_qmlxmlhttprequest(QV4::ExecutionEngine *engine, void *); QT_END_NAMESPACE -#endif // QT_NO_XMLSTREAMREADER && qml_network +#endif // xmlstreamreader && qml_network #endif // QQMLXMLHTTPREQUEST_P_H diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index c8a0463a2d..19dc100f40 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -148,9 +148,7 @@ void Heap::QtObject::init(QQmlEngine *qmlEngine) o->defineAccessorProperty(QStringLiteral("platform"), QV4::QtObject::method_get_platform, 0); o->defineAccessorProperty(QStringLiteral("application"), QV4::QtObject::method_get_application, 0); -#ifndef QT_NO_IM o->defineAccessorProperty(QStringLiteral("inputMethod"), QV4::QtObject::method_get_inputMethod, 0); -#endif o->defineAccessorProperty(QStringLiteral("styleHints"), QV4::QtObject::method_get_styleHints, 0); o->defineDefaultProperty(QStringLiteral("callLater"), QV4::QtObject::method_callLater); @@ -1305,30 +1303,15 @@ ReturnedValue QtObject::method_locale(CallContext *ctx) void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *originalFunction) { - QV4::Heap::FunctionObject::init(originalFunction->scope(), originalFunction->name()); - bindingLocation = new QQmlSourceLocation; - this->originalFunction = originalFunction->d(); + Scope scope(originalFunction->engine()); + ScopedContext context(scope, originalFunction->scope()); + FunctionObject::init(context, originalFunction->function()); } -void QQmlBindingFunction::initBindingLocation() +QQmlSourceLocation QQmlBindingFunction::currentLocation() const { QV4::StackFrame frame = engine()->currentStackFrame(); - d()->bindingLocation->sourceFile = frame.source; - d()->bindingLocation->line = frame.line; -} - -void QQmlBindingFunction::call(const Managed *that, Scope &scope, CallData *callData) -{ - ScopedFunctionObject function(scope, static_cast<const QQmlBindingFunction*>(that)->d()->originalFunction); - function->call(scope, callData); -} - -void QQmlBindingFunction::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - QQmlBindingFunction::Data *This = static_cast<QQmlBindingFunction::Data *>(that); - if (This->originalFunction) - This->originalFunction->mark(e); - QV4::FunctionObject::markObjects(that, e); + return QQmlSourceLocation(frame.source, frame.line, 0); } DEFINE_OBJECT_VTABLE(QQmlBindingFunction); @@ -1423,13 +1406,11 @@ ReturnedValue QtObject::method_get_application(CallContext *ctx) return QV4::QObjectWrapper::wrap(ctx->d()->engine, qt->d()->application); } -#ifndef QT_NO_IM ReturnedValue QtObject::method_get_inputMethod(CallContext *ctx) { QObject *o = QQml_guiProvider()->inputMethod(); return QV4::QObjectWrapper::wrap(ctx->d()->engine, o); } -#endif ReturnedValue QtObject::method_get_styleHints(CallContext *ctx) { @@ -1740,7 +1721,7 @@ void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions ext Scope scope(v4); if (extensions.testFlag(QJSEngine::TranslationExtension)) { - #ifndef QT_NO_TRANSLATION + #if QT_CONFIG(translation) globalObject->defineDefaultProperty(QStringLiteral("qsTranslate"), QV4::GlobalExtensions::method_qsTranslate); globalObject->defineDefaultProperty(QStringLiteral("QT_TRANSLATE_NOOP"), QV4::GlobalExtensions::method_qsTranslateNoOp); globalObject->defineDefaultProperty(QStringLiteral("qsTr"), QV4::GlobalExtensions::method_qsTr); @@ -1767,7 +1748,7 @@ void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions ext } -#ifndef QT_NO_TRANSLATION +#if QT_CONFIG(translation) /*! \qmlmethod string Qt::qsTranslate(string context, string sourceText, string disambiguation, int n) @@ -2015,7 +1996,7 @@ ReturnedValue GlobalExtensions::method_qsTrIdNoOp(CallContext *ctx) return QV4::Encode::undefined(); return ctx->args()[0].asReturnedValue(); } -#endif // QT_NO_TRANSLATION +#endif // translation QV4::ReturnedValue GlobalExtensions::method_gc(CallContext *ctx) diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index f428e377d7..fe43532647 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -82,13 +82,6 @@ struct ConsoleObject : Object { struct QQmlBindingFunction : FunctionObject { void init(const QV4::FunctionObject *originalFunction); - void destroy() { - delete bindingLocation; - Object::destroy(); - } - Pointer<FunctionObject> originalFunction; - // Set when the binding is created later - QQmlSourceLocation *bindingLocation; }; } @@ -135,9 +128,7 @@ struct QtObject : Object static ReturnedValue method_get_platform(CallContext *ctx); static ReturnedValue method_get_application(CallContext *ctx); -#ifndef QT_NO_IM static ReturnedValue method_get_inputMethod(CallContext *ctx); -#endif static ReturnedValue method_get_styleHints(CallContext *ctx); static ReturnedValue method_callLater(CallContext *ctx); @@ -169,7 +160,7 @@ struct ConsoleObject : Object struct Q_QML_PRIVATE_EXPORT GlobalExtensions { static void init(Object *globalObject, QJSEngine::Extensions extensions); -#ifndef QT_NO_TRANSLATION +#if QT_CONFIG(translation) static ReturnedValue method_qsTranslate(CallContext *ctx); static ReturnedValue method_qsTranslateNoOp(CallContext *ctx); static ReturnedValue method_qsTr(CallContext *ctx); @@ -187,13 +178,8 @@ struct Q_QML_PRIVATE_EXPORT GlobalExtensions { struct QQmlBindingFunction : public QV4::FunctionObject { V4_OBJECT2(QQmlBindingFunction, FunctionObject) - V4_NEEDS_DESTROY - - void initBindingLocation(); // from caller stack trace - - static void call(const Managed *that, Scope &scope, CallData *callData); - static void markObjects(Heap::Base *that, ExecutionEngine *e); + QQmlSourceLocation currentLocation() const; // from caller stack trace }; } diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index b0599dd0a2..dadff819cf 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -52,7 +52,6 @@ #include <private/qqmlplatform_p.h> #include <private/qjsvalue_p.h> #include <private/qqmltypewrapper_p.h> -#include <private/qqmlcontextwrapper_p.h> #include <private/qqmlvaluetypewrapper_p.h> #include <private/qqmllistwrapper_p.h> #include <private/qv4scopedvalue_p.h> @@ -160,7 +159,7 @@ QV8Engine::~QV8Engine() qDeleteAll(m_extensionData); m_extensionData.clear(); -#if !defined(QT_NO_XMLSTREAMREADER) && QT_CONFIG(qml_network) +#if QT_CONFIG(xmlstreamreader) && QT_CONFIG(qml_network) qt_rem_qmlxmlhttprequest(m_v4Engine, m_xmlHttpRequestData); m_xmlHttpRequestData = 0; #endif @@ -195,7 +194,7 @@ void QV8Engine::initializeGlobal() QQmlDateExtension::registerExtension(m_v4Engine); QQmlNumberExtension::registerExtension(m_v4Engine); -#if !defined(QT_NO_XMLSTREAMREADER) && QT_CONFIG(qml_network) +#if QT_CONFIG(xmlstreamreader) && QT_CONFIG(qml_network) qt_add_domexceptions(m_v4Engine); m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(m_v4Engine); #endif diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index 2ba164f721..8574a4784c 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -505,10 +505,10 @@ void ListModel::set(int elementIndex, QV4::Object *object) break; // Add the value now - if (propertyValue->isString()) { + if (QV4::String *s = propertyValue->stringValue()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String); if (r.type == ListLayout::Role::String) - e->setStringPropertyFast(r, propertyValue->stringValue()->toQString()); + e->setStringPropertyFast(r, s->toQString()); } else if (propertyValue->isNumber()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number); if (r.type == ListLayout::Role::Number) { diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp index 78e7776c9b..e095eabce8 100644 --- a/src/qml/types/qquickworkerscript.cpp +++ b/src/qml/types/qquickworkerscript.cpp @@ -42,7 +42,6 @@ #include "qqmllistmodelworkeragent_p.h" #include <private/qqmlengine_p.h> #include <private/qqmlexpression_p.h> -#include <private/qqmlcontextwrapper_p.h> #include <QtCore/qcoreevent.h> #include <QtCore/qcoreapplication.h> @@ -318,19 +317,8 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::getWorker(WorkerScript *scri QV4::ExecutionEngine *v4 = QV8Engine::getV4(workerEngine); QV4::Scope scope(v4); - - QV4::Scoped<QV4::QmlContextWrapper> w(scope, QV4::QmlContextWrapper::urlScope(v4, script->source)); - Q_ASSERT(!!w); - w->setReadOnly(false); - - QV4::ScopedObject api(scope, v4->newObject()); - api->put(QV4::ScopedString(scope, v4->newString(QStringLiteral("sendMessage"))), QV4::ScopedValue(scope, workerEngine->sendFunction(script->id))); - - w->QV4::Object::put(QV4::ScopedString(scope, v4->newString(QStringLiteral("WorkerScript"))), api); - - w->setReadOnly(true); - - script->qmlContext.set(v4, v4->rootContext()->newQmlContext(w)); + QV4::ScopedValue v(scope, workerEngine->sendFunction(script->id)); + script->qmlContext.set(v4, QV4::QmlContext::createWorkerContext(v4->rootContext(), script->source, v)); } return script->qmlContext.value(); |