diff options
Diffstat (limited to 'src/qml')
229 files changed, 5486 insertions, 11601 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 63833504f1..4b1e3601dc 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -33,7 +33,7 @@ #include "qqmlirbuilder_p.h" -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4compileddata_p.h> #include <private/qqmljsparser_p.h> #include <private/qqmljslexer_p.h> @@ -1456,10 +1456,8 @@ JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, QV4::IR , _disableAcceleratedLookups(false) , _contextObject(0) , _scopeObject(0) - , _contextObjectTemp(-1) - , _scopeObjectTemp(-1) + , _qmlContextTemp(-1) , _importedScriptsTemp(-1) - , _idArrayTemp(-1) { _module = jsModule; _module->setFileName(fileName); @@ -1764,24 +1762,14 @@ static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, void JSCodeGen::beginFunctionBodyHook() { - _contextObjectTemp = _block->newTemp(); - _scopeObjectTemp = _block->newTemp(); + _qmlContextTemp = _block->newTemp(); _importedScriptsTemp = _block->newTemp(); - _idArrayTemp = _block->newTemp(); #ifndef V4_BOOTSTRAP - QV4::IR::Temp *temp = _block->TEMP(_contextObjectTemp); - temp->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>(); - initMetaObjectResolver(temp->memberResolver, _contextObject); - move(temp, _block->NAME(QV4::IR::Name::builtin_qml_context_object, 0, 0)); - - temp = _block->TEMP(_scopeObjectTemp); - temp->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>(); - initMetaObjectResolver(temp->memberResolver, _scopeObject); - move(temp, _block->NAME(QV4::IR::Name::builtin_qml_scope_object, 0, 0)); + QV4::IR::Temp *temp = _block->TEMP(_qmlContextTemp); + move(temp, _block->NAME(QV4::IR::Name::builtin_qml_context, 0, 0)); move(_block->TEMP(_importedScriptsTemp), _block->NAME(QV4::IR::Name::builtin_qml_imported_scripts_object, 0, 0)); - move(_block->TEMP(_idArrayTemp), _block->NAME(QV4::IR::Name::builtin_qml_id_array, 0, 0)); #endif } @@ -1807,7 +1795,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int foreach (const IdMapping &mapping, _idObjects) if (name == mapping.name) { _function->idObjectDependencies.insert(mapping.idIndex); - QV4::IR::Expr *s = subscript(_block->TEMP(_idArrayTemp), _block->CONST(QV4::IR::SInt32Type, mapping.idIndex)); + QV4::IR::Expr *s = _block->MEMBER(_block->TEMP(_qmlContextTemp), _function->newString(name), 0, QV4::IR::Member::MemberOfIdObjectsArray, mapping.idIndex); QV4::IR::Temp *result = _block->TEMP(_block->newTemp()); _block->MOVE(result, s); result = _block->TEMP(result->index); @@ -1857,7 +1845,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int if (propertyExistsButForceNameLookup) return 0; if (pd) { - QV4::IR::Temp *base = _block->TEMP(_scopeObjectTemp); + QV4::IR::Temp *base = _block->TEMP(_qmlContextTemp); base->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>(); initMetaObjectResolver(base->memberResolver, _scopeObject); return _block->MEMBER(base, _function->newString(name), pd, QV4::IR::Member::MemberOfQmlScopeObject); @@ -1870,7 +1858,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int if (propertyExistsButForceNameLookup) return 0; if (pd) { - QV4::IR::Temp *base = _block->TEMP(_contextObjectTemp); + QV4::IR::Temp *base = _block->TEMP(_qmlContextTemp); base->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>(); initMetaObjectResolver(base->memberResolver, _contextObject); return _block->MEMBER(base, _function->newString(name), pd, QV4::IR::Member::MemberOfQmlContextObject); diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 120de91321..5617912081 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -34,7 +34,6 @@ #define QQMLIRBUILDER_P_H #include <private/qqmljsast_p.h> -#include <private/qqmlpool_p.h> #include <private/qqmljsengine_p.h> #include <private/qv4compiler_p.h> #include <private/qv4compileddata_p.h> @@ -496,10 +495,8 @@ private: ObjectIdMapping _idObjects; QQmlPropertyCache *_contextObject; QQmlPropertyCache *_scopeObject; - int _contextObjectTemp; - int _scopeObjectTemp; + int _qmlContextTemp; int _importedScriptsTemp; - int _idArrayTemp; }; } // namespace QmlIR diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 4e9817aa0d..307f945d20 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -104,11 +104,10 @@ bool QQmlTypeCompiler::compile() } if (ref->type->containsRevisionedAttributes()) { - QQmlError cacheError; ref->typePropertyCache = engine->cache(ref->type, - resolvedType->minorVersion, - cacheError); + resolvedType->minorVersion); if (!ref->typePropertyCache) { + QQmlError cacheError; cacheError.setColumn(resolvedType->location.column); cacheError.setLine(resolvedType->location.line); recordError(cacheError); @@ -696,6 +695,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob const int paramCount = s->parameters->count; QList<QByteArray> names; + names.reserve(paramCount); QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0); if (paramCount) { @@ -1022,10 +1022,10 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio } } - QHash<QString, QStringList>::ConstIterator entry = customSignals.find(propertyName); + QHash<QString, QStringList>::ConstIterator entry = customSignals.constFind(propertyName); if (entry == customSignals.constEnd() && propertyName.endsWith(QStringLiteral("Changed"))) { QString alternateName = propertyName.mid(0, propertyName.length() - static_cast<int>(strlen("Changed"))); - entry = customSignals.find(alternateName); + entry = customSignals.constFind(alternateName); } if (entry == customSignals.constEnd()) { @@ -2017,7 +2017,7 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD customParserBindingsPerObject->insert(objectIndex, customParserBindings); const QList<QQmlError> parserErrors = customParser->errors(); if (!parserErrors.isEmpty()) { - foreach (QQmlError error, parserErrors) + foreach (const QQmlError &error, parserErrors) compiler->recordError(error); return false; } @@ -2623,10 +2623,8 @@ void QQmlJavaScriptBindingExpressionSimplificationPass::visitMove(QV4::IR::Move } if (QV4::IR::Name *n = move->source->asName()) { - if (n->builtin == QV4::IR::Name::builtin_qml_id_array - || n->builtin == QV4::IR::Name::builtin_qml_imported_scripts_object - || n->builtin == QV4::IR::Name::builtin_qml_context_object - || n->builtin == QV4::IR::Name::builtin_qml_scope_object) { + if (n->builtin == QV4::IR::Name::builtin_qml_context + || n->builtin == QV4::IR::Name::builtin_qml_imported_scripts_object) { // these are free of side-effects return; } diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 9168889c8c..ea82d07e69 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -33,6 +33,7 @@ #include "qv4codegen_p.h" #include "qv4util_p.h" +#include "qv4engine_p.h" #include <QtCore/QCoreApplication> #include <QtCore/QStringList> @@ -43,7 +44,7 @@ #include <QtCore/QStack> #include <private/qqmljsast_p.h> #include <private/qv4string_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #ifndef V4_BOOTSTRAP #include <qv4context_p.h> diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 5d954eb4fc..20db5edaa3 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -33,7 +33,7 @@ #include "qv4compileddata_p.h" #include "qv4jsir_p.h" -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #ifndef V4_BOOTSTRAP #include <private/qv4engine_p.h> #include <private/qv4function_p.h> diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 450889c275..ba4bde7a31 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -35,7 +35,7 @@ #include <qv4compileddata_p.h> #include <qv4isel_p.h> #include <private/qv4string_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> QV4::Compiler::StringTableGenerator::StringTableGenerator() { @@ -44,8 +44,8 @@ QV4::Compiler::StringTableGenerator::StringTableGenerator() int QV4::Compiler::StringTableGenerator::registerString(const QString &str) { - QHash<QString, int>::ConstIterator it = stringToId.find(str); - if (it != stringToId.end()) + QHash<QString, int>::ConstIterator it = stringToId.constFind(str); + if (it != stringToId.cend()) return *it; stringToId.insert(str, strings.size()); strings.append(str); @@ -169,6 +169,7 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, IR::ExprList *arg // ### re-use existing class definitions. QList<CompiledData::JSClassMember> members; + members.reserve(count); IR::ExprList *it = args; for (int i = 0; i < count; ++i, it = it->next) { diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 5c2ad45da2..6839c7f609 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -64,12 +64,19 @@ QT_BEGIN_NAMESPACE F(SetLookup, setLookup) \ F(StoreQObjectProperty, storeQObjectProperty) \ F(LoadQObjectProperty, loadQObjectProperty) \ + F(StoreScopeObjectProperty, storeScopeObjectProperty) \ + F(StoreContextObjectProperty, storeContextObjectProperty) \ + F(LoadScopeObjectProperty, loadScopeObjectProperty) \ + F(LoadContextObjectProperty, loadContextObjectProperty) \ + F(LoadIdObject, loadIdObject) \ F(LoadAttachedQObjectProperty, loadAttachedQObjectProperty) \ F(LoadSingletonQObjectProperty, loadQObjectProperty) \ F(Push, push) \ F(CallValue, callValue) \ F(CallProperty, callProperty) \ F(CallPropertyLookup, callPropertyLookup) \ + F(CallScopeObjectProperty, callScopeObjectProperty) \ + F(CallContextObjectProperty, callContextObjectProperty) \ F(CallElement, callElement) \ F(CallActivationProperty, callActivationProperty) \ F(CallGlobalLookup, callGlobalLookup) \ @@ -125,10 +132,8 @@ QT_BEGIN_NAMESPACE F(Sub, sub) \ F(BinopContext, binopContext) \ F(LoadThis, loadThis) \ - F(LoadQmlIdArray, loadQmlIdArray) \ + F(LoadQmlContext, loadQmlContext) \ F(LoadQmlImportedScripts, loadQmlImportedScripts) \ - F(LoadQmlContextObject, loadQmlContextObject) \ - F(LoadQmlScopeObject, loadQmlScopeObject) \ F(LoadQmlSingleton, loadQmlSingleton) #if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200) @@ -293,6 +298,24 @@ union Instr Param base; Param result; }; + struct instr_loadScopeObjectProperty { + MOTH_INSTR_HEADER + int propertyIndex; + Param base; + Param result; + }; + struct instr_loadContextObjectProperty { + MOTH_INSTR_HEADER + int propertyIndex; + Param base; + Param result; + }; + struct instr_loadIdObject { + MOTH_INSTR_HEADER + int index; + Param base; + Param result; + }; struct instr_loadQObjectProperty { MOTH_INSTR_HEADER int propertyIndex; @@ -318,6 +341,18 @@ union Instr Param base; Param source; }; + struct instr_storeScopeObjectProperty { + MOTH_INSTR_HEADER + Param base; + int propertyIndex; + Param source; + }; + struct instr_storeContextObjectProperty { + MOTH_INSTR_HEADER + Param base; + int propertyIndex; + Param source; + }; struct instr_storeQObjectProperty { MOTH_INSTR_HEADER Param base; @@ -377,6 +412,22 @@ union Instr Param base; Param result; }; + struct instr_callScopeObjectProperty { + MOTH_INSTR_HEADER + int index; + quint32 argc; + quint32 callData; + Param base; + Param result; + }; + struct instr_callContextObjectProperty { + MOTH_INSTR_HEADER + int index; + quint32 argc; + quint32 callData; + Param base; + Param result; + }; struct instr_callElement { MOTH_INSTR_HEADER Param base; @@ -684,7 +735,7 @@ union Instr MOTH_INSTR_HEADER Param result; }; - struct instr_loadQmlIdArray { + struct instr_loadQmlContext { MOTH_INSTR_HEADER Param result; }; @@ -692,14 +743,6 @@ union Instr MOTH_INSTR_HEADER Param result; }; - struct instr_loadQmlContextObject { - MOTH_INSTR_HEADER - Param result; - }; - struct instr_loadQmlScopeObject { - MOTH_INSTR_HEADER - Param result; - }; struct instr_loadQmlSingleton { MOTH_INSTR_HEADER Param result; @@ -725,15 +768,22 @@ union Instr instr_storeElementLookup storeElementLookup; instr_loadProperty loadProperty; instr_getLookup getLookup; + instr_loadScopeObjectProperty loadScopeObjectProperty; + instr_loadContextObjectProperty loadContextObjectProperty; + instr_loadIdObject loadIdObject; instr_loadQObjectProperty loadQObjectProperty; instr_loadAttachedQObjectProperty loadAttachedQObjectProperty; instr_storeProperty storeProperty; instr_setLookup setLookup; + instr_storeScopeObjectProperty storeScopeObjectProperty; + instr_storeContextObjectProperty storeContextObjectProperty; instr_storeQObjectProperty storeQObjectProperty; instr_push push; instr_callValue callValue; instr_callProperty callProperty; instr_callPropertyLookup callPropertyLookup; + instr_callScopeObjectProperty callScopeObjectProperty; + instr_callContextObjectProperty callContextObjectProperty; instr_callElement callElement; instr_callActivationProperty callActivationProperty; instr_callGlobalLookup callGlobalLookup; @@ -789,10 +839,8 @@ union Instr instr_sub sub; instr_binopContext binopContext; instr_loadThis loadThis; - instr_loadQmlIdArray loadQmlIdArray; + instr_loadQmlContext loadQmlContext; instr_loadQmlImportedScripts loadQmlImportedScripts; - instr_loadQmlContextObject loadQmlContextObject; - instr_loadQmlScopeObject loadQmlScopeObject; instr_loadQmlSingleton loadQmlSingleton; static int size(Type type); diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index eb78a0c054..ede1e6938f 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -447,7 +447,7 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection::backend foreach (IR::Function *irFunction, irModule->functions) compilationUnit->codeRefs[i++] = codeRefs[irFunction]; QQmlRefPointer<QV4::CompiledData::CompilationUnit> result; - result.take(compilationUnit.take()); + result.adopt(compilationUnit.take()); return result; } @@ -461,6 +461,29 @@ void InstructionSelection::callValue(IR::Expr *value, IR::ExprList *args, IR::Ex addInstruction(call); } +void InstructionSelection::callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result) +{ + if (kind == IR::Member::MemberOfQmlScopeObject) { + Instruction::CallScopeObjectProperty call; + call.base = getParam(base); + call.index = propertyIndex; + prepareCallArgs(args, call.argc); + call.callData = callDataStart(); + call.result = getResultParam(result); + addInstruction(call); + } else if (kind == IR::Member::MemberOfQmlContextObject) { + Instruction::CallContextObjectProperty call; + call.base = getParam(base); + call.index = propertyIndex; + prepareCallArgs(args, call.argc); + call.callData = callDataStart(); + call.result = getResultParam(result); + addInstruction(call); + } else { + Q_ASSERT(false); + } +} + void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) { @@ -565,9 +588,9 @@ void InstructionSelection::loadThisObject(IR::Expr *e) addInstruction(load); } -void InstructionSelection::loadQmlIdArray(IR::Expr *e) +void InstructionSelection::loadQmlContext(IR::Expr *e) { - Instruction::LoadQmlIdArray load; + Instruction::LoadQmlContext load; load.result = getResultParam(e); addInstruction(load); } @@ -579,20 +602,6 @@ void InstructionSelection::loadQmlImportedScripts(IR::Expr *e) addInstruction(load); } -void InstructionSelection::loadQmlContextObject(IR::Expr *e) -{ - Instruction::LoadQmlContextObject load; - load.result = getResultParam(e); - addInstruction(load); -} - -void InstructionSelection::loadQmlScopeObject(IR::Expr *e) -{ - Instruction::LoadQmlScopeObject load; - load.result = getResultParam(e); - addInstruction(load); -} - void InstructionSelection::loadQmlSingleton(const QString &name, IR::Expr *e) { Instruction::LoadQmlSingleton load; @@ -694,6 +703,25 @@ void InstructionSelection::setProperty(IR::Expr *source, IR::Expr *targetBase, addInstruction(store); } +void InstructionSelection::setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex) +{ + if (kind == IR::Member::MemberOfQmlScopeObject) { + Instruction::StoreScopeObjectProperty store; + store.base = getParam(targetBase); + store.propertyIndex = propertyIndex; + store.source = getParam(source); + addInstruction(store); + } else if (kind == IR::Member::MemberOfQmlContextObject) { + Instruction::StoreContextObjectProperty store; + store.base = getParam(targetBase); + store.propertyIndex = propertyIndex; + store.source = getParam(source); + addInstruction(store); + } else { + Q_ASSERT(false); + } +} + void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex) { Instruction::StoreQObjectProperty store; @@ -703,6 +731,31 @@ void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *target addInstruction(store); } +void InstructionSelection::getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target) +{ + if (kind == IR::Member::MemberOfQmlScopeObject) { + Instruction::LoadScopeObjectProperty load; + load.base = getParam(source); + load.propertyIndex = index; + load.result = getResultParam(target); + addInstruction(load); + } else if (kind == IR::Member::MemberOfQmlContextObject) { + Instruction::LoadContextObjectProperty load; + load.base = getParam(source); + load.propertyIndex = index; + load.result = getResultParam(target); + addInstruction(load); + } else if (kind == IR::Member::MemberOfIdObjectsArray) { + Instruction::LoadIdObject load; + load.base = getParam(source); + load.index = index; + load.result = getResultParam(target); + addInstruction(load); + } else { + Q_ASSERT(false); + } +} + void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target) { if (attachedPropertiesId != 0) { @@ -1444,7 +1497,7 @@ ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &in void InstructionSelection::patchJumpAddresses() { typedef QHash<IR::BasicBlock *, QVector<ptrdiff_t> >::ConstIterator PatchIt; - for (PatchIt i = _patches.begin(), ei = _patches.end(); i != ei; ++i) { + for (PatchIt i = _patches.cbegin(), ei = _patches.cend(); i != ei; ++i) { Q_ASSERT(_addrs.contains(i.key())); ptrdiff_t target = _addrs.value(i.key()); diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h index 4ea0f1d07f..ac1eaba740 100644 --- a/src/qml/compiler/qv4isel_moth_p.h +++ b/src/qml/compiler/qv4isel_moth_p.h @@ -95,6 +95,7 @@ protected: virtual void callBuiltinSetupArgumentObject(IR::Expr *result); virtual void callBuiltinConvertThisToObject(); virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result); + virtual void callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result); virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result); virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Expr *result); virtual void convertType(IR::Expr *source, IR::Expr *target); @@ -102,10 +103,8 @@ protected: virtual void constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result); virtual void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result); virtual void loadThisObject(IR::Expr *e); - virtual void loadQmlIdArray(IR::Expr *e); + virtual void loadQmlContext(IR::Expr *e); virtual void loadQmlImportedScripts(IR::Expr *e); - virtual void loadQmlContextObject(IR::Expr *e); - virtual void loadQmlScopeObject(IR::Expr *e); virtual void loadQmlSingleton(const QString &name, IR::Expr *e); virtual void loadConst(IR::Const *sourceConst, IR::Expr *e); virtual void loadString(const QString &str, IR::Expr *target); @@ -115,7 +114,9 @@ protected: virtual void initClosure(IR::Closure *closure, IR::Expr *target); virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target); virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName); + virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex); virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex); + virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target); virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target); virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target); virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex); diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp index 54b184b4eb..9d172b1223 100644 --- a/src/qml/compiler/qv4isel_p.cpp +++ b/src/qml/compiler/qv4isel_p.cpp @@ -36,7 +36,7 @@ #include "qv4jsir_p.h" #include "qv4isel_p.h" #include "qv4isel_util_p.h" -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #ifndef V4_BOOTSTRAP #include <private/qqmlpropertycache_p.h> #endif @@ -91,12 +91,8 @@ void IRDecoder::visitMove(IR::Move *s) if (IR::Name *n = s->source->asName()) { if (n->id && *n->id == QStringLiteral("this")) // TODO: `this' should be a builtin. loadThisObject(s->target); - else if (n->builtin == IR::Name::builtin_qml_id_array) - loadQmlIdArray(s->target); - else if (n->builtin == IR::Name::builtin_qml_context_object) - loadQmlContextObject(s->target); - else if (n->builtin == IR::Name::builtin_qml_scope_object) - loadQmlScopeObject(s->target); + else if (n->builtin == IR::Name::builtin_qml_context) + loadQmlContext(s->target); else if (n->builtin == IR::Name::builtin_qml_imported_scripts_object) loadQmlImportedScripts(s->target); else if (n->qmlSingleton) @@ -140,8 +136,8 @@ void IRDecoder::visitMove(IR::Move *s) #else bool captureRequired = true; - Q_ASSERT(m->kind != IR::Member::MemberOfEnum); - const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue; + Q_ASSERT(m->kind != IR::Member::MemberOfEnum && m->kind != IR::Member::MemberOfIdObjectsArray); + const int attachedPropertiesId = m->attachedPropertiesId; const bool isSingletonProperty = m->kind == IR::Member::MemberOfSingletonObject; if (_function && attachedPropertiesId == 0 && !m->property->isConstant()) { @@ -153,9 +149,16 @@ void IRDecoder::visitMove(IR::Move *s) captureRequired = false; } } + if (m->kind == IR::Member::MemberOfQmlScopeObject || m->kind == IR::Member::MemberOfQmlContextObject) { + getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, m->property->coreIndex, s->target); + return; + } getQObjectProperty(m->base, m->property->coreIndex, captureRequired, isSingletonProperty, attachedPropertiesId, s->target); #endif // V4_BOOTSTRAP return; + } else if (m->kind == IR::Member::MemberOfIdObjectsArray) { + getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, m->idIndex, s->target); + return; } else if (m->base->asTemp() || m->base->asConst() || m->base->asArgLocal()) { getProperty(m->base, *m->name, s->target); return; @@ -174,6 +177,13 @@ void IRDecoder::visitMove(IR::Move *s) callBuiltin(c, s->target); return; } else if (Member *member = c->base->asMember()) { +#ifndef V4_BOOTSTRAP + Q_ASSERT(member->kind != IR::Member::MemberOfIdObjectsArray); + if (member->kind == IR::Member::MemberOfQmlScopeObject || member->kind == IR::Member::MemberOfQmlContextObject) { + callQmlContextProperty(member->base, (IR::Member::MemberKind)member->kind, member->property->coreIndex, c->args, s->target); + return; + } +#endif callProperty(member->base, *member->name, c->args, s->target); return; } else if (Subscript *ss = c->base->asSubscript()) { @@ -192,11 +202,16 @@ void IRDecoder::visitMove(IR::Move *s) if (m->base->asTemp() || m->base->asConst() || m->base->asArgLocal()) { if (s->source->asTemp() || s->source->asConst() || s->source->asArgLocal()) { Q_ASSERT(m->kind != IR::Member::MemberOfEnum); - const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue; + Q_ASSERT(m->kind != IR::Member::MemberOfIdObjectsArray); + const int attachedPropertiesId = m->attachedPropertiesId; if (m->property && attachedPropertiesId == 0) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else + if (m->kind == IR::Member::MemberOfQmlScopeObject || m->kind == IR::Member::MemberOfQmlContextObject) { + setQmlContextProperty(s->source, m->base, (IR::Member::MemberKind)m->kind, m->property->coreIndex); + return; + } setQObjectProperty(s->source, m->base, m->property->coreIndex); #endif return; @@ -238,6 +253,13 @@ void IRDecoder::visitExp(IR::Exp *s) callValue(c->base, c->args, 0); } else if (Member *member = c->base->asMember()) { Q_ASSERT(member->base->asTemp() || member->base->asArgLocal()); +#ifndef V4_BOOTSTRAP + Q_ASSERT(member->kind != IR::Member::MemberOfIdObjectsArray); + if (member->kind == IR::Member::MemberOfQmlScopeObject || member->kind == IR::Member::MemberOfQmlContextObject) { + callQmlContextProperty(member->base, (IR::Member::MemberKind)member->kind, member->property->coreIndex, c->args, 0); + return; + } +#endif callProperty(member->base, *member->name, c->args, 0); } else if (Subscript *s = c->base->asSubscript()) { callSubscript(s->base, s->index, c->args, 0); diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h index 1e273df93e..2b8aa7eb33 100644 --- a/src/qml/compiler/qv4isel_p.h +++ b/src/qml/compiler/qv4isel_p.h @@ -129,6 +129,7 @@ public: // to implement by subclasses: virtual void callBuiltinSetupArgumentObject(IR::Expr *result) = 0; virtual void callBuiltinConvertThisToObject() = 0; virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) = 0; + virtual void callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result) = 0; virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) = 0; virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Expr *result) = 0; virtual void convertType(IR::Expr *source, IR::Expr *target) = 0; @@ -136,10 +137,8 @@ public: // to implement by subclasses: virtual void constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) = 0; virtual void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) = 0; virtual void loadThisObject(IR::Expr *target) = 0; - virtual void loadQmlIdArray(IR::Expr *target) = 0; + virtual void loadQmlContext(IR::Expr *target) = 0; virtual void loadQmlImportedScripts(IR::Expr *target) = 0; - virtual void loadQmlContextObject(IR::Expr *target) = 0; - virtual void loadQmlScopeObject(IR::Expr *target) = 0; virtual void loadQmlSingleton(const QString &name, IR::Expr *target) = 0; virtual void loadConst(IR::Const *sourceConst, IR::Expr *target) = 0; virtual void loadString(const QString &str, IR::Expr *target) = 0; @@ -149,7 +148,9 @@ public: // to implement by subclasses: virtual void initClosure(IR::Closure *closure, IR::Expr *target) = 0; virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target) = 0; virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target) = 0; + virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target) = 0; virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName) = 0; + virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex) = 0; virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex) = 0; virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target) = 0; virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex) = 0; diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index 5c9cc98ade..98b53c6b3b 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -341,14 +341,10 @@ const char *builtin_to_string(Name::Builtin b) return "builtin_setup_argument_object"; case IR::Name::builtin_convert_this_to_object: return "builtin_convert_this_to_object"; - case IR::Name::builtin_qml_id_array: - return "builtin_qml_id_array"; + case IR::Name::builtin_qml_context: + return "builtin_qml_context"; case IR::Name::builtin_qml_imported_scripts_object: return "builtin_qml_imported_scripts_object"; - case IR::Name::builtin_qml_scope_object: - return "builtin_qml_scope_object"; - case IR::Name::builtin_qml_context_object: - return "builtin_qml_context_object"; } return "builtin_(###FIXME)"; }; @@ -935,7 +931,7 @@ void CloneExpr::visitSubscript(Subscript *e) void CloneExpr::visitMember(Member *e) { Expr *clonedBase = clone(e->base); - cloned = block->MEMBER(clonedBase, e->name, e->property, e->kind, e->attachedPropertiesIdOrEnumValue); + cloned = block->MEMBER(clonedBase, e->name, e->property, e->kind, e->idIndex); } IRPrinter::IRPrinter(QTextStream *out) @@ -1239,9 +1235,9 @@ void IRPrinter::visitSubscript(Subscript *e) void IRPrinter::visitMember(Member *e) { - if (e->kind != Member::MemberOfEnum - && e->attachedPropertiesIdOrEnumValue != 0 && !e->base->asTemp()) - *out << "[[attached property from " << e->attachedPropertiesIdOrEnumValue << "]]"; + if (e->kind != Member::MemberOfEnum && e->kind != Member::MemberOfIdObjectsArray + && e->attachedPropertiesId != 0 && !e->base->asTemp()) + *out << "[[attached property from " << e->attachedPropertiesId << "]]"; else e->base->accept(this); *out << '.' << *e->name; @@ -1250,6 +1246,8 @@ void IRPrinter::visitMember(Member *e) *out << " (meta-property " << e->property->coreIndex << " <" << QMetaType::typeName(e->property->propType) << ">)"; + else if (e->kind == Member::MemberOfIdObjectsArray) + *out << "(id object " << e->idIndex << ")"; #endif } diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 8daad97e8b..568ded5337 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -337,10 +337,8 @@ struct Name: Expr { builtin_define_object_literal, builtin_setup_argument_object, builtin_convert_this_to_object, - builtin_qml_id_array, - builtin_qml_imported_scripts_object, - builtin_qml_context_object, - builtin_qml_scope_object + builtin_qml_context, + builtin_qml_imported_scripts_object }; const QString *id; @@ -558,13 +556,18 @@ struct Member: Expr { MemberOfEnum, MemberOfQmlScopeObject, MemberOfQmlContextObject, - MemberOfSingletonObject + MemberOfIdObjectsArray, + MemberOfSingletonObject, }; Expr *base; const QString *name; QQmlPropertyData *property; - int attachedPropertiesIdOrEnumValue; // depending on kind + union { // depending on kind + int attachedPropertiesId; + int enumValue; + int idIndex; + }; uchar freeOfSideEffects : 1; // This is set for example for for QObject properties. All sorts of extra behavior @@ -577,20 +580,20 @@ struct Member: Expr { void setEnumValue(int value) { kind = MemberOfEnum; - attachedPropertiesIdOrEnumValue = value; + enumValue = value; } void setAttachedPropertiesId(int id) { - Q_ASSERT(kind != MemberOfEnum); - attachedPropertiesIdOrEnumValue = id; + Q_ASSERT(kind != MemberOfEnum && kind != MemberOfIdObjectsArray); + attachedPropertiesId = id; } - void init(Expr *base, const QString *name, QQmlPropertyData *property = 0, uchar kind = UnspecifiedMember, int attachedPropertiesIdOrEnumValue = 0) + void init(Expr *base, const QString *name, QQmlPropertyData *property = 0, uchar kind = UnspecifiedMember, int index = 0) { this->base = base; this->name = name; this->property = property; - this->attachedPropertiesIdOrEnumValue = attachedPropertiesIdOrEnumValue; + this->idIndex = index; this->freeOfSideEffects = false; this->inhibitTypeConversionOnWrite = property != 0; this->kind = kind; diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index c0669d3e47..c150666a11 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -3912,7 +3912,7 @@ void cfg2dot(IR::Function *f, const QVector<LoopDetection::LoopInfo *> &loops = QString name; if (f->name) name = *f->name; - else name = QString::fromLatin1("%1").arg((unsigned long long)f); + else name = QStringLiteral("%1").arg((unsigned long long)f); qout << "digraph \"" << name << "\" { ordering=out;\n"; foreach (LoopDetection::LoopInfo *l, loops) { @@ -4020,14 +4020,14 @@ void optimizeSSA(StatementWorklist &W, DefUses &defUses, DominatorTree &df) if (Member *member = m->source->asMember()) { if (member->kind == Member::MemberOfEnum) { Const *c = function->New<Const>(); - const int enumValue = member->attachedPropertiesIdOrEnumValue; + const int enumValue = member->enumValue; c->init(SInt32Type, enumValue); replaceUses(targetTemp, c, W); defUses.removeDef(*targetTemp); W.remove(s); defUses.removeUse(s, *member->base->asTemp()); continue; - } else if (member->attachedPropertiesIdOrEnumValue != 0 && member->property && member->base->asTemp()) { + } else if (member->kind != IR::Member::MemberOfIdObjectsArray && member->attachedPropertiesId != 0 && member->property && member->base->asTemp()) { // Attached properties have no dependency on their base. Isel doesn't // need it and we can eliminate the temp used to initialize it. defUses.removeUse(s, *member->base->asTemp()); diff --git a/src/qml/debugger/debugger.pri b/src/qml/debugger/debugger.pri index 77a3ba6490..30a44eedd1 100644 --- a/src/qml/debugger/debugger.pri +++ b/src/qml/debugger/debugger.pri @@ -1,36 +1,23 @@ +contains(QT_CONFIG, no-qml-debug):DEFINES += QT_NO_QML_DEBUGGER + SOURCES += \ + $$PWD/qqmldebug.cpp \ + $$PWD/qqmldebugconnector.cpp \ $$PWD/qqmldebugservice.cpp \ - $$PWD/qqmlprofilerservice.cpp \ - $$PWD/qqmldebugserver.cpp \ - $$PWD/qqmlinspectorservice.cpp \ - $$PWD/qqmlenginedebugservice.cpp \ - $$PWD/qdebugmessageservice.cpp \ - $$PWD/qv4debugservice.cpp \ - $$PWD/qqmlconfigurabledebugservice.cpp \ - $$PWD/qqmlenginecontrolservice.cpp \ + $$PWD/qqmldebugserviceinterfaces.cpp \ $$PWD/qqmlabstractprofileradapter.cpp \ - $$PWD/qv4profileradapter.cpp \ $$PWD/qqmlprofiler.cpp HEADERS += \ + $$PWD/qqmldebugconnector_p.h \ + $$PWD/qqmldebugpluginmanager_p.h \ $$PWD/qqmldebugservice_p.h \ - $$PWD/qqmldebugservice_p_p.h \ - $$PWD/qqmlprofilerservice_p.h \ - $$PWD/qqmldebugserver_p.h \ - $$PWD/qqmldebugserverconnection_p.h \ + $$PWD/qqmldebugservicefactory_p.h \ + $$PWD/qqmldebugserviceinterfaces_p.h \ $$PWD/qqmldebugstatesdelegate_p.h \ - $$PWD/qqmlinspectorservice_p.h \ - $$PWD/qqmlinspectorinterface_p.h \ - $$PWD/qqmlenginedebugservice_p.h \ $$PWD/qqmldebug.h \ - $$PWD/qdebugmessageservice_p.h \ - $$PWD/qv4debugservice_p.h \ - $$PWD/qqmlconfigurabledebugservice_p.h \ - $$PWD/qqmlconfigurabledebugservice_p_p.h \ - $$PWD/qqmlenginecontrolservice_p.h \ $$PWD/qqmlprofilerdefinitions_p.h \ $$PWD/qqmlabstractprofileradapter_p.h \ - $$PWD/qv4profileradapter_p.h \ $$PWD/qqmlprofiler_p.h INCLUDEPATH += $$PWD diff --git a/src/qml/debugger/qdebugmessageservice.cpp b/src/qml/debugger/qdebugmessageservice.cpp deleted file mode 100644 index deaa472ce0..0000000000 --- a/src/qml/debugger/qdebugmessageservice.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdebugmessageservice_p.h" -#include "qqmldebugservice_p_p.h" - -#include <QDataStream> -#include <QMutex> - -QT_BEGIN_NAMESPACE - -Q_GLOBAL_STATIC(QDebugMessageService, qmlDebugMessageService) - -void DebugMessageHandler(QtMsgType type, const QMessageLogContext &ctxt, - const QString &buf) -{ - QDebugMessageService::instance()->sendDebugMessage(type, ctxt, buf); -} - -class QDebugMessageServicePrivate : public QQmlDebugServicePrivate -{ -public: - QDebugMessageServicePrivate() - : oldMsgHandler(0) - , prevState(QQmlDebugService::NotConnected) - { - } - - QtMessageHandler oldMsgHandler; - QQmlDebugService::State prevState; - QMutex initMutex; -}; - -QDebugMessageService::QDebugMessageService(QObject *parent) : - QQmlDebugService(*(new QDebugMessageServicePrivate()), - QStringLiteral("DebugMessages"), 2, parent) -{ - Q_D(QDebugMessageService); - - // don't execute stateChanged() in parallel - QMutexLocker lock(&d->initMutex); - registerService(); - if (state() == Enabled) { - d->oldMsgHandler = qInstallMessageHandler(DebugMessageHandler); - d->prevState = Enabled; - } -} - -QDebugMessageService *QDebugMessageService::instance() -{ - return qmlDebugMessageService(); -} - -void QDebugMessageService::sendDebugMessage(QtMsgType type, - const QMessageLogContext &ctxt, - const QString &buf) -{ - Q_D(QDebugMessageService); - - //We do not want to alter the message handling mechanism - //We just eavesdrop and forward the messages to a port - //only if a client is connected to it. - QByteArray message; - QQmlDebugStream ws(&message, QIODevice::WriteOnly); - ws << QByteArray("MESSAGE") << type << buf.toUtf8(); - ws << QString::fromLatin1(ctxt.file).toUtf8(); - ws << ctxt.line << QString::fromLatin1(ctxt.function).toUtf8(); - - sendMessage(message); - if (d->oldMsgHandler) - (*d->oldMsgHandler)(type, ctxt, buf); -} - -void QDebugMessageService::stateChanged(State state) -{ - Q_D(QDebugMessageService); - QMutexLocker lock(&d->initMutex); - - if (state != Enabled && d->prevState == Enabled) { - QtMessageHandler handler = qInstallMessageHandler(d->oldMsgHandler); - // has our handler been overwritten in between? - if (handler != DebugMessageHandler) - qInstallMessageHandler(handler); - - } else if (state == Enabled && d->prevState != Enabled) { - d->oldMsgHandler = qInstallMessageHandler(DebugMessageHandler); - } - - d->prevState = state; -} - -QT_END_NAMESPACE diff --git a/src/qml/debugger/qdebugmessageservice_p.h b/src/qml/debugger/qdebugmessageservice_p.h deleted file mode 100644 index 694cd0e64c..0000000000 --- a/src/qml/debugger/qdebugmessageservice_p.h +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDEBUGMESSAGESERVICE_P_H -#define QDEBUGMESSAGESERVICE_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. -// - -#include "qqmldebugservice_p.h" - -#include <QtCore/qlogging.h> - -QT_BEGIN_NAMESPACE - -class QDebugMessageServicePrivate; - -class QDebugMessageService : public QQmlDebugService -{ - Q_OBJECT -public: - QDebugMessageService(QObject *parent = 0); - - static QDebugMessageService *instance(); - - void sendDebugMessage(QtMsgType type, const QMessageLogContext &ctxt, - const QString &buf); - -protected: - void stateChanged(State); - -private: - Q_DISABLE_COPY(QDebugMessageService) - Q_DECLARE_PRIVATE(QDebugMessageService) -}; - -QT_END_NAMESPACE - -#endif // QDEBUGMESSAGESERVICE_P_H diff --git a/src/qml/debugger/qqmlconfigurabledebugservice.cpp b/src/qml/debugger/qqmlconfigurabledebugservice.cpp deleted file mode 100644 index e3693e00a4..0000000000 --- a/src/qml/debugger/qqmlconfigurabledebugservice.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlconfigurabledebugservice_p.h" -#include "qqmlconfigurabledebugservice_p_p.h" - -QT_BEGIN_NAMESPACE - -QQmlConfigurableDebugService::QQmlConfigurableDebugService(const QString &name, float version, - QObject *parent) : - QQmlDebugService((*new QQmlConfigurableDebugServicePrivate), name, version, parent) { init(); } - -QQmlConfigurableDebugService::QQmlConfigurableDebugService(QQmlDebugServicePrivate &dd, - const QString &name, float version, - QObject *parent) : - QQmlDebugService(dd, name, version, parent) { init(); } - -QMutex *QQmlConfigurableDebugService::configMutex() -{ - Q_D(QQmlConfigurableDebugService); - return &d->configMutex; -} - -void QQmlConfigurableDebugService::init() -{ - Q_D(QQmlConfigurableDebugService); - QMutexLocker lock(&d->configMutex); - // If we're not enabled or not blocking, don't wait for configuration - d->waitingForConfiguration = (registerService() == Enabled && blockingMode()); -} - -void QQmlConfigurableDebugService::stopWaiting() -{ - Q_D(QQmlConfigurableDebugService); - QMutexLocker lock(&d->configMutex); - d->waitingForConfiguration = false; - foreach (QQmlEngine *engine, d->waitingEngines) - emit attachedToEngine(engine); - d->waitingEngines.clear(); -} - -void QQmlConfigurableDebugService::stateChanged(QQmlDebugService::State newState) -{ - if (newState != Enabled) - stopWaiting(); -} - -void QQmlConfigurableDebugService::engineAboutToBeAdded(QQmlEngine *engine) -{ - Q_D(QQmlConfigurableDebugService); - QMutexLocker lock(&d->configMutex); - if (d->waitingForConfiguration) - d->waitingEngines.append(engine); - else - emit attachedToEngine(engine); -} - -QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmlconfigurabledebugservice_p.h b/src/qml/debugger/qqmlconfigurabledebugservice_p.h deleted file mode 100644 index cf69c3a1f6..0000000000 --- a/src/qml/debugger/qqmlconfigurabledebugservice_p.h +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QQMLCONFIGURABLEDEBUGSEVICE_H -#define QQMLCONFIGURABLEDEBUGSEVICE_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. -// - -#include "qqmldebugservice_p.h" - -QT_BEGIN_NAMESPACE - -class QMutex; -class QQmlConfigurableDebugServicePrivate; -class QQmlConfigurableDebugService : public QQmlDebugService -{ - Q_OBJECT -public: - QQmlConfigurableDebugService(const QString &name, float version, QObject *parent = 0); - -protected: - QQmlConfigurableDebugService(QQmlDebugServicePrivate &dd, const QString &name, float version, QObject *parent = 0); - - QMutex *configMutex(); - void stopWaiting(); - void init(); - - void stateChanged(State); - void engineAboutToBeAdded(QQmlEngine *); - - virtual ~QQmlConfigurableDebugService() {} -private: - Q_DISABLE_COPY(QQmlConfigurableDebugService) - Q_DECLARE_PRIVATE(QQmlConfigurableDebugService) -}; - -QT_END_NAMESPACE - -#endif // QQMLCONFIGURABLEDEBUGSEVICE_H diff --git a/src/qml/debugger/qqmlconfigurabledebugservice_p_p.h b/src/qml/debugger/qqmlconfigurabledebugservice_p_p.h deleted file mode 100644 index 6d693b6352..0000000000 --- a/src/qml/debugger/qqmlconfigurabledebugservice_p_p.h +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLCONFIGURABLEDEBUGSERVICE_P_H -#define QQMLCONFIGURABLEDEBUGSERVICE_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. -// - -#include "qqmldebugservice_p.h" -#include "qqmldebugservice_p_p.h" - -#include <QMutex> - -QT_BEGIN_NAMESPACE - -class QQmlEngine; - -class QQmlConfigurableDebugServicePrivate : public QQmlDebugServicePrivate -{ - Q_DECLARE_PUBLIC(QQmlConfigurableDebugService) -public: - QQmlConfigurableDebugServicePrivate() : configMutex(QMutex::Recursive) {} - - QMutex configMutex; - QList<QQmlEngine *> waitingEngines; - bool waitingForConfiguration; -}; - -QT_END_NAMESPACE - -#endif // QQMLCONFIGURABLEDEBUGSERVICE_P_H diff --git a/src/qml/debugger/qqmldebug.cpp b/src/qml/debugger/qqmldebug.cpp new file mode 100644 index 0000000000..83718921f1 --- /dev/null +++ b/src/qml/debugger/qqmldebug.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmldebug.h" +#include "qqmldebugconnector_p.h" + +#include <private/qqmlengine_p.h> + +QT_BEGIN_NAMESPACE + +QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning) +{ +#ifndef QQML_NO_DEBUG_PROTOCOL + if (!QQmlEnginePrivate::qml_debugging_enabled + && printWarning) { + qDebug("QML debugging is enabled. Only use this in a safe environment."); + } + QQmlEnginePrivate::qml_debugging_enabled = true; +#else + Q_UNUSED(printWarning); +#endif +} + +/*! + * \enum QQmlDebuggingEnabler::StartMode + * + * Defines the debug server's start behavior. You can interrupt QML engines starting while a debug + * client is connecting, in order to set breakpoints in or profile startup code. + * + * \value DoNotWaitForClient Run any QML engines as usual while the debug services are connecting. + * \value WaitForClient If a QML engine starts while the debug services are connecting, + * interrupt it until they are done. + */ + +/*! + * Enables debugging for QML engines created after calling this function. The debug server will + * listen on \a port at \a hostName and block the QML engine until it receives a connection if + * \a mode is \c WaitForClient. If \a mode is not specified it won't block and if \a hostName is not + * specified it will listen on all available interfaces. You can only start one debug server at a + * time. A debug server may have already been started if the -qmljsdebugger= command line argument + * was given. This method returns \c true if a new debug server was successfully started, or + * \c false otherwise. + */ +bool QQmlDebuggingEnabler::startTcpDebugServer(int port, StartMode mode, const QString &hostName) +{ +#ifndef QQML_NO_DEBUG_PROTOCOL + QQmlDebugConnector::setPluginKey(QLatin1String("QQmlDebugServer")); + QQmlDebugConnector *connector = QQmlDebugConnector::instance(); + if (connector) { + QVariantHash configuration; + configuration[QLatin1String("portFrom")] = configuration[QLatin1String("portTo")] = port; + configuration[QLatin1String("block")] = (mode == WaitForClient); + configuration[QLatin1String("hostAddress")] = hostName; + return connector->open(configuration); + } +#else + Q_UNUSED(port); + Q_UNUSED(block); + Q_UNUSED(hostName); +#endif + return false; +} + +/*! + * Enables debugging for QML engines created after calling this function. The debug server will + * connect to a debugger waiting on a local socket at the given \a socketFileName and block the QML + * engine until the connection is established if \a mode is \c WaitForClient. If \a mode is not + * specified it will not block. You can only start one debug server at a time. A debug server may + * have already been started if the -qmljsdebugger= command line argument was given. This method + * returns \c true if a new debug server was successfully started, or \c false otherwise. + */ +bool QQmlDebuggingEnabler::connectToLocalDebugger(const QString &socketFileName, StartMode mode) +{ +#ifndef QQML_NO_DEBUG_PROTOCOL + QQmlDebugConnector::setPluginKey(QLatin1String("QQmlDebugServer")); + QQmlDebugConnector *connector = QQmlDebugConnector::instance(); + if (connector) { + QVariantHash configuration; + configuration[QLatin1String("fileName")] = socketFileName; + configuration[QLatin1String("block")] = (mode == WaitForClient); + return connector->open(configuration); + } +#else + Q_UNUSED(fileName); + Q_UNUSED(block); +#endif + return false; +} + +QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmldebug.h b/src/qml/debugger/qqmldebug.h index 559c492dfd..5d65982a49 100644 --- a/src/qml/debugger/qqmldebug.h +++ b/src/qml/debugger/qqmldebug.h @@ -50,6 +50,8 @@ struct Q_QML_EXPORT QQmlDebuggingEnabler QQmlDebuggingEnabler(bool printWarning = true); static bool startTcpDebugServer(int port, StartMode mode = DoNotWaitForClient, const QString &hostName = QString()); + static bool connectToLocalDebugger(const QString &socketFileName, + StartMode mode = DoNotWaitForClient); }; // Execute code in constructor before first QQmlEngine is instantiated diff --git a/src/qml/debugger/qqmldebugconnector.cpp b/src/qml/debugger/qqmldebugconnector.cpp new file mode 100644 index 0000000000..8de734fa68 --- /dev/null +++ b/src/qml/debugger/qqmldebugconnector.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmldebugpluginmanager_p.h" +#include "qqmldebugconnector_p.h" +#include "qqmldebugservicefactory_p.h" +#include <QtCore/QPluginLoader> +#include <QtCore/QCoreApplication> +#include <QtCore/QDir> +#include <QtCore/QDebug> +#include <QtCore/QJsonArray> + +#include <private/qcoreapplication_p.h> +#include <private/qqmlengine_p.h> + +QT_BEGIN_NAMESPACE + +// We could add more plugins here, and distinguish by arguments to instance() +Q_QML_DEBUG_PLUGIN_LOADER(QQmlDebugConnector) +Q_QML_IMPORT_DEBUG_PLUGIN(QQmlDebugServerFactory) + +Q_QML_DEBUG_PLUGIN_LOADER(QQmlDebugService) +Q_QML_IMPORT_DEBUG_PLUGIN(QQmlInspectorServiceFactory) +Q_QML_IMPORT_DEBUG_PLUGIN(QQmlProfilerServiceFactory) +Q_QML_IMPORT_DEBUG_PLUGIN(QQmlDebuggerServiceFactory) + +struct QQmlDebugConnectorParams { + QString pluginKey; + QStringList services; + QString arguments; + QQmlDebugConnector *instance; + + QQmlDebugConnectorParams() : instance(0) + { + if (qApp) { + QCoreApplicationPrivate *appD = + static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp)); + if (appD) + arguments = appD->qmljsDebugArgumentsString(); + } + } +}; + +Q_GLOBAL_STATIC(QQmlDebugConnectorParams, qmlDebugConnectorParams) + +void QQmlDebugConnector::setPluginKey(const QString &key) +{ + QQmlDebugConnectorParams *params = qmlDebugConnectorParams(); + if (params) { + if (params->instance) + qWarning() << "QML debugger: Cannot set plugin key after loading the plugin."; + else + params->pluginKey = key; + } +} + +void QQmlDebugConnector::setServices(const QStringList &services) +{ + QQmlDebugConnectorParams *params = qmlDebugConnectorParams(); + if (params) + params->services = services; +} + +QString QQmlDebugConnector::commandLineArguments() +{ + QQmlDebugConnectorParams *params = qmlDebugConnectorParams(); + if (!params) + return QString(); + return params->arguments; +} + +QQmlDebugConnector *QQmlDebugConnector::instance() +{ + QQmlDebugConnectorParams *params = qmlDebugConnectorParams(); + if (!params) + return 0; + + if (!QQmlEnginePrivate::qml_debugging_enabled) { + if (!params->arguments.isEmpty()) { + qWarning() << QString::fromLatin1( + "QML Debugger: Ignoring \"-qmljsdebugger=%1\". Debugging has not " + "been enabled.").arg(params->arguments); + params->arguments.clear(); + } + return 0; + } + + if (!params->instance) { + if (!params->pluginKey.isEmpty()) { + if (params->pluginKey != QLatin1String("QQmlDebugServer")) + return 0; // We cannot load anything else, yet + } else if (params->arguments.isEmpty()) { + return 0; // no explicit class name given and no command line arguments + } + params->instance = loadQQmlDebugConnector(QLatin1String("QQmlDebugServer")); + if (params->instance) { + foreach (const QJsonObject &object, metaDataForQQmlDebugService()) { + foreach (const QJsonValue &key, object.value(QLatin1String("MetaData")).toObject() + .value(QLatin1String("Keys")).toArray()) { + QString keyString = key.toString(); + if (params->services.isEmpty() || params->services.contains(keyString)) + loadQQmlDebugService(keyString); + } + } + } + } + + return params->instance; +} + +QQmlDebugConnectorFactory::~QQmlDebugConnectorFactory() +{ + // This is triggered when the plugin is unloaded. + QQmlDebugConnectorParams *params = qmlDebugConnectorParams(); + if (params && params->instance) { + delete params->instance; + params->instance = 0; + } +} + +QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmlinspectorservice_p.h b/src/qml/debugger/qqmldebugconnector_p.h index f49c36aacb..f5f5a87b56 100644 --- a/src/qml/debugger/qqmlinspectorservice_p.h +++ b/src/qml/debugger/qqmldebugconnector_p.h @@ -31,8 +31,13 @@ ** ****************************************************************************/ -#ifndef QQMLINSPECTORSERVICE_H -#define QQMLINSPECTORSERVICE_H +#ifndef QQMLDEBUGCONNECTOR_H +#define QQMLDEBUGCONNECTOR_H + +#include <QtQml/qtqmlglobal.h> +#include <QtCore/QVariantList> + +#include <private/qqmldebugservice_p.h> // // W A R N I N G @@ -45,45 +50,49 @@ // We mean it. // -#include "qqmldebugservice_p.h" - -#include <QtQml/qtqmlglobal.h> -#include <QtCore/QList> - QT_BEGIN_NAMESPACE - -class QQmlInspectorInterface; - -class Q_QML_PRIVATE_EXPORT QQmlInspectorService : public QQmlDebugService +class QQmlDebugService; +class Q_QML_PRIVATE_EXPORT QQmlDebugConnector : public QObject { Q_OBJECT - public: - QQmlInspectorService(); - static QQmlInspectorService *instance(); + static void setPluginKey(const QString &key); + static void setServices(const QStringList &services); + static QQmlDebugConnector *instance(); - void addView(QObject *); - void removeView(QObject *); + virtual bool blockingMode() const = 0; - void sendMessage(const QByteArray &message); + virtual QQmlDebugService *service(const QString &name) const = 0; -protected: - virtual void stateChanged(State state); - virtual void messageReceived(const QByteArray &); + virtual void addEngine(QQmlEngine *engine) = 0; + virtual void removeEngine(QQmlEngine *engine) = 0; + + virtual bool addService(const QString &name, QQmlDebugService *service) = 0; + virtual bool removeService(const QString &name) = 0; -private Q_SLOTS: - void processMessage(const QByteArray &message); - void updateState(); + virtual bool open(const QVariantHash &configuration = QVariantHash()) = 0; -private: - void loadInspectorPlugins(); + template<class Service> + static Service *service() + { + QQmlDebugConnector *inst = instance(); + return inst ? static_cast<Service *>(inst->service(Service::s_key)) : 0; + } + +protected: + static QString commandLineArguments(); +}; - QList<QObject*> m_views; - QQmlInspectorInterface *m_currentInspectorPlugin; - QList<QQmlInspectorInterface*> m_inspectorPlugins; +class Q_QML_PRIVATE_EXPORT QQmlDebugConnectorFactory : public QObject { + Q_OBJECT +public: + virtual QQmlDebugConnector *create(const QString &key) = 0; + ~QQmlDebugConnectorFactory(); }; +#define QQmlDebugConnectorFactory_iid "org.qt-project.Qt.QQmlDebugConnectorFactory" + QT_END_NAMESPACE -#endif // QQMLINSPECTORSERVICE_H +#endif // QQMLDEBUGCONNECTOR_H diff --git a/src/qml/debugger/qqmlenginecontrolservice_p.h b/src/qml/debugger/qqmldebugpluginmanager_p.h index 2171937efe..cef463b8b3 100644 --- a/src/qml/debugger/qqmlenginecontrolservice_p.h +++ b/src/qml/debugger/qqmldebugpluginmanager_p.h @@ -31,11 +31,8 @@ ** ****************************************************************************/ -#ifndef QQMLENGINECONTROLSERVICE_H -#define QQMLENGINECONTROLSERVICE_H - -#include <QMutex> -#include "qqmldebugservice_p.h" +#ifndef QQMLDEBUGPLUGINMANAGER_P_H +#define QQMLDEBUGPLUGINMANAGER_P_H // // W A R N I N G @@ -48,43 +45,49 @@ // We mean it. // -QT_BEGIN_NAMESPACE - -class QQmlEngineControlService : public QQmlDebugService -{ -public: - enum MessageType { - EngineAboutToBeAdded, - EngineAdded, - EngineAboutToBeRemoved, - EngineRemoved - }; +#include <QDebug> +#include <private/qtqmlglobal_p.h> +#include <private/qfactoryloader_p.h> - enum CommandType { - StartWaitingEngine, - StopWaitingEngine - }; +QT_BEGIN_NAMESPACE - QQmlEngineControlService(); +#if defined(QT_NO_QML_DEBUGGER) - static QQmlEngineControlService *instance(); +#define Q_QML_DEBUG_PLUGIN_LOADER(interfaceName)\ + interfaceName *load##interfaceName(const QString &key)\ + {\ + qWarning() << "Qml Debugger: QtQml is not configured for debugging. Ignoring request for"\ + << "debug plugin" << key;\ + return 0;\ + }\ + QList<QJsonObject> metaDataFor##interfaceName()\ + {\ + return QList<QJsonObject();\ + } +#define Q_QML_IMPORT_DEBUG_PLUGIN(className) -protected: - QMutex dataMutex; - QList<QQmlEngine *> startingEngines; - QList<QQmlEngine *> stoppingEngines; +#else // QT_NO_QML_DEBUGGER - void messageReceived(const QByteArray &); - void engineAboutToBeAdded(QQmlEngine *); - void engineAboutToBeRemoved(QQmlEngine *); - void engineAdded(QQmlEngine *); - void engineRemoved(QQmlEngine *); +#ifdef QT_STATIC +#define Q_QML_IMPORT_DEBUG_PLUGIN(className)\ + Q_IMPORT_PLUGIN(className) +#else +#define Q_QML_IMPORT_DEBUG_PLUGIN(className) +#endif // QT_STATIC - void sendMessage(MessageType type, QQmlEngine *engine); +#define Q_QML_DEBUG_PLUGIN_LOADER(interfaceName)\ + Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, interfaceName##Loader,\ + (interfaceName##Factory_iid, QLatin1String("/qmltooling")))\ + interfaceName *load##interfaceName(const QString &key)\ + {\ + return qLoadPlugin<interfaceName, interfaceName##Factory>(interfaceName##Loader(), key);\ + }\ + QList<QJsonObject> metaDataFor##interfaceName()\ + {\ + return interfaceName##Loader()->metaData();\ + } - void stateChanged(State); -}; +#endif // QT_NO_QML_DEBUGGER QT_END_NAMESPACE - -#endif // QQMLENGINECONTROLSERVICE_H +#endif // QQMLDEBUGPLUGINMANAGER_P_H diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp deleted file mode 100644 index b0302181ee..0000000000 --- a/src/qml/debugger/qqmldebugserver.cpp +++ /dev/null @@ -1,787 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmldebugserver_p.h" -#include "qqmldebugservice_p.h" -#include "qqmldebugservice_p_p.h" -#include "qqmlenginedebugservice_p.h" -#include "qv4debugservice_p.h" -#include "qdebugmessageservice_p.h" -#include "qqmlprofilerservice_p.h" - -#include <private/qqmlengine_p.h> -#include <private/qqmlglobal_p.h> - -#include <QtCore/QAtomicInt> -#include <QtCore/QDir> -#include <QtCore/QPluginLoader> -#include <QtCore/QStringList> -#include <QtCore/qwaitcondition.h> - -#include <private/qobject_p.h> -#include <private/qcoreapplication_p.h> - -#if defined(QT_STATIC) && ! defined(QT_NO_QML_DEBUGGER) -#include "../../plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h" -#endif - -QT_BEGIN_NAMESPACE - -// We can't friend the Q_GLOBAL_STATIC to have the constructor available so we need a little -// workaround here. Using this wrapper we can also make QQmlEnginePrivate's cleanup() available to -// qAddPostRoutine(). We can't do the cleanup in the destructor because we need a QApplication to -// be available when stopping the plugins. -struct QQmlDebugServerInstanceWrapper { - QQmlDebugServer m_instance; - void cleanup(); -}; - -Q_GLOBAL_STATIC(QQmlDebugServerInstanceWrapper, debugServerInstance) - -/* - QQmlDebug Protocol (Version 1): - - handshake: - 1. Client sends - "QDeclarativeDebugServer" 0 version pluginNames [QDataStream version] - version: an int representing the highest protocol version the client knows - pluginNames: plugins available on client side - 2. Server sends - "QDeclarativeDebugClient" 0 version pluginNames pluginVersions [QDataStream version] - version: an int representing the highest protocol version the client & server know - pluginNames: plugins available on server side. plugins both in the client and server message are enabled. - client plugin advertisement - 1. Client sends - "QDeclarativeDebugServer" 1 pluginNames - server plugin advertisement - 1. Server sends - "QDeclarativeDebugClient" 1 pluginNames pluginVersions - plugin communication: - Everything send with a header different to "QDeclarativeDebugServer" is sent to the appropriate plugin. - */ - -const int protocolVersion = 1; -int QQmlDebugServer::s_dataStreamVersion = QDataStream::Qt_4_7; - -// print detailed information about loading of plugins -DEFINE_BOOL_CONFIG_OPTION(qmlDebugVerbose, QML_DEBUGGER_VERBOSE) - -class QQmlDebugServerThread; - -class QQmlDebugServerPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QQmlDebugServer) -public: - QQmlDebugServerPrivate(); - - bool start(int portFrom, int portTo, bool block, const QString &hostAddress, - const QString &pluginName); - void advertisePlugins(); - void cleanup(); - QQmlDebugServerConnection *loadConnectionPlugin(const QString &pluginName); - - QQmlDebugServerConnection *connection; - QHash<QString, QQmlDebugService *> plugins; - mutable QReadWriteLock pluginsLock; - QStringList clientPlugins; - bool gotHello; - bool blockingMode; - - class EngineCondition { - public: - EngineCondition() : numServices(0), condition(new QWaitCondition) {} - - bool waitForServices(QReadWriteLock *locked, int numEngines); - - void wake(); - private: - int numServices; - - // shared pointer to allow for QHash-inflicted copying. - QSharedPointer<QWaitCondition> condition; - }; - - QHash<QQmlEngine *, EngineCondition> engineConditions; - - QMutex helloMutex; - QWaitCondition helloCondition; - QQmlDebugServerThread *thread; - QPluginLoader loader; - QAtomicInt changeServiceStateCalls; - -private: - // private slots - void _q_changeServiceState(const QString &serviceName, - QQmlDebugService::State newState); - void _q_sendMessages(const QList<QByteArray> &messages); - void _q_removeThread(); -}; - -void QQmlDebugServerInstanceWrapper::cleanup() -{ m_instance.d_func()->cleanup(); } - -class QQmlDebugServerThread : public QThread -{ -public: - void setPluginName(const QString &pluginName) { - m_pluginName = pluginName; - } - - void setPortRange(int portFrom, int portTo, bool block, const QString &hostAddress) { - m_portFrom = portFrom; - m_portTo = portTo; - m_block = block; - m_hostAddress = hostAddress; - } - - void run(); - -private: - QString m_pluginName; - int m_portFrom; - int m_portTo; - bool m_block; - QString m_hostAddress; -}; - -QQmlDebugServerPrivate::QQmlDebugServerPrivate() : - connection(0), - pluginsLock(QReadWriteLock::Recursive), - gotHello(false), - blockingMode(false), - thread(0) -{ - // used in _q_sendMessages - qRegisterMetaType<QList<QByteArray> >("QList<QByteArray>"); - // used in _q_changeServiceState - qRegisterMetaType<QQmlDebugService::State>("QQmlDebugService::State"); -} - -void QQmlDebugServerPrivate::advertisePlugins() -{ - Q_Q(QQmlDebugServer); - - if (!gotHello) - return; - - QByteArray message; - { - QQmlDebugStream out(&message, QIODevice::WriteOnly); - QStringList pluginNames; - QList<float> pluginVersions; - foreach (QQmlDebugService *service, plugins.values()) { - pluginNames << service->name(); - pluginVersions << service->version(); - } - out << QString(QStringLiteral("QDeclarativeDebugClient")) << 1 << pluginNames << pluginVersions; - } - - QMetaObject::invokeMethod(q, "_q_sendMessages", Qt::QueuedConnection, Q_ARG(QList<QByteArray>, QList<QByteArray>() << message)); -} - -void QQmlDebugServerPrivate::cleanup() -{ - Q_Q(QQmlDebugServer); - { - QReadLocker lock(&pluginsLock); - foreach (QQmlDebugService *service, plugins.values()) { - changeServiceStateCalls.ref(); - QMetaObject::invokeMethod(q, "_q_changeServiceState", Qt::QueuedConnection, - Q_ARG(QString, service->name()), - Q_ARG(QQmlDebugService::State, QQmlDebugService::NotConnected)); - } - } - - // Wait for changeServiceState calls to finish - // (while running an event loop because some services - // might again use slots to execute stuff in the GUI thread) - QEventLoop loop; - while (!changeServiceStateCalls.testAndSetOrdered(0, 0)) - loop.processEvents(); - - // Stop the thread while the application is still there. Copy here as the thread will set itself - // to 0 when it stops. It will also do deleteLater, but as long as we don't allow the GUI - // thread's event loop to run we're safe from that. - QThread *threadCopy = thread; - if (threadCopy) { - threadCopy->exit(); - threadCopy->wait(); - } -} - -QQmlDebugServerConnection *QQmlDebugServerPrivate::loadConnectionPlugin( - const QString &pluginName) -{ -#ifndef QT_NO_LIBRARY - QStringList pluginCandidates; - const QStringList paths = QCoreApplication::libraryPaths(); - foreach (const QString &libPath, paths) { - const QDir dir(libPath + QLatin1String("/qmltooling")); - if (dir.exists()) { - QStringList plugins(dir.entryList(QDir::Files)); - foreach (const QString &pluginPath, plugins) { - if (QFileInfo(pluginPath).fileName().contains(pluginName)) - pluginCandidates << dir.absoluteFilePath(pluginPath); - } - } - } - - QQmlDebugServerConnection *loadedConnection = 0; - foreach (const QString &pluginPath, pluginCandidates) { - if (qmlDebugVerbose()) - qDebug() << "QML Debugger: Trying to load plugin " << pluginPath << "..."; - - loader.setFileName(pluginPath); - if (!loader.load()) { - if (qmlDebugVerbose()) - qDebug() << "QML Debugger: Error while loading: " << loader.errorString(); - continue; - } - if (QObject *instance = loader.instance()) - loadedConnection = qobject_cast<QQmlDebugServerConnection*>(instance); - - if (loadedConnection) { - if (qmlDebugVerbose()) - qDebug() << "QML Debugger: Plugin successfully loaded."; - - return loadedConnection; - } - - if (qmlDebugVerbose()) - qDebug() << "QML Debugger: Plugin does not implement interface QQmlDebugServerConnection."; - - loader.unload(); - } -#endif - return 0; -} - -void QQmlDebugServerThread::run() -{ - QQmlDebugServerInstanceWrapper *wrapper = debugServerInstance(); - Q_ASSERT_X(wrapper != 0, Q_FUNC_INFO, "There should always be a debug server available here."); - QQmlDebugServer *server = &wrapper->m_instance; -#if defined(QT_STATIC) && ! defined(QT_NO_QML_DEBUGGER) - QQmlDebugServerConnection *connection - = new QTcpServerConnection; -#else - QQmlDebugServerConnection *connection - = server->d_func()->loadConnectionPlugin(m_pluginName); -#endif - if (connection) { - connection->setServer(server); - if (!connection->setPortRange(m_portFrom, m_portTo, m_block, m_hostAddress)) { - delete connection; - return; - } - server->d_func()->connection = connection; - if (m_block) - connection->waitForConnection(); - } else { - qWarning() << "QML Debugger: Couldn't load plugin" << m_pluginName; - return; - } - - exec(); - - // make sure events still waiting are processed - QEventLoop eventLoop; - eventLoop.processEvents(QEventLoop::AllEvents); -} - -bool QQmlDebugServer::hasDebuggingClient() const -{ - Q_D(const QQmlDebugServer); - return d->connection - && d->connection->isConnected() - && d->gotHello; -} - -bool QQmlDebugServer::hasThread() const -{ - Q_D(const QQmlDebugServer); - return d->thread != 0; -} - -bool QQmlDebugServer::hasConnection() const -{ - Q_D(const QQmlDebugServer); - return d->connection != 0; -} - -bool QQmlDebugServer::blockingMode() const -{ - Q_D(const QQmlDebugServer); - return d->blockingMode; -} - -QQmlDebugServer *QQmlDebugServer::instance() -{ - QQmlDebugServerInstanceWrapper *wrapper = debugServerInstance(); - if (wrapper && wrapper->m_instance.d_func()->thread) { - QQmlDebugServer *ret = &(wrapper->m_instance); - QQmlDebugServerPrivate *d = ret->d_func(); - QMutexLocker locker(&d->helloMutex); - if (d->blockingMode && !d->gotHello) - d->helloCondition.wait(&d->helloMutex); - return ret; - } else { - return 0; - } -} - -static void cleanupOnShutdown() -{ - QQmlDebugServerInstanceWrapper *wrapper = debugServerInstance(); - if (wrapper) - wrapper->cleanup(); -} - -bool QQmlDebugServerPrivate::start(int portFrom, int portTo, bool block, const QString &hostAddress, - const QString &pluginName) -{ - if (!QQmlEnginePrivate::qml_debugging_enabled) - return false; - if (thread) - return false; - static bool postRoutineAdded = false; - if (!postRoutineAdded) { - qAddPostRoutine(cleanupOnShutdown); - postRoutineAdded = true; - } - Q_Q(QQmlDebugServer); - thread = new QQmlDebugServerThread; - q->moveToThread(thread); - - // Remove the thread immmediately when it finishes, so that we don't have to wait for the event - // loop to signal that. - QObject::connect(thread, SIGNAL(finished()), q, SLOT(_q_removeThread()), Qt::DirectConnection); - - thread->setObjectName(QStringLiteral("QQmlDebugServerThread")); - thread->setPluginName(pluginName); - thread->setPortRange(portFrom, portTo == -1 ? portFrom : portTo, block, hostAddress); - blockingMode = block; - thread->start(); - return true; -} - -QQmlDebugServer::QQmlDebugServer() - : QObject(*(new QQmlDebugServerPrivate)) -{ - if (qApp == 0) - return; - QCoreApplicationPrivate *appD = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp)); -#ifndef QT_NO_QML_DEBUGGER - // ### remove port definition when protocol is changed - int portFrom = 0; - int portTo = 0; - bool block = false; - bool ok = false; - QString hostAddress; - - // format: qmljsdebugger=port:<port_from>[,port_to],host:<ip address>][,block] - if (!appD->qmljsDebugArgumentsString().isEmpty()) { - if (!QQmlEnginePrivate::qml_debugging_enabled) { - qWarning() << QString(QLatin1String( - "QML Debugger: Ignoring \"-qmljsdebugger=%1\". " - "Debugging has not been enabled.")).arg( - appD->qmljsDebugArgumentsString()); - return; - } - - QString pluginName; - QStringList lstjsDebugArguments = appD->qmljsDebugArgumentsString() - .split(QLatin1Char(',')); - QStringList::const_iterator argsItEnd = lstjsDebugArguments.end(); - QStringList::const_iterator argsIt = lstjsDebugArguments.begin(); - for (; argsIt != argsItEnd; ++argsIt) { - const QString strArgument = *argsIt; - if (strArgument.startsWith(QLatin1String("port:"))) { - pluginName = QLatin1String("qmldbg_tcp"); - portFrom = strArgument.mid(5).toInt(&ok); - portTo = portFrom; - QStringList::const_iterator argsNext = argsIt + 1; - if (argsNext == argsItEnd) - break; - const QString nextArgument = *argsNext; - if (ok && nextArgument.contains(QRegExp(QStringLiteral("^\\s*\\d+\\s*$")))) { - portTo = nextArgument.toInt(&ok); - ++argsIt; - } - } else if (strArgument.startsWith(QLatin1String("host:"))) { - hostAddress = strArgument.mid(5); - } else if (strArgument == QLatin1String("block")) { - block = true; - } else { - qWarning() << QString::fromLatin1("QML Debugger: Invalid argument '%1' " - "detected. Ignoring the same.") - .arg(strArgument); - } - } - - if (ok) { - Q_D(QQmlDebugServer); - d->start(portFrom, portTo, block, hostAddress, pluginName); - } else { - qWarning() << QString(QLatin1String( - "QML Debugger: Ignoring \"-qmljsdebugger=%1\". " - "Format is qmljsdebugger=port:<port_from>[,port_to],host:" - "<ip address>][,block]")).arg(appD->qmljsDebugArgumentsString()); - } - } -#else - if (!appD->qmljsDebugArgumentsString().isEmpty()) { - qWarning() << QString(QLatin1String( - "QML Debugger: Ignoring \"-qmljsdebugger=%1\". " - "QtQml is not configured for debugging.")).arg( - appD->qmljsDebugArgumentsString()); - } -#endif -} - -void QQmlDebugServer::receiveMessage(const QByteArray &message) -{ - typedef QHash<QString, QQmlDebugService*>::const_iterator DebugServiceConstIt; - - // to be executed in debugger thread - Q_ASSERT(QThread::currentThread() == thread()); - - Q_D(QQmlDebugServer); - - QQmlDebugStream in(message); - - QString name; - - in >> name; - if (name == QLatin1String("QDeclarativeDebugServer")) { - int op = -1; - in >> op; - if (op == 0) { - QWriteLocker lock(&d->pluginsLock); - int version; - in >> version >> d->clientPlugins; - - //Get the supported QDataStream version - if (!in.atEnd()) { - in >> s_dataStreamVersion; - if (s_dataStreamVersion > QDataStream().version()) - s_dataStreamVersion = QDataStream().version(); - } - - // Send the hello answer immediately, since it needs to arrive before - // the plugins below start sending messages. - - QByteArray helloAnswer; - QQmlDebugStream out(&helloAnswer, QIODevice::WriteOnly); - QStringList pluginNames; - QList<float> pluginVersions; - foreach (QQmlDebugService *service, d->plugins.values()) { - pluginNames << service->name(); - pluginVersions << service->version(); - } - - out << QString(QStringLiteral("QDeclarativeDebugClient")) << 0 << protocolVersion - << pluginNames << pluginVersions << s_dataStreamVersion; - - d->connection->send(QList<QByteArray>() << helloAnswer); - - QMutexLocker helloLock(&d->helloMutex); - d->gotHello = true; - - for (DebugServiceConstIt iter = d->plugins.constBegin(), cend = d->plugins.constEnd(); iter != cend; ++iter) { - QQmlDebugService::State newState = QQmlDebugService::Unavailable; - if (d->clientPlugins.contains(iter.key())) - newState = QQmlDebugService::Enabled; - d->changeServiceStateCalls.ref(); - d->_q_changeServiceState(iter.value()->name(), newState); - } - - d->helloCondition.wakeAll(); - - } else if (op == 1) { - QWriteLocker lock(&d->pluginsLock); - - // Service Discovery - QStringList oldClientPlugins = d->clientPlugins; - in >> d->clientPlugins; - - for (DebugServiceConstIt iter = d->plugins.constBegin(), cend = d->plugins.constEnd(); iter != cend; ++iter) { - const QString pluginName = iter.key(); - QQmlDebugService::State newState = QQmlDebugService::Unavailable; - if (d->clientPlugins.contains(pluginName)) - newState = QQmlDebugService::Enabled; - - if (oldClientPlugins.contains(pluginName) - != d->clientPlugins.contains(pluginName)) { - d->changeServiceStateCalls.ref(); - d->_q_changeServiceState(iter.value()->name(), newState); - } - } - - } else { - qWarning("QML Debugger: Invalid control message %d.", op); - d->connection->disconnect(); - return; - } - - } else { - if (d->gotHello) { - QByteArray message; - in >> message; - - QReadLocker lock(&d->pluginsLock); - QHash<QString, QQmlDebugService *>::Iterator iter = d->plugins.find(name); - if (iter == d->plugins.end()) { - qWarning() << "QML Debugger: Message received for missing plugin" << name << '.'; - } else { - (*iter)->messageReceived(message); - } - } else { - qWarning("QML Debugger: Invalid hello message."); - } - - } -} - -void QQmlDebugServerPrivate::_q_changeServiceState(const QString &serviceName, - QQmlDebugService::State newState) -{ - // to be executed in debugger thread - Q_ASSERT(QThread::currentThread() == q_func()->thread()); - - QQmlDebugService *service = 0; - { - // Write lock here, because this can be called from receiveMessage which already has a write - // lock. We cannot downgrade it. We also don't want to give up the write lock and later get - // a read lock as that technique has great potential for deadlocks. - QWriteLocker lock(&pluginsLock); - service = plugins.value(serviceName); - } - - if (service && (service->d_func()->state != newState)) { - service->stateAboutToBeChanged(newState); - service->d_func()->state = newState; - service->stateChanged(newState); - } - - changeServiceStateCalls.deref(); -} - -void QQmlDebugServerPrivate::_q_sendMessages(const QList<QByteArray> &messages) -{ - // to be executed in debugger thread - Q_ASSERT(QThread::currentThread() == q_func()->thread()); - - if (connection) - connection->send(messages); -} - -void QQmlDebugServerPrivate::_q_removeThread() -{ - Q_ASSERT(thread->isFinished()); - Q_ASSERT(QThread::currentThread() == thread); - - QThread *parentThread = thread->thread(); - - // We cannot delete it right away as it will access its data after the finished() signal. - thread->deleteLater(); - thread = 0; - - delete connection; - connection = 0; - - // Move it back to the parent thread so that we can potentially restart it on a new thread. - q_func()->moveToThread(parentThread); -} - -QList<QQmlDebugService*> QQmlDebugServer::services() const -{ - Q_D(const QQmlDebugServer); - QReadLocker lock(&d->pluginsLock); - return d->plugins.values(); -} - -QStringList QQmlDebugServer::serviceNames() const -{ - Q_D(const QQmlDebugServer); - QReadLocker lock(&d->pluginsLock); - return d->plugins.keys(); -} - -void QQmlDebugServer::addEngine(QQmlEngine *engine) -{ - Q_D(QQmlDebugServer); - QWriteLocker lock(&d->pluginsLock); - - foreach (QQmlDebugService *service, d->plugins) - service->engineAboutToBeAdded(engine); - - d->engineConditions[engine].waitForServices(&d->pluginsLock, d->plugins.count()); - - foreach (QQmlDebugService *service, d->plugins) - service->engineAdded(engine); -} - -void QQmlDebugServer::removeEngine(QQmlEngine *engine) -{ - Q_D(QQmlDebugServer); - QWriteLocker lock(&d->pluginsLock); - - foreach (QQmlDebugService *service, d->plugins) - service->engineAboutToBeRemoved(engine); - - d->engineConditions[engine].waitForServices(&d->pluginsLock, d->plugins.count()); - - foreach (QQmlDebugService *service, d->plugins) - service->engineRemoved(engine); -} - -bool QQmlDebugServer::addService(QQmlDebugService *service) -{ - Q_D(QQmlDebugServer); - - // to be executed outside of debugger thread - Q_ASSERT(QThread::currentThread() != thread()); - - connect(service, SIGNAL(attachedToEngine(QQmlEngine*)), - this, SLOT(wakeEngine(QQmlEngine*)), Qt::QueuedConnection); - connect(service, SIGNAL(detachedFromEngine(QQmlEngine*)), - this, SLOT(wakeEngine(QQmlEngine*)), Qt::QueuedConnection); - - - QWriteLocker lock(&d->pluginsLock); - if (!service || d->plugins.contains(service->name())) - return false; - d->plugins.insert(service->name(), service); - d->advertisePlugins(); - QQmlDebugService::State newState = QQmlDebugService::Unavailable; - if (d->clientPlugins.contains(service->name())) - newState = QQmlDebugService::Enabled; - service->d_func()->state = newState; - return true; -} - -bool QQmlDebugServer::removeService(QQmlDebugService *service) -{ - Q_D(QQmlDebugServer); - - // to be executed outside of debugger thread - Q_ASSERT(QThread::currentThread() != thread()); - - QWriteLocker lock(&d->pluginsLock); - QQmlDebugService::State newState = QQmlDebugService::NotConnected; - - d->changeServiceStateCalls.ref(); - QMetaObject::invokeMethod(this, "_q_changeServiceState", Qt::QueuedConnection, - Q_ARG(QString, service->name()), - Q_ARG(QQmlDebugService::State, newState)); - - if (!service || !d->plugins.contains(service->name())) - return false; - d->plugins.remove(service->name()); - - d->advertisePlugins(); - - return true; -} - -void QQmlDebugServer::sendMessages(QQmlDebugService *service, - const QList<QByteArray> &messages) -{ - QList<QByteArray> prefixedMessages; - foreach (const QByteArray &message, messages) { - QByteArray prefixed; - QQmlDebugStream out(&prefixed, QIODevice::WriteOnly); - out << service->name() << message; - prefixedMessages << prefixed; - } - - QMetaObject::invokeMethod(this, "_q_sendMessages", Qt::QueuedConnection, - Q_ARG(QList<QByteArray>, prefixedMessages)); -} - -bool QQmlDebugServer::enable(int portFrom, int portTo, bool block, const QString &hostAddress) -{ -#ifndef QT_NO_QML_DEBUGGER - QQmlDebugServerInstanceWrapper *wrapper = debugServerInstance(); - if (!wrapper) - return false; - QQmlDebugServerPrivate *d = wrapper->m_instance.d_func(); - if (d->thread) - return false; - if (!d->start(portFrom, portTo, block, hostAddress, QLatin1String("qmldbg_tcp"))) - return false; - while (!wrapper->m_instance.hasConnection()) { - if (!wrapper->m_instance.hasThread()) - return false; - } - return true; -#else - Q_UNUSED(portFrom); - Q_UNUSED(portTo); - Q_UNUSED(block); - Q_UNUSED(hostAddress); - return false; -#endif -} - -void QQmlDebugServer::wakeEngine(QQmlEngine *engine) -{ - // to be executed in debugger thread - Q_ASSERT(QThread::currentThread() == thread()); - - Q_D(QQmlDebugServer); - QWriteLocker lock(&d->pluginsLock); - d->engineConditions[engine].wake(); -} - -bool QQmlDebugServerPrivate::EngineCondition::waitForServices(QReadWriteLock *locked, int num) -{ - // to be executed outside of debugger thread - Q_ASSERT(QThread::currentThread() != QQmlDebugServer::instance()->thread()); - - Q_ASSERT_X(numServices == 0, Q_FUNC_INFO, "Request to wait again before previous wait finished"); - numServices = num; - return condition->wait(locked); -} - -void QQmlDebugServerPrivate::EngineCondition::wake() -{ - if (--numServices == 0) - condition->wakeAll(); - Q_ASSERT_X(numServices >=0, Q_FUNC_INFO, "Woken more often than #services."); -} - -QT_END_NAMESPACE - -#include "moc_qqmldebugserver_p.cpp" diff --git a/src/qml/debugger/qqmldebugserver_p.h b/src/qml/debugger/qqmldebugserver_p.h deleted file mode 100644 index b2bd0b2463..0000000000 --- a/src/qml/debugger/qqmldebugserver_p.h +++ /dev/null @@ -1,104 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLDEBUGSERVER_H -#define QQMLDEBUGSERVER_H - -#include <QtQml/qtqmlglobal.h> -#include <private/qqmldebugserverconnection_p.h> -#include <private/qqmldebugservice_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. -// - -QT_BEGIN_NAMESPACE - - -class QQmlDebugServerPrivate; -class Q_QML_PRIVATE_EXPORT QQmlDebugServer : public QObject -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QQmlDebugServer) - Q_DISABLE_COPY(QQmlDebugServer) -public: - - static QQmlDebugServer *instance(); - - bool hasThread() const; - bool hasConnection() const; - bool hasDebuggingClient() const; - bool blockingMode() const; - - QList<QQmlDebugService*> services() const; - QStringList serviceNames() const; - - void addEngine(QQmlEngine *engine); - void removeEngine(QQmlEngine *engine); - - bool addService(QQmlDebugService *service); - bool removeService(QQmlDebugService *service); - - void receiveMessage(const QByteArray &message); - - void sendMessages(QQmlDebugService *service, const QList<QByteArray> &messages); - static bool enable(int portFrom, int portTo, bool block, const QString &hostAddress); - -private slots: - void wakeEngine(QQmlEngine *engine); - -private: - friend class QQmlDebugService; - friend class QQmlDebugServicePrivate; - friend class QQmlDebugServerThread; - friend struct QQmlDebugServerInstanceWrapper; - QQmlDebugServer(); - Q_PRIVATE_SLOT(d_func(), void _q_changeServiceState(const QString &serviceName, - QQmlDebugService::State state)) - Q_PRIVATE_SLOT(d_func(), void _q_sendMessages(QList<QByteArray>)) - Q_PRIVATE_SLOT(d_func(), void _q_removeThread()) - -public: - static int s_dataStreamVersion; -}; - -QT_END_NAMESPACE - -#endif // QQMLDEBUGSERVICE_H diff --git a/src/qml/debugger/qqmldebugserverconnection_p.h b/src/qml/debugger/qqmldebugserverconnection_p.h deleted file mode 100644 index 9170238b46..0000000000 --- a/src/qml/debugger/qqmldebugserverconnection_p.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLDEBUGSERVERCONNECTION_H -#define QQMLDEBUGSERVERCONNECTION_H - -#include <QtQml/qtqmlglobal.h> -#include <private/qqmlglobal_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. -// - -QT_BEGIN_NAMESPACE - - -class QQmlDebugServer; -class Q_QML_PRIVATE_EXPORT QQmlDebugServerConnection -{ -public: - QQmlDebugServerConnection() {} - virtual ~QQmlDebugServerConnection() {} - - virtual void setServer(QQmlDebugServer *server) = 0; - virtual bool setPortRange(int portFrom, int portTo, bool bock, const QString &hostaddress) = 0; - virtual bool isConnected() const = 0; - virtual void send(const QList<QByteArray> &messages) = 0; - virtual void disconnect() = 0; - virtual void waitForConnection() = 0; - virtual bool waitForMessage() = 0; -}; - -#define QQmlDebugServerConnection_iid "org.qt-project.Qt.QQmlDebugServerConnection" - -Q_DECLARE_INTERFACE(QQmlDebugServerConnection, QQmlDebugServerConnection_iid) - -QT_END_NAMESPACE - -#endif // QQMLDEBUGSERVERCONNECTION_H diff --git a/src/qml/debugger/qqmldebugservice.cpp b/src/qml/debugger/qqmldebugservice.cpp index b37a7335a0..0b07f320ec 100644 --- a/src/qml/debugger/qqmldebugservice.cpp +++ b/src/qml/debugger/qqmldebugservice.cpp @@ -32,8 +32,7 @@ ****************************************************************************/ #include "qqmldebugservice_p.h" -#include "qqmldebugservice_p_p.h" -#include "qqmldebugserver_p.h" +#include "qqmldebugconnector_p.h" #include <private/qqmldata_p.h> #include <private/qqmlcontext_p.h> @@ -43,58 +42,55 @@ QT_BEGIN_NAMESPACE -QQmlDebugServicePrivate::QQmlDebugServicePrivate() -{ -} +class QQmlDebugServer; -QQmlDebugService::QQmlDebugService(const QString &name, float version, QObject *parent) - : QObject(*(new QQmlDebugServicePrivate), parent) +class QQmlDebugServicePrivate : public QObjectPrivate { - QQmlDebugServer::instance(); // create it when it isn't there yet. + Q_DECLARE_PUBLIC(QQmlDebugService) +public: + QQmlDebugServicePrivate(const QString &name, float version); - Q_D(QQmlDebugService); - d->name = name; - d->version = version; - d->state = QQmlDebugService::NotConnected; -} + const QString name; + const float version; + QQmlDebugService::State state; +}; -QQmlDebugService::QQmlDebugService(QQmlDebugServicePrivate &dd, - const QString &name, float version, QObject *parent) - : QObject(dd, parent) +QQmlDebugServicePrivate::QQmlDebugServicePrivate(const QString &name, float version) : + name(name), version(version), state(QQmlDebugService::NotConnected) { - Q_D(QQmlDebugService); - d->name = name; - d->version = version; - d->state = QQmlDebugService::NotConnected; } -/** - Registers the service. This should be called in the constructor of the inherited class. From - then on the service might get asynchronous calls to messageReceived(). - */ -QQmlDebugService::State QQmlDebugService::registerService() +QQmlDebugService::QQmlDebugService(const QString &name, float version, QObject *parent) + : QObject(*(new QQmlDebugServicePrivate(name, version)), parent) { Q_D(QQmlDebugService); - QQmlDebugServer *server = QQmlDebugServer::instance(); + QQmlDebugConnector *server = QQmlDebugConnector::instance(); if (!server) - return NotConnected; + return; - if (server->serviceNames().contains(d->name)) { + if (server->service(d->name)) { qWarning() << "QQmlDebugService: Conflicting plugin name" << d->name; } else { - server->addService(this); + server->addService(d->name, this); } - return state(); } QQmlDebugService::~QQmlDebugService() { - if (QQmlDebugServer *inst = QQmlDebugServer::instance()) - inst->removeService(this); + Q_D(QQmlDebugService); + QQmlDebugConnector *server = QQmlDebugConnector::instance(); + + if (!server) + return; + + if (server->service(d->name) != this) + qWarning() << "QQmlDebugService: Plugin" << d->name << "is not registered."; + else + server->removeService(d->name); } -QString QQmlDebugService::name() const +const QString &QQmlDebugService::name() const { Q_D(const QQmlDebugService); return d->name; @@ -112,27 +108,38 @@ QQmlDebugService::State QQmlDebugService::state() const return d->state; } -namespace { - -struct ObjectReference +void QQmlDebugService::setState(QQmlDebugService::State newState) { - QPointer<QObject> object; - int id; -}; + Q_D(QQmlDebugService); + d->state = newState; +} -struct ObjectReferenceHash +namespace { +class ObjectReferenceHash : public QObject { + Q_OBJECT +public: ObjectReferenceHash() : nextId(0) {} - QHash<QObject *, ObjectReference> objects; + QHash<QObject *, int> objects; QHash<int, QObject *> ids; int nextId; -}; +private slots: + void remove(QObject *obj); +}; } Q_GLOBAL_STATIC(ObjectReferenceHash, objectReferenceHash) +void ObjectReferenceHash::remove(QObject *obj) +{ + QHash<QObject *, int>::Iterator iter = objects.find(obj); + if (iter != objects.end()) { + ids.remove(iter.value()); + objects.erase(iter); + } +} /*! Returns a unique id for \a object. Calling this method multiple times @@ -144,158 +151,23 @@ int QQmlDebugService::idForObject(QObject *object) return -1; ObjectReferenceHash *hash = objectReferenceHash(); - QHash<QObject *, ObjectReference>::Iterator iter = - hash->objects.find(object); + QHash<QObject *, int>::Iterator iter = hash->objects.find(object); if (iter == hash->objects.end()) { int id = hash->nextId++; - - hash->ids.insert(id, object); - iter = hash->objects.insert(object, ObjectReference()); - iter->object = object; - iter->id = id; - } else if (iter->object != object) { - int id = hash->nextId++; - - hash->ids.remove(iter->id); - hash->ids.insert(id, object); - iter->object = object; - iter->id = id; - } - return iter->id; -} - -/*! - Returns the object for unique \a id. If the object has not previously been - assigned an id, through idForObject(), then 0 is returned. If the object - has been destroyed, 0 is returned. -*/ -QObject *QQmlDebugService::objectForId(int id) -{ - ObjectReferenceHash *hash = objectReferenceHash(); - - QHash<int, QObject *>::Iterator iter = hash->ids.find(id); - if (iter == hash->ids.end()) - return 0; - - - QHash<QObject *, ObjectReference>::Iterator objIter = - hash->objects.find(*iter); - Q_ASSERT(objIter != hash->objects.end()); - - if (objIter->object == 0) { - hash->ids.erase(iter); - hash->objects.erase(objIter); - // run a loop to remove other invalid objects - removeInvalidObjectsFromHash(); - return 0; - } else { - return *iter; + iter = hash->objects.insert(object, id); + connect(object, SIGNAL(destroyed(QObject*)), hash, SLOT(remove(QObject*))); } + return iter.value(); } /*! - Returns a list of objects matching the given filename, line and column. + Returns the mapping of objects to unique \a ids, created through calls to idForObject(). */ -QList<QObject*> QQmlDebugService::objectForLocationInfo(const QString &filename, - int lineNumber, int columnNumber) -{ - ObjectReferenceHash *hash = objectReferenceHash(); - QList<QObject*> objects; - QHash<int, QObject *>::Iterator iter = hash->ids.begin(); - while (iter != hash->ids.end()) { - QHash<QObject *, ObjectReference>::Iterator objIter = - hash->objects.find(*iter); - Q_ASSERT(objIter != hash->objects.end()); - - if (objIter->object == 0) { - iter = hash->ids.erase(iter); - hash->objects.erase(objIter); - } else { - QQmlData *ddata = QQmlData::get(iter.value()); - if (ddata && ddata->outerContext) { - if (QFileInfo(ddata->outerContext->urlString()).fileName() == filename && - ddata->lineNumber == lineNumber && - ddata->columnNumber >= columnNumber) { - objects << *iter; - } - } - ++iter; - } - } - return objects; -} - -void QQmlDebugService::removeInvalidObjectsFromHash() -{ - ObjectReferenceHash *hash = objectReferenceHash(); - QHash<int, QObject *>::Iterator iter = hash->ids.begin(); - while (iter != hash->ids.end()) { - QHash<QObject *, ObjectReference>::Iterator objIter = - hash->objects.find(*iter); - Q_ASSERT(objIter != hash->objects.end()); - - if (objIter->object == 0) { - iter = hash->ids.erase(iter); - hash->objects.erase(objIter); - } else { - ++iter; - } - } -} - -void QQmlDebugService::clearObjectsFromHash() -{ - ObjectReferenceHash *hash = objectReferenceHash(); - hash->ids.clear(); - hash->objects.clear(); -} - -bool QQmlDebugService::isDebuggingEnabled() -{ - return QQmlDebugServer::instance() != 0; -} - -bool QQmlDebugService::hasDebuggingClient() +const QHash<int, QObject *> &QQmlDebugService::objectsForIds() { - return QQmlDebugServer::instance() != 0 - && QQmlDebugServer::instance()->hasDebuggingClient(); -} - -bool QQmlDebugService::blockingMode() -{ - return QQmlDebugServer::instance() != 0 - && QQmlDebugServer::instance()->blockingMode(); -} - -QString QQmlDebugService::objectToString(QObject *obj) -{ - if(!obj) - return QStringLiteral("NULL"); - - QString objectName = obj->objectName(); - if(objectName.isEmpty()) - objectName = QStringLiteral("<unnamed>"); - - QString rv = QString::fromUtf8(obj->metaObject()->className()) + - QLatin1String(": ") + objectName; - - return rv; -} - -void QQmlDebugService::sendMessage(const QByteArray &message) -{ - sendMessages(QList<QByteArray>() << message); -} - -void QQmlDebugService::sendMessages(const QList<QByteArray> &messages) -{ - if (state() != Enabled) - return; - - if (QQmlDebugServer *inst = QQmlDebugServer::instance()) - inst->sendMessages(this, messages); + return objectReferenceHash()->ids; } void QQmlDebugService::stateAboutToBeChanged(State) @@ -328,28 +200,32 @@ void QQmlDebugService::engineRemoved(QQmlEngine *) { } +int QQmlDebugStream::s_dataStreamVersion = QDataStream::Qt_4_7; + QQmlDebugStream::QQmlDebugStream() : QDataStream() { - setVersion(QQmlDebugServer::s_dataStreamVersion); + setVersion(s_dataStreamVersion); } QQmlDebugStream::QQmlDebugStream(QIODevice *d) : QDataStream(d) { - setVersion(QQmlDebugServer::s_dataStreamVersion); + setVersion(s_dataStreamVersion); } QQmlDebugStream::QQmlDebugStream(QByteArray *ba, QIODevice::OpenMode flags) : QDataStream(ba, flags) { - setVersion(QQmlDebugServer::s_dataStreamVersion); + setVersion(s_dataStreamVersion); } QQmlDebugStream::QQmlDebugStream(const QByteArray &ba) : QDataStream(ba) { - setVersion(QQmlDebugServer::s_dataStreamVersion); + setVersion(s_dataStreamVersion); } QT_END_NAMESPACE + +#include "qqmldebugservice.moc" diff --git a/src/qml/debugger/qqmldebugservice_p.h b/src/qml/debugger/qqmldebugservice_p.h index 9cdfc34ff1..3d692133cc 100644 --- a/src/qml/debugger/qqmldebugservice_p.h +++ b/src/qml/debugger/qqmldebugservice_p.h @@ -35,7 +35,8 @@ #define QQMLDEBUGSERVICE_H #include <QtCore/qobject.h> -#include <QtCore/QDataStream> +#include <QtCore/qdatastream.h> +#include <QtCore/qhash.h> #include <private/qtqmlglobal_p.h> @@ -62,35 +63,14 @@ class Q_QML_PRIVATE_EXPORT QQmlDebugService : public QObject Q_DISABLE_COPY(QQmlDebugService) public: - explicit QQmlDebugService(const QString &, float version, QObject *parent = 0); ~QQmlDebugService(); - QString name() const; + const QString &name() const; float version() const; enum State { NotConnected, Unavailable, Enabled }; State state() const; - - void sendMessage(const QByteArray &); - void sendMessages(const QList<QByteArray> &); - - static int idForObject(QObject *); - static QObject *objectForId(int); - static QList<QObject*> objectForLocationInfo(const QString &filename, - int lineNumber, int columnNumber); - static void removeInvalidObjectsFromHash(); - static void clearObjectsFromHash(); - - static QString objectToString(QObject *obj); - - static bool isDebuggingEnabled(); - static bool hasDebuggingClient(); - static bool blockingMode(); - -protected: - QQmlDebugService(QQmlDebugServicePrivate &dd, const QString &name, float version, QObject *parent = 0); - - State registerService(); + void setState(State newState); virtual void stateAboutToBeChanged(State); virtual void stateChanged(State); @@ -101,18 +81,26 @@ protected: virtual void engineAdded(QQmlEngine *); virtual void engineRemoved(QQmlEngine *); + static const QHash<int, QObject *> &objectsForIds(); + static int idForObject(QObject *); + static QObject *objectForId(int id) { return objectsForIds().value(id); } + +protected: + explicit QQmlDebugService(const QString &, float version, QObject *parent = 0); + signals: void attachedToEngine(QQmlEngine *); void detachedFromEngine(QQmlEngine *); -private: - friend class QQmlDebugServer; - friend class QQmlDebugServerPrivate; + void messageToClient(const QString &name, const QByteArray &message); + void messagesToClient(const QString &name, const QList<QByteArray> &messages); }; class Q_QML_PRIVATE_EXPORT QQmlDebugStream : public QDataStream { public: + static int s_dataStreamVersion; + QQmlDebugStream(); explicit QQmlDebugStream(QIODevice *d); QQmlDebugStream(QByteArray *ba, QIODevice::OpenMode flags); diff --git a/src/qml/debugger/qqmldebugservice_p_p.h b/src/qml/debugger/qqmldebugservicefactory_p.h index 7d60739f3a..af50cd4635 100644 --- a/src/qml/debugger/qqmldebugservice_p_p.h +++ b/src/qml/debugger/qqmldebugservicefactory_p.h @@ -31,8 +31,8 @@ ** ****************************************************************************/ -#ifndef QQMLDEBUGSERVICE_P_H -#define QQMLDEBUGSERVICE_P_H +#ifndef QQMLDEBUGSERVICEFACTORY_P_H +#define QQMLDEBUGSERVICEFACTORY_P_H // // W A R N I N G @@ -45,25 +45,19 @@ // We mean it. // -#include <QtCore/qglobal.h> -#include <private/qobject_p.h> +#include "qqmldebugservice_p.h" QT_BEGIN_NAMESPACE - -class QQmlDebugServer; - -class QQmlDebugServicePrivate : public QObjectPrivate +class Q_QML_PRIVATE_EXPORT QQmlDebugServiceFactory : public QObject { - Q_DECLARE_PUBLIC(QQmlDebugService) + Q_OBJECT public: - QQmlDebugServicePrivate(); - - QString name; - float version; - QQmlDebugService::State state; + virtual QQmlDebugService *create(const QString &key) = 0; }; +#define QQmlDebugServiceFactory_iid "org.qt-project.Qt.QQmlDebugServiceFactory" + QT_END_NAMESPACE -#endif // QQMLDEBUGSERVICE_P_H +#endif // QQMLDEBUGSERVICEFACTORY_P_H diff --git a/src/qml/jsruntime/qv4qmlextensions_p.h b/src/qml/debugger/qqmldebugserviceinterfaces.cpp index e4b9f75298..2bf9f2785c 100644 --- a/src/qml/jsruntime/qv4qmlextensions_p.h +++ b/src/qml/debugger/qqmldebugserviceinterfaces.cpp @@ -30,29 +30,14 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#ifndef QV4QMLEXTENSIONS_P_H -#define QV4QMLEXTENSIONS_P_H -#include <qtqmlglobal.h> -#include <qv4global_p.h> +#include "qqmldebugserviceinterfaces_p.h" QT_BEGIN_NAMESPACE -namespace QV4 { - -struct Q_QML_EXPORT QmlExtensions -{ - QmlExtensions() - : valueTypeWrapperPrototype(0) - {} - - Heap::Object *valueTypeWrapperPrototype; - - void markObjects(ExecutionEngine *e); -}; - -} // namespace QV4 +const QString QV4DebugService::s_key = QStringLiteral("V8Debugger"); +const QString QQmlEngineDebugService::s_key = QStringLiteral("QmlDebugger"); +const QString QQmlInspectorService::s_key = QStringLiteral("QmlInspector"); +const QString QQmlProfilerService::s_key = QStringLiteral("CanvasFrameRate"); QT_END_NAMESPACE - -#endif diff --git a/src/qml/debugger/qqmldebugserviceinterfaces_p.h b/src/qml/debugger/qqmldebugserviceinterfaces_p.h new file mode 100644 index 0000000000..a2ba670608 --- /dev/null +++ b/src/qml/debugger/qqmldebugserviceinterfaces_p.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLDEBUGSERVICEINTERFACES_P_H +#define QQMLDEBUGSERVICEINTERFACES_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. +// + +#include <QtCore/qstring.h> +#include <private/qtqmlglobal_p.h> +#include <private/qqmldebugservice_p.h> +#include <private/qqmldebugstatesdelegate_p.h> +#include <private/qqmlabstractprofileradapter_p.h> +#include <private/qqmlboundsignal_p.h> + +#include <limits> + +QT_BEGIN_NAMESPACE + +class Q_QML_PRIVATE_EXPORT QV4DebugService : protected QQmlDebugService +{ + Q_OBJECT +public: + virtual void signalEmitted(const QString &signal) = 0; + +protected: + friend class QQmlDebugConnector; + + QV4DebugService(float version, QObject *parent = 0) : + QQmlDebugService(s_key, version, parent) {} + + static const QString s_key; +}; + +class Q_QML_PRIVATE_EXPORT QQmlProfilerService : protected QQmlDebugService +{ + Q_OBJECT +public: + virtual void addGlobalProfiler(QQmlAbstractProfilerAdapter *profiler) = 0; + virtual void removeGlobalProfiler(QQmlAbstractProfilerAdapter *profiler) = 0; + + virtual void startProfiling(QQmlEngine *engine, + quint64 features = std::numeric_limits<quint64>::max()) = 0; + virtual void stopProfiling(QQmlEngine *engine) = 0; + + virtual void dataReady(QQmlAbstractProfilerAdapter *profiler) = 0; + +protected: + friend class QQmlDebugConnector; + + QQmlProfilerService(float version, QObject *parent = 0) : + QQmlDebugService(s_key, version, parent) {} + + static const QString s_key; +}; + +class Q_QML_PRIVATE_EXPORT QQmlEngineDebugService : protected QQmlDebugService +{ + Q_OBJECT +public: + virtual void objectCreated(QQmlEngine *engine, QObject *object) = 0; + virtual void setStatesDelegate(QQmlDebugStatesDelegate *) = 0; + +protected: + friend class QQmlDebugConnector; + + QQmlEngineDebugService(float version, QObject *parent = 0) : + QQmlDebugService(s_key, version, parent) {} + + QQmlBoundSignal *nextSignal(QQmlBoundSignal *prev) { return prev->m_nextSignal; } + + static const QString s_key; +}; + +class Q_QML_PRIVATE_EXPORT QQmlInspectorService : protected QQmlDebugService +{ + Q_OBJECT +public: + virtual void addView(QObject *) = 0; + virtual void removeView(QObject *) = 0; + +protected: + friend class QQmlDebugConnector; + + QQmlInspectorService(float version, QObject *parent = 0) : + QQmlDebugService(s_key, version, parent) {} + + static const QString s_key; +}; + +QT_END_NAMESPACE + +#endif // QQMLDEBUGSERVICEINTERFACES_P_H + diff --git a/src/qml/debugger/qqmlenginecontrolservice.cpp b/src/qml/debugger/qqmlenginecontrolservice.cpp deleted file mode 100644 index 07c6715524..0000000000 --- a/src/qml/debugger/qqmlenginecontrolservice.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QQmlEngine> -#include "qqmldebug.h" -#include "qqmlenginecontrolservice_p.h" - -QT_BEGIN_NAMESPACE - -Q_GLOBAL_STATIC(QQmlEngineControlService, qmlEngineControlService) - -QQmlEngineControlService::QQmlEngineControlService() : - QQmlDebugService(QStringLiteral("EngineControl"), 1) -{ - QMutexLocker lock(&dataMutex); - registerService(); -} - -QQmlEngineControlService *QQmlEngineControlService::instance() -{ - return qmlEngineControlService(); -} - -void QQmlEngineControlService::messageReceived(const QByteArray &message) -{ - QMutexLocker lock(&dataMutex); - QQmlDebugStream d(message); - int command; - int engineId; - d >> command >> engineId; - QQmlEngine *engine = qobject_cast<QQmlEngine *>(objectForId(engineId)); - if (command == StartWaitingEngine && startingEngines.contains(engine)) { - startingEngines.removeOne(engine); - emit attachedToEngine(engine); - } else if (command == StopWaitingEngine && stoppingEngines.contains(engine)) { - stoppingEngines.removeOne(engine); - emit detachedFromEngine(engine); - } -} - -void QQmlEngineControlService::engineAboutToBeAdded(QQmlEngine *engine) -{ - QMutexLocker lock(&dataMutex); - if (state() == Enabled) { - Q_ASSERT(!stoppingEngines.contains(engine)); - Q_ASSERT(!startingEngines.contains(engine)); - startingEngines.append(engine); - sendMessage(EngineAboutToBeAdded, engine); - } else { - emit attachedToEngine(engine); - } -} - -void QQmlEngineControlService::engineAboutToBeRemoved(QQmlEngine *engine) -{ - QMutexLocker lock(&dataMutex); - if (state() == Enabled) { - Q_ASSERT(!stoppingEngines.contains(engine)); - Q_ASSERT(!startingEngines.contains(engine)); - stoppingEngines.append(engine); - sendMessage(EngineAboutToBeRemoved, engine); - } else { - emit detachedFromEngine(engine); - } -} - -void QQmlEngineControlService::engineAdded(QQmlEngine *engine) -{ - if (state() == Enabled) { - QMutexLocker lock(&dataMutex); - Q_ASSERT(!startingEngines.contains(engine)); - Q_ASSERT(!stoppingEngines.contains(engine)); - sendMessage(EngineAdded, engine); - } -} - -void QQmlEngineControlService::engineRemoved(QQmlEngine *engine) -{ - if (state() == Enabled) { - QMutexLocker lock(&dataMutex); - Q_ASSERT(!startingEngines.contains(engine)); - Q_ASSERT(!stoppingEngines.contains(engine)); - sendMessage(EngineRemoved, engine); - } -} - -void QQmlEngineControlService::sendMessage(QQmlEngineControlService::MessageType type, QQmlEngine *engine) -{ - QByteArray message; - QQmlDebugStream d(&message, QIODevice::WriteOnly); - d << type << idForObject(engine); - QQmlDebugService::sendMessage(message); -} - -void QQmlEngineControlService::stateChanged(State) -{ - // We flush everything for any kind of state change, to avoid complicated timing issues. - QMutexLocker lock(&dataMutex); - foreach (QQmlEngine *engine, startingEngines) - emit attachedToEngine(engine); - startingEngines.clear(); - foreach (QQmlEngine *engine, stoppingEngines) - emit detachedFromEngine(engine); - stoppingEngines.clear(); -} - -QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmlenginedebugservice.cpp b/src/qml/debugger/qqmlenginedebugservice.cpp deleted file mode 100644 index da01d00f17..0000000000 --- a/src/qml/debugger/qqmlenginedebugservice.cpp +++ /dev/null @@ -1,820 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlenginedebugservice_p.h" - -#include "qqmldebugstatesdelegate_p.h" -#include <private/qqmlboundsignal_p.h> -#include <qqmlengine.h> -#include <private/qqmlmetatype_p.h> -#include <qqmlproperty.h> -#include <private/qqmlproperty_p.h> -#include <private/qqmlbinding_p.h> -#include <private/qqmlcontext_p.h> -#include <private/qqmlwatcher_p.h> -#include <private/qqmlvaluetype_p.h> -#include <private/qqmlvmemetaobject_p.h> -#include <private/qqmlexpression_p.h> - -#include <QtCore/qdebug.h> -#include <QtCore/qmetaobject.h> -#include <private/qmetaobject_p.h> - -QT_BEGIN_NAMESPACE - -Q_GLOBAL_STATIC(QQmlEngineDebugService, qmlEngineDebugService) - -QQmlEngineDebugService *QQmlEngineDebugService::instance() -{ - return qmlEngineDebugService(); -} - -QQmlEngineDebugService::QQmlEngineDebugService(QObject *parent) - : QQmlDebugService(QStringLiteral("QmlDebugger"), 2, parent), - m_watch(new QQmlWatcher(this)), - m_statesDelegate(0) -{ - QObject::connect(m_watch, SIGNAL(propertyChanged(int,int,QMetaProperty,QVariant)), - this, SLOT(propertyChanged(int,int,QMetaProperty,QVariant))); - - registerService(); -} - -QQmlEngineDebugService::~QQmlEngineDebugService() -{ - delete m_statesDelegate; -} - -QDataStream &operator<<(QDataStream &ds, - const QQmlEngineDebugService::QQmlObjectData &data) -{ - ds << data.url << data.lineNumber << data.columnNumber << data.idString - << data.objectName << data.objectType << data.objectId << data.contextId - << data.parentId; - return ds; -} - -QDataStream &operator>>(QDataStream &ds, - QQmlEngineDebugService::QQmlObjectData &data) -{ - ds >> data.url >> data.lineNumber >> data.columnNumber >> data.idString - >> data.objectName >> data.objectType >> data.objectId >> data.contextId - >> data.parentId; - return ds; -} - -QDataStream &operator<<(QDataStream &ds, - const QQmlEngineDebugService::QQmlObjectProperty &data) -{ - ds << (int)data.type << data.name; - // check first whether the data can be saved - // (otherwise we assert in QVariant::operator<<) - QByteArray buffer; - QDataStream fakeStream(&buffer, QIODevice::WriteOnly); - if (QMetaType::save(fakeStream, data.value.type(), data.value.constData())) - ds << data.value; - else - ds << QVariant(); - ds << data.valueTypeName << data.binding << data.hasNotifySignal; - return ds; -} - -QDataStream &operator>>(QDataStream &ds, - QQmlEngineDebugService::QQmlObjectProperty &data) -{ - int type; - ds >> type >> data.name >> data.value >> data.valueTypeName - >> data.binding >> data.hasNotifySignal; - data.type = (QQmlEngineDebugService::QQmlObjectProperty::Type)type; - return ds; -} - -static inline bool isSignalPropertyName(const QString &signalName) -{ - // see QmlCompiler::isSignalPropertyName - return signalName.length() >= 3 && signalName.startsWith(QLatin1String("on")) && - signalName.at(2).isLetter() && signalName.at(2).isUpper(); -} - -static bool hasValidSignal(QObject *object, const QString &propertyName) -{ - if (!isSignalPropertyName(propertyName)) - return false; - - QString signalName = propertyName.mid(2); - signalName[0] = signalName.at(0).toLower(); - - int sigIdx = QQmlPropertyPrivate::findSignalByName(object->metaObject(), signalName.toLatin1()).methodIndex(); - - if (sigIdx == -1) - return false; - - return true; -} - -QQmlEngineDebugService::QQmlObjectProperty -QQmlEngineDebugService::propertyData(QObject *obj, int propIdx) -{ - QQmlObjectProperty rv; - - QMetaProperty prop = obj->metaObject()->property(propIdx); - - rv.type = QQmlObjectProperty::Unknown; - rv.valueTypeName = QString::fromUtf8(prop.typeName()); - rv.name = QString::fromUtf8(prop.name()); - rv.hasNotifySignal = prop.hasNotifySignal(); - QQmlAbstractBinding *binding = - QQmlPropertyPrivate::binding(QQmlProperty(obj, rv.name)); - if (binding) - rv.binding = binding->expression(); - - if (QQmlValueTypeFactory::isValueType(prop.userType())) { - rv.type = QQmlObjectProperty::Basic; - } else if (QQmlMetaType::isQObject(prop.userType())) { - rv.type = QQmlObjectProperty::Object; - } else if (QQmlMetaType::isList(prop.userType())) { - rv.type = QQmlObjectProperty::List; - } else if (prop.userType() == QMetaType::QVariant) { - rv.type = QQmlObjectProperty::Variant; - } - - QVariant value; - if (rv.type != QQmlObjectProperty::Unknown && prop.userType() != 0) { - value = prop.read(obj); - } - rv.value = valueContents(value); - - return rv; -} - -QVariant QQmlEngineDebugService::valueContents(QVariant value) const -{ - // We can't send JS objects across the wire, so transform them to variant - // maps for serialization. - if (value.userType() == qMetaTypeId<QJSValue>()) - value = value.value<QJSValue>().toVariant(); - const int userType = value.userType(); - - //QObject * is not streamable. - //Convert all such instances to a String value - - if (value.type() == QVariant::List) { - QVariantList contents; - QVariantList list = value.toList(); - int count = list.size(); - for (int i = 0; i < count; i++) - contents << valueContents(list.at(i)); - return contents; - } - - if (value.type() == QVariant::Map) { - QVariantMap contents; - QMapIterator<QString, QVariant> i(value.toMap()); - while (i.hasNext()) { - i.next(); - contents.insert(i.key(), valueContents(i.value())); - } - return contents; - } - - if (QQmlValueTypeFactory::isValueType(userType)) { - const QMetaObject *mo = QQmlValueTypeFactory::metaObjectForMetaType(userType); - if (mo) { - int toStringIndex = mo->indexOfMethod("toString"); - if (toStringIndex != -1) { - QMetaMethod mm = mo->method(toStringIndex); - QMetaType info(userType); - QString s; - if (info.flags() & QMetaType::IsGadget - && mm.invokeOnGadget(value.data(), Q_RETURN_ARG(QString, s))) - return s; - } - } - - return value; - } - - if (QQmlMetaType::isQObject(userType)) { - QObject *o = QQmlMetaType::toQObject(value); - if (o) { - QString name = o->objectName(); - if (name.isEmpty()) - name = QStringLiteral("<unnamed object>"); - return name; - } - } - - return QString(QStringLiteral("<unknown value>")); -} - -void QQmlEngineDebugService::buildObjectDump(QDataStream &message, - QObject *object, bool recur, bool dumpProperties) -{ - message << objectData(object); - - QObjectList children = object->children(); - - int childrenCount = children.count(); - for (int ii = 0; ii < children.count(); ++ii) { - if (qobject_cast<QQmlContext*>(children[ii])) - --childrenCount; - } - - message << childrenCount << recur; - - QList<QQmlObjectProperty> fakeProperties; - - for (int ii = 0; ii < children.count(); ++ii) { - QObject *child = children.at(ii); - if (qobject_cast<QQmlContext*>(child)) - continue; - if (recur) - buildObjectDump(message, child, recur, dumpProperties); - else - message << objectData(child); - } - - if (!dumpProperties) { - message << 0; - return; - } - - QList<int> propertyIndexes; - for (int ii = 0; ii < object->metaObject()->propertyCount(); ++ii) { - if (object->metaObject()->property(ii).isScriptable()) - propertyIndexes << ii; - } - - QQmlData *ddata = QQmlData::get(object); - if (ddata && ddata->signalHandlers) { - QQmlAbstractBoundSignal *signalHandler = ddata->signalHandlers; - - while (signalHandler) { - if (!dumpProperties) { - signalHandler = signalHandler->m_nextSignal; - continue; - } - QQmlObjectProperty prop; - prop.type = QQmlObjectProperty::SignalProperty; - prop.hasNotifySignal = false; - QQmlBoundSignalExpression *expr = signalHandler->expression(); - if (expr) { - prop.value = expr->expression(); - QObject *scope = expr->scopeObject(); - if (scope) { - QString methodName = QString::fromLatin1(QMetaObjectPrivate::signal(scope->metaObject(), signalHandler->index()).name()); - if (!methodName.isEmpty()) { - prop.name = QLatin1String("on") + methodName[0].toUpper() - + methodName.mid(1); - } - } - } - fakeProperties << prop; - - signalHandler = signalHandler->m_nextSignal; - } - } - - message << propertyIndexes.size() + fakeProperties.count(); - - for (int ii = 0; ii < propertyIndexes.size(); ++ii) - message << propertyData(object, propertyIndexes.at(ii)); - - for (int ii = 0; ii < fakeProperties.count(); ++ii) - message << fakeProperties[ii]; -} - -void QQmlEngineDebugService::prepareDeferredObjects(QObject *obj) -{ - qmlExecuteDeferred(obj); - - QObjectList children = obj->children(); - for (int ii = 0; ii < children.count(); ++ii) { - QObject *child = children.at(ii); - prepareDeferredObjects(child); - } - -} - -void QQmlEngineDebugService::storeObjectIds(QObject *co) -{ - QQmlDebugService::idForObject(co); - QObjectList children = co->children(); - for (int ii = 0; ii < children.count(); ++ii) - storeObjectIds(children.at(ii)); -} - -void QQmlEngineDebugService::buildObjectList(QDataStream &message, - QQmlContext *ctxt, - const QList<QPointer<QObject> > &instances) -{ - QQmlContextData *p = QQmlContextData::get(ctxt); - - QString ctxtName = ctxt->objectName(); - int ctxtId = QQmlDebugService::idForObject(ctxt); - if (ctxt->contextObject()) - storeObjectIds(ctxt->contextObject()); - - message << ctxtName << ctxtId; - - int count = 0; - - QQmlContextData *child = p->childContexts; - while (child) { - ++count; - child = child->nextChild; - } - - message << count; - - child = p->childContexts; - while (child) { - buildObjectList(message, child->asQQmlContext(), instances); - child = child->nextChild; - } - - count = 0; - for (int ii = 0; ii < instances.count(); ++ii) { - QQmlData *data = QQmlData::get(instances.at(ii)); - if (data->context == p) - count ++; - } - message << count; - - for (int ii = 0; ii < instances.count(); ++ii) { - QQmlData *data = QQmlData::get(instances.at(ii)); - if (data->context == p) - message << objectData(instances.at(ii)); - } -} - -void QQmlEngineDebugService::buildStatesList(bool cleanList, - const QList<QPointer<QObject> > &instances) -{ - if (m_statesDelegate) - m_statesDelegate->buildStatesList(cleanList, instances); -} - -QQmlEngineDebugService::QQmlObjectData -QQmlEngineDebugService::objectData(QObject *object) -{ - QQmlData *ddata = QQmlData::get(object); - QQmlObjectData rv; - if (ddata && ddata->outerContext) { - rv.url = ddata->outerContext->url(); - rv.lineNumber = ddata->lineNumber; - rv.columnNumber = ddata->columnNumber; - } else { - rv.lineNumber = -1; - rv.columnNumber = -1; - } - - QQmlContext *context = qmlContext(object); - if (context) { - QQmlContextData *cdata = QQmlContextData::get(context); - if (cdata) - rv.idString = cdata->findObjectId(object); - } - - rv.objectName = object->objectName(); - rv.objectId = QQmlDebugService::idForObject(object); - rv.contextId = QQmlDebugService::idForObject(qmlContext(object)); - rv.parentId = QQmlDebugService::idForObject(object->parent()); - QQmlType *type = QQmlMetaType::qmlType(object->metaObject()); - if (type) { - QString typeName = type->qmlTypeName(); - int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); - rv.objectType = lastSlash < 0 ? typeName : typeName.mid(lastSlash+1); - } else { - rv.objectType = QString::fromUtf8(object->metaObject()->className()); - int marker = rv.objectType.indexOf(QLatin1String("_QMLTYPE_")); - if (marker != -1) - rv.objectType = rv.objectType.left(marker); - } - - return rv; -} - -void QQmlEngineDebugService::messageReceived(const QByteArray &message) -{ - QMetaObject::invokeMethod(this, "processMessage", Qt::QueuedConnection, Q_ARG(QByteArray, message)); -} - -void QQmlEngineDebugService::processMessage(const QByteArray &message) -{ - QQmlDebugStream ds(message); - - QByteArray type; - int queryId; - ds >> type >> queryId; - - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); - - if (type == "LIST_ENGINES") { - rs << QByteArray("LIST_ENGINES_R"); - rs << queryId << m_engines.count(); - - for (int ii = 0; ii < m_engines.count(); ++ii) { - QQmlEngine *engine = m_engines.at(ii); - - QString engineName = engine->objectName(); - int engineId = QQmlDebugService::idForObject(engine); - - rs << engineName << engineId; - } - - } else if (type == "LIST_OBJECTS") { - int engineId = -1; - ds >> engineId; - - QQmlEngine *engine = - qobject_cast<QQmlEngine *>(QQmlDebugService::objectForId(engineId)); - - rs << QByteArray("LIST_OBJECTS_R") << queryId; - - if (engine) { - QQmlContext *rootContext = engine->rootContext(); - // Clean deleted objects - QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(rootContext); - for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) { - if (!ctxtPriv->instances.at(ii)) { - ctxtPriv->instances.removeAt(ii); - --ii; - } - } - buildObjectList(rs, rootContext, ctxtPriv->instances); - buildStatesList(true, ctxtPriv->instances); - } - - } else if (type == "FETCH_OBJECT") { - int objectId; - bool recurse; - bool dumpProperties = true; - - ds >> objectId >> recurse >> dumpProperties; - - QObject *object = QQmlDebugService::objectForId(objectId); - - rs << QByteArray("FETCH_OBJECT_R") << queryId; - - if (object) { - if (recurse) - prepareDeferredObjects(object); - buildObjectDump(rs, object, recurse, dumpProperties); - } - - } else if (type == "FETCH_OBJECTS_FOR_LOCATION") { - QString file; - int lineNumber; - int columnNumber; - bool recurse; - bool dumpProperties = true; - - ds >> file >> lineNumber >> columnNumber >> recurse >> dumpProperties; - - QList<QObject*> objects = QQmlDebugService::objectForLocationInfo( - file, lineNumber, columnNumber); - - rs << QByteArray("FETCH_OBJECTS_FOR_LOCATION_R") << queryId - << objects.count(); - - foreach (QObject *object, objects) { - if (recurse) - prepareDeferredObjects(object); - buildObjectDump(rs, object, recurse, dumpProperties); - } - - } else if (type == "WATCH_OBJECT") { - int objectId; - - ds >> objectId; - bool ok = m_watch->addWatch(queryId, objectId); - - rs << QByteArray("WATCH_OBJECT_R") << queryId << ok; - - } else if (type == "WATCH_PROPERTY") { - int objectId; - QByteArray property; - - ds >> objectId >> property; - bool ok = m_watch->addWatch(queryId, objectId, property); - - rs << QByteArray("WATCH_PROPERTY_R") << queryId << ok; - - } else if (type == "WATCH_EXPR_OBJECT") { - int debugId; - QString expr; - - ds >> debugId >> expr; - bool ok = m_watch->addWatch(queryId, debugId, expr); - - rs << QByteArray("WATCH_EXPR_OBJECT_R") << queryId << ok; - - } else if (type == "NO_WATCH") { - bool ok = m_watch->removeWatch(queryId); - - rs << QByteArray("NO_WATCH_R") << queryId << ok; - - } else if (type == "EVAL_EXPRESSION") { - int objectId; - QString expr; - - ds >> objectId >> expr; - int engineId = -1; - if (!ds.atEnd()) - ds >> engineId; - - QObject *object = QQmlDebugService::objectForId(objectId); - QQmlContext *context = qmlContext(object); - if (!context) { - QQmlEngine *engine = qobject_cast<QQmlEngine *>( - QQmlDebugService::objectForId(engineId)); - if (engine && m_engines.contains(engine)) - context = engine->rootContext(); - } - QVariant result; - if (context) { - QQmlExpression exprObj(context, object, expr); - bool undefined = false; - QVariant value = exprObj.evaluate(&undefined); - if (undefined) - result = QString(QStringLiteral("<undefined>")); - else - result = valueContents(value); - } else { - result = QString(QStringLiteral("<unknown context>")); - } - - rs << QByteArray("EVAL_EXPRESSION_R") << queryId << result; - - } else if (type == "SET_BINDING") { - int objectId; - QString propertyName; - QVariant expr; - bool isLiteralValue; - QString filename; - int line; - ds >> objectId >> propertyName >> expr >> isLiteralValue >> - filename >> line; - bool ok = setBinding(objectId, propertyName, expr, isLiteralValue, - filename, line); - - rs << QByteArray("SET_BINDING_R") << queryId << ok; - - } else if (type == "RESET_BINDING") { - int objectId; - QString propertyName; - ds >> objectId >> propertyName; - bool ok = resetBinding(objectId, propertyName); - - rs << QByteArray("RESET_BINDING_R") << queryId << ok; - - } else if (type == "SET_METHOD_BODY") { - int objectId; - QString methodName; - QString methodBody; - ds >> objectId >> methodName >> methodBody; - bool ok = setMethodBody(objectId, methodName, methodBody); - - rs << QByteArray("SET_METHOD_BODY_R") << queryId << ok; - - } - sendMessage(reply); -} - -bool QQmlEngineDebugService::setBinding(int objectId, - const QString &propertyName, - const QVariant &expression, - bool isLiteralValue, - QString filename, - int line, - int column) -{ - bool ok = true; - QObject *object = objectForId(objectId); - QQmlContext *context = qmlContext(object); - - if (object && context) { - QQmlProperty property(object, propertyName, context); - if (property.isValid()) { - - bool inBaseState = true; - if (m_statesDelegate) { - m_statesDelegate->updateBinding(context, property, expression, isLiteralValue, - filename, line, column, &inBaseState); - } - - if (inBaseState) { - if (isLiteralValue) { - property.write(expression); - } else if (hasValidSignal(object, propertyName)) { - QQmlBoundSignalExpression *qmlExpression = new QQmlBoundSignalExpression(object, QQmlPropertyPrivate::get(property)->signalIndex(), - QQmlContextData::get(context), object, expression.toString(), - filename, line, column); - QQmlPropertyPrivate::takeSignalExpression(property, qmlExpression); - } else if (property.isProperty()) { - QQmlBinding *binding = new QQmlBinding(expression.toString(), object, QQmlContextData::get(context), filename, line, column);; - binding->setTarget(property); - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::setBinding(property, binding); - if (oldBinding) - oldBinding->destroy(); - binding->update(); - } else { - ok = false; - qWarning() << "QQmlEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object; - } - } - - } else { - // not a valid property - if (m_statesDelegate) - ok = m_statesDelegate->setBindingForInvalidProperty(object, propertyName, expression, isLiteralValue); - if (!ok) - qWarning() << "QQmlEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object; - } - } - return ok; -} - -bool QQmlEngineDebugService::resetBinding(int objectId, const QString &propertyName) -{ - QObject *object = objectForId(objectId); - QQmlContext *context = qmlContext(object); - - if (object && context) { - QString parentProperty = propertyName; - if (propertyName.indexOf(QLatin1Char('.')) != -1) - parentProperty = propertyName.left(propertyName.indexOf(QLatin1Char('.'))); - - if (object->property(parentProperty.toLatin1()).isValid()) { - QQmlProperty property(object, propertyName); - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(property); - if (oldBinding) { - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::setBinding(property, 0); - if (oldBinding) - oldBinding->destroy(); - } - if (property.isResettable()) { - // Note: this will reset the property in any case, without regard to states - // Right now almost no QQuickItem has reset methods for its properties (with the - // notable exception of QQuickAnchors), so this is not a big issue - // later on, setBinding does take states into account - property.reset(); - } else { - // overwrite with default value - if (QQmlType *objType = QQmlMetaType::qmlType(object->metaObject())) { - if (QObject *emptyObject = objType->create()) { - if (emptyObject->property(parentProperty.toLatin1()).isValid()) { - QVariant defaultValue = QQmlProperty(emptyObject, propertyName).read(); - if (defaultValue.isValid()) { - setBinding(objectId, propertyName, defaultValue, true); - } - } - delete emptyObject; - } - } - } - return true; - } - - if (hasValidSignal(object, propertyName)) { - QQmlProperty property(object, propertyName, context); - QQmlPropertyPrivate::setSignalExpression(property, 0); - return true; - } - - if (m_statesDelegate) { - m_statesDelegate->resetBindingForInvalidProperty(object, propertyName); - return true; - } - - return false; - } - // object or context null. - return false; -} - -bool QQmlEngineDebugService::setMethodBody(int objectId, const QString &method, const QString &body) -{ - QObject *object = objectForId(objectId); - QQmlContext *context = qmlContext(object); - if (!object || !context || !context->engine()) - return false; - QQmlContextData *contextData = QQmlContextData::get(context); - if (!contextData) - return false; - - QQmlPropertyData dummy; - QQmlPropertyData *prop = - QQmlPropertyCache::property(context->engine(), object, method, contextData, dummy); - - if (!prop || !prop->isVMEFunction()) - return false; - - QMetaMethod metaMethod = object->metaObject()->method(prop->coreIndex); - QList<QByteArray> paramNames = metaMethod.parameterNames(); - - QString paramStr; - for (int ii = 0; ii < paramNames.count(); ++ii) { - if (ii != 0) paramStr.append(QLatin1Char(',')); - paramStr.append(QString::fromUtf8(paramNames.at(ii))); - } - - QString jsfunction = QLatin1String("(function ") + method + QLatin1Char('(') + paramStr + - QLatin1String(") {"); - jsfunction += body; - jsfunction += QLatin1String("\n})"); - - QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(object); - Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this - - int lineNumber = vmeMetaObject->vmeMethodLineNumber(prop->coreIndex); - QV4::ExecutionEngine *v4 = QV8Engine::getV4(qmlEngine(object)->handle()); - QV4::Scope scope(v4); - QV4::ScopedValue v(scope, QQmlExpressionPrivate::evalFunction(contextData, object, jsfunction, contextData->urlString(), lineNumber)); - vmeMetaObject->setVmeMethod(prop->coreIndex, v); - return true; -} - -void QQmlEngineDebugService::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value) -{ - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); - - rs << QByteArray("UPDATE_WATCH") << id << objectId << QByteArray(property.name()) << valueContents(value); - - sendMessage(reply); -} - -void QQmlEngineDebugService::engineAboutToBeAdded(QQmlEngine *engine) -{ - Q_ASSERT(engine); - Q_ASSERT(!m_engines.contains(engine)); - - m_engines.append(engine); - emit attachedToEngine(engine); -} - -void QQmlEngineDebugService::engineAboutToBeRemoved(QQmlEngine *engine) -{ - Q_ASSERT(engine); - Q_ASSERT(m_engines.contains(engine)); - - m_engines.removeAll(engine); - emit detachedFromEngine(engine); -} - -void QQmlEngineDebugService::objectCreated(QQmlEngine *engine, QObject *object) -{ - Q_ASSERT(engine); - Q_ASSERT(m_engines.contains(engine)); - - int engineId = QQmlDebugService::idForObject(engine); - int objectId = QQmlDebugService::idForObject(object); - int parentId = QQmlDebugService::idForObject(object->parent()); - - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); - - //unique queryId -1 - rs << QByteArray("OBJECT_CREATED") << -1 << engineId << objectId << parentId; - sendMessage(reply); -} - -void QQmlEngineDebugService::setStatesDelegate(QQmlDebugStatesDelegate *delegate) -{ - m_statesDelegate = delegate; -} - -QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmlenginedebugservice_p.h b/src/qml/debugger/qqmlenginedebugservice_p.h deleted file mode 100644 index 0a824b132f..0000000000 --- a/src/qml/debugger/qqmlenginedebugservice_p.h +++ /dev/null @@ -1,132 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLENGINEDEBUGSERVICE_P_H -#define QQMLENGINEDEBUGSERVICE_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. -// - -#include <private/qqmldebugservice_p.h> - -#include <QtCore/qurl.h> -#include <QtCore/qvariant.h> -#include <QtCore/QPointer> - -QT_BEGIN_NAMESPACE - -class QQmlEngine; -class QQmlContext; -class QQmlWatcher; -class QDataStream; -class QQmlDebugStatesDelegate; - -class Q_QML_PRIVATE_EXPORT QQmlEngineDebugService : public QQmlDebugService -{ - Q_OBJECT -public: - QQmlEngineDebugService(QObject * = 0); - ~QQmlEngineDebugService(); - - struct QQmlObjectData { - QUrl url; - int lineNumber; - int columnNumber; - QString idString; - QString objectName; - QString objectType; - int objectId; - int contextId; - int parentId; - }; - - struct QQmlObjectProperty { - enum Type { Unknown, Basic, Object, List, SignalProperty, Variant }; - Type type; - QString name; - QVariant value; - QString valueTypeName; - QString binding; - bool hasNotifySignal; - }; - - void engineAboutToBeAdded(QQmlEngine *); - void engineAboutToBeRemoved(QQmlEngine *); - void objectCreated(QQmlEngine *, QObject *); - - void setStatesDelegate(QQmlDebugStatesDelegate *); - - static QQmlEngineDebugService *instance(); - -protected: - virtual void messageReceived(const QByteArray &); - -private Q_SLOTS: - void processMessage(const QByteArray &msg); - void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value); - -private: - void prepareDeferredObjects(QObject *); - void buildObjectList(QDataStream &, QQmlContext *, - const QList<QPointer<QObject> > &instances); - void buildObjectDump(QDataStream &, QObject *, bool, bool); - void buildStatesList(bool cleanList, const QList<QPointer<QObject> > &instances); - QQmlObjectData objectData(QObject *); - QQmlObjectProperty propertyData(QObject *, int); - QVariant valueContents(QVariant defaultValue) const; - bool setBinding(int objectId, const QString &propertyName, const QVariant &expression, bool isLiteralValue, QString filename = QString(), int line = -1, int column = 0); - bool resetBinding(int objectId, const QString &propertyName); - bool setMethodBody(int objectId, const QString &method, const QString &body); - void storeObjectIds(QObject *co); - - QList<QQmlEngine *> m_engines; - QQmlWatcher *m_watch; - QQmlDebugStatesDelegate *m_statesDelegate; -}; -Q_QML_PRIVATE_EXPORT QDataStream &operator<<(QDataStream &, const QQmlEngineDebugService::QQmlObjectData &); -Q_QML_PRIVATE_EXPORT QDataStream &operator>>(QDataStream &, QQmlEngineDebugService::QQmlObjectData &); -Q_QML_PRIVATE_EXPORT QDataStream &operator<<(QDataStream &, const QQmlEngineDebugService::QQmlObjectProperty &); -Q_QML_PRIVATE_EXPORT QDataStream &operator>>(QDataStream &, QQmlEngineDebugService::QQmlObjectProperty &); - -QT_END_NAMESPACE - -#endif // QQMLENGINEDEBUGSERVICE_P_H - diff --git a/src/qml/debugger/qqmlinspectorinterface_p.h b/src/qml/debugger/qqmlinspectorinterface_p.h deleted file mode 100644 index 9b29d383c7..0000000000 --- a/src/qml/debugger/qqmlinspectorinterface_p.h +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLINSPECTORINTERFACE_H -#define QQMLINSPECTORINTERFACE_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. -// - -#include <QtQml/qtqmlglobal.h> -#include <private/qqmlglobal_p.h> - -QT_BEGIN_NAMESPACE - - -class Q_QML_PRIVATE_EXPORT QQmlInspectorInterface -{ -public: - QQmlInspectorInterface() {} - virtual ~QQmlInspectorInterface() {} - - virtual bool canHandleView(QObject *view) = 0; - - virtual void activate(QObject *view) = 0; - virtual void deactivate() = 0; - - virtual void clientMessage(const QByteArray &message) = 0; -}; - -#define QQmlInspectorInterface_iid "org.qt-project.Qt.QQmlInspectorInterface" - -Q_DECLARE_INTERFACE(QQmlInspectorInterface, QQmlInspectorInterface_iid) - -QT_END_NAMESPACE - -#endif // QQMLINSPECTORINTERFACE_H diff --git a/src/qml/debugger/qqmlinspectorservice.cpp b/src/qml/debugger/qqmlinspectorservice.cpp deleted file mode 100644 index 5a8c4487d9..0000000000 --- a/src/qml/debugger/qqmlinspectorservice.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlinspectorservice_p.h" -#include "qqmlinspectorinterface_p.h" -#include "qqmldebugserver_p.h" - -#include <private/qqmlglobal_p.h> - -#include <QtCore/QCoreApplication> -#include <QtCore/QDebug> -#include <QtCore/QDir> -#include <QtCore/QPluginLoader> - -// print detailed information about loading of plugins -DEFINE_BOOL_CONFIG_OPTION(qmlDebugVerbose, QML_DEBUGGER_VERBOSE) - -QT_BEGIN_NAMESPACE - -Q_GLOBAL_STATIC(QQmlInspectorService, serviceInstance) - -QQmlInspectorService::QQmlInspectorService() - : QQmlDebugService(QStringLiteral("QmlInspector"), 1) - , m_currentInspectorPlugin(0) -{ - registerService(); -} - -QQmlInspectorService *QQmlInspectorService::instance() -{ - return serviceInstance(); -} - -void QQmlInspectorService::addView(QObject *view) -{ - m_views.append(view); - updateState(); -} - -void QQmlInspectorService::removeView(QObject *view) -{ - m_views.removeAll(view); - updateState(); -} - -void QQmlInspectorService::sendMessage(const QByteArray &message) -{ - if (state() != Enabled) - return; - - QQmlDebugService::sendMessage(message); -} - -void QQmlInspectorService::stateChanged(State /*state*/) -{ - QMetaObject::invokeMethod(this, "updateState", Qt::QueuedConnection); -} - -void QQmlInspectorService::updateState() -{ - if (m_views.isEmpty()) { - if (m_currentInspectorPlugin) { - m_currentInspectorPlugin->deactivate(); - m_currentInspectorPlugin = 0; - } - return; - } - - if (state() == Enabled) { - if (m_inspectorPlugins.isEmpty()) - loadInspectorPlugins(); - - if (m_inspectorPlugins.isEmpty()) { - qWarning() << "QQmlInspector: No plugins found."; - QQmlDebugServer::instance()->removeService(this); - return; - } - - m_currentInspectorPlugin = 0; - foreach (QQmlInspectorInterface *inspector, m_inspectorPlugins) { - if (inspector->canHandleView(m_views.first())) { - m_currentInspectorPlugin = inspector; - break; - } - } - - if (!m_currentInspectorPlugin) { - qWarning() << "QQmlInspector: No plugin available for view '" << m_views.first()->metaObject()->className() << "'."; - return; - } - m_currentInspectorPlugin->activate(m_views.first()); - } else { - if (m_currentInspectorPlugin) { - m_currentInspectorPlugin->deactivate(); - m_currentInspectorPlugin = 0; - } - } -} - -void QQmlInspectorService::messageReceived(const QByteArray &message) -{ - QMetaObject::invokeMethod(this, "processMessage", Qt::QueuedConnection, Q_ARG(QByteArray, message)); -} - -void QQmlInspectorService::processMessage(const QByteArray &message) -{ - if (m_currentInspectorPlugin) - m_currentInspectorPlugin->clientMessage(message); -} - -void QQmlInspectorService::loadInspectorPlugins() -{ - QStringList pluginCandidates; - const QStringList paths = QCoreApplication::libraryPaths(); - foreach (const QString &libPath, paths) { - const QDir dir(libPath + QLatin1String("/qmltooling")); - if (dir.exists()) - foreach (const QString &pluginPath, dir.entryList(QDir::Files)) - pluginCandidates << dir.absoluteFilePath(pluginPath); - } - - foreach (const QString &pluginPath, pluginCandidates) { - if (pluginPath.contains(QLatin1String("qmldbg_tcp"))) - continue; - if (qmlDebugVerbose()) - qDebug() << "QQmlInspector: Trying to load plugin " << pluginPath << "..."; - - QPluginLoader loader(pluginPath); - if (!loader.load()) { - if (qmlDebugVerbose()) - qDebug() << "QQmlInspector: Error while loading: " << loader.errorString(); - - continue; - } - - QQmlInspectorInterface *inspector = - qobject_cast<QQmlInspectorInterface*>(loader.instance()); - if (inspector) { - if (qmlDebugVerbose()) - qDebug() << "QQmlInspector: Plugin successfully loaded."; - m_inspectorPlugins << inspector; - } else { - if (qmlDebugVerbose()) - qDebug() << "QQmlInspector: Plugin does not implement interface QQmlInspectorInterface."; - - loader.unload(); - } - } -} - -QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmlprofiler.cpp b/src/qml/debugger/qqmlprofiler.cpp index b35da8a714..a6423d769a 100644 --- a/src/qml/debugger/qqmlprofiler.cpp +++ b/src/qml/debugger/qqmlprofiler.cpp @@ -32,88 +32,13 @@ ****************************************************************************/ #include "qqmlprofiler_p.h" -#include "qqmlprofilerservice_p.h" #include "qqmldebugservice_p.h" QT_BEGIN_NAMESPACE -// convert to QByteArrays that can be sent to the debug client -// use of QDataStream can skew results -// (see tst_qqmldebugtrace::trace() benchmark) -void QQmlProfilerData::toByteArrays(QList<QByteArray> &messages) const -{ - QByteArray data; - Q_ASSERT_X(((messageType | detailType) & (1 << 31)) == 0, Q_FUNC_INFO, "You can use at most 31 message types and 31 detail types."); - for (uint decodedMessageType = 0; (messageType >> decodedMessageType) != 0; ++decodedMessageType) { - if ((messageType & (1 << decodedMessageType)) == 0) - continue; - - for (uint decodedDetailType = 0; (detailType >> decodedDetailType) != 0; ++decodedDetailType) { - if ((detailType & (1 << decodedDetailType)) == 0) - continue; - - //### using QDataStream is relatively expensive - QQmlDebugStream ds(&data, QIODevice::WriteOnly); - ds << time << decodedMessageType << decodedDetailType; - - switch (decodedMessageType) { - case QQmlProfilerDefinitions::RangeStart: - if (decodedDetailType == (int)QQmlProfilerDefinitions::Binding) - ds << QQmlProfilerDefinitions::QmlBinding; - break; - case QQmlProfilerDefinitions::RangeData: - ds << detailString; - break; - case QQmlProfilerDefinitions::RangeLocation: - ds << (detailUrl.isEmpty() ? detailString : detailUrl.toString()) << x << y; - break; - case QQmlProfilerDefinitions::RangeEnd: break; - default: - Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type."); - break; - } - messages << data; - data.clear(); - } - } -} - -QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine) : - QQmlAbstractProfilerAdapter(service) -{ - engine->enableProfiler(); - connect(this, SIGNAL(profilingEnabled(quint64)), engine->profiler, SLOT(startProfiling(quint64))); - connect(this, SIGNAL(profilingEnabledWhileWaiting(quint64)), - engine->profiler, SLOT(startProfiling(quint64)), Qt::DirectConnection); - connect(this, SIGNAL(profilingDisabled()), engine->profiler, SLOT(stopProfiling())); - connect(this, SIGNAL(profilingDisabledWhileWaiting()), - engine->profiler, SLOT(stopProfiling()), Qt::DirectConnection); - connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData())); - connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), - engine->profiler, SLOT(setTimer(QElapsedTimer))); - connect(engine->profiler, SIGNAL(dataReady(QList<QQmlProfilerData>)), - this, SLOT(receiveData(QList<QQmlProfilerData>))); -} - -qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) -{ - while (!data.empty() && data.front().time <= until) { - data.front().toByteArrays(messages); - data.pop_front(); - } - return data.empty() ? -1 : data.front().time; -} - -void QQmlProfilerAdapter::receiveData(const QList<QQmlProfilerData> &new_data) -{ - data = new_data; - service->dataReady(this); -} - - QQmlProfiler::QQmlProfiler() : featuresEnabled(0) { - static int metatype = qRegisterMetaType<QList<QQmlProfilerData> >(); + static int metatype = qRegisterMetaType<QVector<QQmlProfilerData> >(); Q_UNUSED(metatype); m_timer.start(); } @@ -127,16 +52,12 @@ void QQmlProfiler::stopProfiling() { featuresEnabled = false; reportData(); - m_data.clear(); } void QQmlProfiler::reportData() { - QList<QQmlProfilerData> result; - result.reserve(m_data.size()); - for (int i = 0; i < m_data.size(); ++i) - result.append(m_data[i]); - emit dataReady(result); + emit dataReady(m_data); + m_data.clear(); } QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h index 5c994b112f..3c8337c969 100644 --- a/src/qml/debugger/qqmlprofiler_p.h +++ b/src/qml/debugger/qqmlprofiler_p.h @@ -68,8 +68,9 @@ QT_BEGIN_NAMESPACE // This struct is somewhat dangerous to use: // The messageType is a bit field. You can pack multiple messages into // one object, e.g. RangeStart and RangeLocation. Each one will be read -// independently by toByteArrays. Thus you can only pack messages if their data -// doesn't overlap. It's up to you to figure that out. +// independently when converting to QByteArrays. Thus you can only pack +// messages if their data doesn't overlap. It's up to you to figure that +// out. struct Q_AUTOTEST_EXPORT QQmlProfilerData { QQmlProfilerData() {} @@ -103,8 +104,6 @@ struct Q_AUTOTEST_EXPORT QQmlProfilerData int x; //used by RangeLocation int y; //used by RangeLocation - - void toByteArrays(QList<QByteArray> &messages) const; }; Q_DECLARE_TYPEINFO(QQmlProfilerData, Q_MOVABLE_TYPE); @@ -171,24 +170,11 @@ public slots: void setTimer(const QElapsedTimer &timer) { m_timer = timer; } signals: - void dataReady(const QList<QQmlProfilerData> &); + void dataReady(const QVector<QQmlProfilerData> &); protected: QElapsedTimer m_timer; - QVarLengthArray<QQmlProfilerData> m_data; -}; - -class QQmlProfilerAdapter : public QQmlAbstractProfilerAdapter { - Q_OBJECT -public: - QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine); - qint64 sendMessages(qint64 until, QList<QByteArray> &messages); - -public slots: - void receiveData(const QList<QQmlProfilerData> &new_data); - -private: - QList<QQmlProfilerData> data; + QVector<QQmlProfilerData> m_data; }; // @@ -332,6 +318,6 @@ private: }; QT_END_NAMESPACE -Q_DECLARE_METATYPE(QList<QQmlProfilerData>) +Q_DECLARE_METATYPE(QVector<QQmlProfilerData>) #endif // QQMLPROFILER_P_H diff --git a/src/qml/debugger/qqmlprofilerservice.cpp b/src/qml/debugger/qqmlprofilerservice.cpp deleted file mode 100644 index 85556836e6..0000000000 --- a/src/qml/debugger/qqmlprofilerservice.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlprofilerservice_p.h" -#include "qqmldebugserver_p.h" -#include "qv4profileradapter_p.h" -#include "qqmlprofiler_p.h" -#include <private/qqmlengine_p.h> - -#include <QtCore/qdatastream.h> -#include <QtCore/qurl.h> -#include <QtCore/qtimer.h> -#include <QtCore/qthread.h> -#include <QtCore/qcoreapplication.h> - -QT_BEGIN_NAMESPACE - -Q_GLOBAL_STATIC(QQmlProfilerService, profilerInstance) - -QQmlProfilerService::QQmlProfilerService() - : QQmlConfigurableDebugService(QStringLiteral("CanvasFrameRate"), 1) -{ - m_timer.start(); - - QMutexLocker lock(configMutex()); - // If there is no debug server it doesn't matter as we'll never get enabled anyway. - if (QQmlDebugServer::instance() != 0) - moveToThread(QQmlDebugServer::instance()->thread()); -} - -QQmlProfilerService::~QQmlProfilerService() -{ - // No need to lock here. If any engine or global profiler is still trying to register at this - // point we have a nasty bug anyway. - qDeleteAll(m_engineProfilers.values()); - qDeleteAll(m_globalProfilers); -} - -void QQmlProfilerService::dataReady(QQmlAbstractProfilerAdapter *profiler) -{ - QMutexLocker lock(configMutex()); - bool dataComplete = true; - for (QMultiMap<qint64, QQmlAbstractProfilerAdapter *>::iterator i(m_startTimes.begin()); i != m_startTimes.end();) { - if (i.value() == profiler) { - m_startTimes.erase(i++); - } else { - if (i.key() == -1) - dataComplete = false; - ++i; - } - } - m_startTimes.insert(0, profiler); - if (dataComplete) { - QList<QQmlEngine *> enginesToRelease; - foreach (QQmlEngine *engine, m_stoppingEngines) { - foreach (QQmlAbstractProfilerAdapter *engineProfiler, m_engineProfilers.values(engine)) { - if (m_startTimes.values().contains(engineProfiler)) { - enginesToRelease.append(engine); - break; - } - } - } - sendMessages(); - foreach (QQmlEngine *engine, enginesToRelease) { - m_stoppingEngines.removeOne(engine); - emit detachedFromEngine(engine); - } - } -} - -QQmlProfilerService *QQmlProfilerService::instance() -{ - // just make sure that the service is properly registered - return profilerInstance(); -} - -void QQmlProfilerService::engineAboutToBeAdded(QQmlEngine *engine) -{ - Q_ASSERT_X(QThread::currentThread() != thread(), Q_FUNC_INFO, "QML profilers have to be added from the engine thread"); - - QMutexLocker lock(configMutex()); - QQmlProfilerAdapter *qmlAdapter = new QQmlProfilerAdapter(this, QQmlEnginePrivate::get(engine)); - QV4ProfilerAdapter *v4Adapter = new QV4ProfilerAdapter(this, QV8Engine::getV4(engine->handle())); - addEngineProfiler(qmlAdapter, engine); - addEngineProfiler(v4Adapter, engine); - QQmlConfigurableDebugService::engineAboutToBeAdded(engine); -} - -void QQmlProfilerService::engineAdded(QQmlEngine *engine) -{ - Q_ASSERT_X(QThread::currentThread() != thread(), Q_FUNC_INFO, "QML profilers have to be added from the engine thread"); - - QMutexLocker lock(configMutex()); - foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers.values(engine)) - profiler->stopWaiting(); -} - -void QQmlProfilerService::engineAboutToBeRemoved(QQmlEngine *engine) -{ - Q_ASSERT_X(QThread::currentThread() != thread(), Q_FUNC_INFO, "QML profilers have to be removed from the engine thread"); - - QMutexLocker lock(configMutex()); - bool isRunning = false; - foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers.values(engine)) { - if (profiler->isRunning()) - isRunning = true; - profiler->startWaiting(); - } - if (isRunning) { - m_stoppingEngines.append(engine); - stopProfiling(engine); - } else { - emit detachedFromEngine(engine); - } -} - -void QQmlProfilerService::engineRemoved(QQmlEngine *engine) -{ - Q_ASSERT_X(QThread::currentThread() != thread(), Q_FUNC_INFO, "QML profilers have to be removed from the engine thread"); - - QMutexLocker lock(configMutex()); - foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers.values(engine)) { - removeProfilerFromStartTimes(profiler); - delete profiler; - } - m_engineProfilers.remove(engine); -} - -void QQmlProfilerService::addEngineProfiler(QQmlAbstractProfilerAdapter *profiler, QQmlEngine *engine) -{ - profiler->moveToThread(thread()); - profiler->synchronize(m_timer); - m_engineProfilers.insert(engine, profiler); -} - -void QQmlProfilerService::addGlobalProfiler(QQmlAbstractProfilerAdapter *profiler) -{ - QMutexLocker lock(configMutex()); - profiler->synchronize(m_timer); - m_globalProfilers.append(profiler); - // Global profiler, not connected to a specific engine. - // Global profilers are started whenever any engine profiler is started and stopped when - // all engine profilers are stopped. - quint64 features = 0; - foreach (QQmlAbstractProfilerAdapter *engineProfiler, m_engineProfilers) - features |= engineProfiler->features(); - - if (features != 0) - profiler->startProfiling(features); -} - -void QQmlProfilerService::removeGlobalProfiler(QQmlAbstractProfilerAdapter *profiler) -{ - QMutexLocker lock(configMutex()); - removeProfilerFromStartTimes(profiler); - m_globalProfilers.removeOne(profiler); - delete profiler; -} - -void QQmlProfilerService::removeProfilerFromStartTimes(const QQmlAbstractProfilerAdapter *profiler) -{ - for (QMultiMap<qint64, QQmlAbstractProfilerAdapter *>::iterator i(m_startTimes.begin()); - i != m_startTimes.end();) { - if (i.value() == profiler) { - m_startTimes.erase(i++); - break; - } else { - ++i; - } - } -} - -/*! - * Start profiling the given \a engine. If \a engine is 0, start all engine profilers that aren't - * currently running. - * - * If any engine profiler is started like that also start all global profilers. - */ -void QQmlProfilerService::startProfiling(QQmlEngine *engine, quint64 features) -{ - QMutexLocker lock(configMutex()); - - QByteArray message; - QQmlDebugStream d(&message, QIODevice::WriteOnly); - - d << m_timer.nsecsElapsed() << (int)Event << (int)StartTrace; - bool startedAny = false; - if (engine != 0) { - foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers.values(engine)) { - if (!profiler->isRunning()) { - profiler->startProfiling(features); - startedAny = true; - } - } - if (startedAny) - d << idForObject(engine); - } else { - QSet<QQmlEngine *> engines; - for (QMultiHash<QQmlEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin()); - i != m_engineProfilers.end(); ++i) { - if (!i.value()->isRunning()) { - engines << i.key(); - i.value()->startProfiling(features); - startedAny = true; - } - } - foreach (QQmlEngine *profiledEngine, engines) - d << idForObject(profiledEngine); - } - - if (startedAny) { - foreach (QQmlAbstractProfilerAdapter *profiler, m_globalProfilers) { - if (!profiler->isRunning()) - profiler->startProfiling(features); - } - } - - QQmlDebugService::sendMessage(message); -} - -/*! - * Stop profiling the given \a engine. If \a engine is 0, stop all currently running engine - * profilers. - * - * If afterwards no more engine profilers are running, also stop all global profilers. Otherwise - * only make them report their data. - */ -void QQmlProfilerService::stopProfiling(QQmlEngine *engine) -{ - QMutexLocker lock(configMutex()); - QList<QQmlAbstractProfilerAdapter *> stopping; - QList<QQmlAbstractProfilerAdapter *> reporting; - - bool stillRunning = false; - for (QMultiHash<QQmlEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin()); - i != m_engineProfilers.end(); ++i) { - if (i.value()->isRunning()) { - if (engine == 0 || i.key() == engine) { - m_startTimes.insert(-1, i.value()); - stopping << i.value(); - } else { - stillRunning = true; - } - } - } - - foreach (QQmlAbstractProfilerAdapter *profiler, m_globalProfilers) { - if (!profiler->isRunning()) - continue; - m_startTimes.insert(-1, profiler); - if (stillRunning) { - reporting << profiler; - } else { - stopping << profiler; - } - } - - foreach (QQmlAbstractProfilerAdapter *profiler, reporting) - profiler->reportData(); - - foreach (QQmlAbstractProfilerAdapter *profiler, stopping) - profiler->stopProfiling(); -} - -/* - Send the queued up messages. -*/ -void QQmlProfilerService::sendMessages() -{ - QList<QByteArray> messages; - - QByteArray data; - QQmlDebugStream traceEnd(&data, QIODevice::WriteOnly); - traceEnd << m_timer.nsecsElapsed() << (int)Event << (int)EndTrace; - - QSet<QQmlEngine *> seen; - foreach (QQmlAbstractProfilerAdapter *profiler, m_startTimes) { - for (QMultiHash<QQmlEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin()); - i != m_engineProfilers.end(); ++i) { - if (i.value() == profiler && !seen.contains(i.key())) { - seen << i.key(); - traceEnd << idForObject(i.key()); - } - } - } - - while (!m_startTimes.empty()) { - QQmlAbstractProfilerAdapter *first = m_startTimes.begin().value(); - m_startTimes.erase(m_startTimes.begin()); - if (!m_startTimes.empty()) { - qint64 next = first->sendMessages(m_startTimes.begin().key(), messages); - if (next != -1) - m_startTimes.insert(next, first); - } else { - first->sendMessages(std::numeric_limits<qint64>::max(), messages); - } - } - - //indicate completion - messages << data; - data.clear(); - - QQmlDebugStream ds(&data, QIODevice::WriteOnly); - ds << (qint64)-1 << (int)Complete; - messages << data; - - QQmlDebugService::sendMessages(messages); -} - -void QQmlProfilerService::stateAboutToBeChanged(QQmlDebugService::State newState) -{ - QMutexLocker lock(configMutex()); - - if (state() == newState) - return; - - // Stop all profiling and send the data before we get disabled. - if (newState != Enabled) { - foreach (QQmlEngine *engine, m_engineProfilers.keys()) - stopProfiling(engine); - } -} - -void QQmlProfilerService::messageReceived(const QByteArray &message) -{ - QMutexLocker lock(configMutex()); - - QByteArray rwData = message; - QQmlDebugStream stream(&rwData, QIODevice::ReadOnly); - - int engineId = -1; - quint64 features = std::numeric_limits<quint64>::max(); - bool enabled; - stream >> enabled; - if (!stream.atEnd()) - stream >> engineId; - if (!stream.atEnd()) - stream >> features; - - // If engineId == -1 objectForId() and then the cast will return 0. - if (enabled) - startProfiling(qobject_cast<QQmlEngine *>(objectForId(engineId)), features); - else - stopProfiling(qobject_cast<QQmlEngine *>(objectForId(engineId))); - - stopWaiting(); -} - -QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h deleted file mode 100644 index 978d8413a7..0000000000 --- a/src/qml/debugger/qqmlprofilerservice_p.h +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLPROFILERSERVICE_P_H -#define QQMLPROFILERSERVICE_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. -// - -#include "qqmlconfigurabledebugservice_p.h" -#include "qqmlprofilerdefinitions_p.h" -#include "qqmlabstractprofileradapter_p.h" - -#include <private/qqmlboundsignal_p.h> - -#include <QtCore/qelapsedtimer.h> -#include <QtCore/qmetaobject.h> -#include <QtCore/qmutex.h> -#include <QtCore/qvector.h> -#include <QtCore/qstringbuilder.h> -#include <QtCore/qwaitcondition.h> - -#include <limits> - -QT_BEGIN_NAMESPACE - -class QUrl; -class QQmlEngine; - - -class Q_QML_PRIVATE_EXPORT QQmlProfilerService : public QQmlConfigurableDebugService, public QQmlProfilerDefinitions -{ - Q_OBJECT -public: - - static QQmlProfilerService *instance(); - void engineAboutToBeAdded(QQmlEngine *engine); - void engineAboutToBeRemoved(QQmlEngine *engine); - void engineAdded(QQmlEngine *engine); - void engineRemoved(QQmlEngine *engine); - - void addGlobalProfiler(QQmlAbstractProfilerAdapter *profiler); - void removeGlobalProfiler(QQmlAbstractProfilerAdapter *profiler); - - void startProfiling(QQmlEngine *engine, quint64 features = std::numeric_limits<quint64>::max()); - void stopProfiling(QQmlEngine *engine); - - QQmlProfilerService(); - ~QQmlProfilerService(); - - void dataReady(QQmlAbstractProfilerAdapter *profiler); - -protected: - virtual void stateAboutToBeChanged(State state); - virtual void messageReceived(const QByteArray &); - -private: - - void sendMessages(); - void addEngineProfiler(QQmlAbstractProfilerAdapter *profiler, QQmlEngine *engine); - void removeProfilerFromStartTimes(const QQmlAbstractProfilerAdapter *profiler); - - QElapsedTimer m_timer; - - QList<QQmlAbstractProfilerAdapter *> m_globalProfilers; - QMultiHash<QQmlEngine *, QQmlAbstractProfilerAdapter *> m_engineProfilers; - QList<QQmlEngine *> m_stoppingEngines; - QMultiMap<qint64, QQmlAbstractProfilerAdapter *> m_startTimes; -}; - -QT_END_NAMESPACE - -#endif // QQMLPROFILERSERVICE_P_H - diff --git a/src/qml/debugger/qv4debugservice.cpp b/src/qml/debugger/qv4debugservice.cpp deleted file mode 100644 index cefb29e031..0000000000 --- a/src/qml/debugger/qv4debugservice.cpp +++ /dev/null @@ -1,1265 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qv4debugservice_p.h" -#include "qqmlconfigurabledebugservice_p_p.h" -#include "qqmlengine.h" -#include "qv4debugging_p.h" -#include "qv4engine_p.h" -#include "qv4function_p.h" -#include "qqmldebugserver_p.h" - -#include <private/qv8engine_p.h> - -#include <QtCore/QJsonArray> -#include <QtCore/QJsonDocument> -#include <QtCore/QJsonObject> -#include <QtCore/QJsonValue> - -const char *V4_CONNECT = "connect"; -const char *V4_DISCONNECT = "disconnect"; -const char *V4_BREAK_ON_SIGNAL = "breakonsignal"; -const char *V4_ADD_BREAKPOINT = "addBreakpoint"; -const char *V4_REMOVE_BREAKPOINT = "removeBreakpoint"; -const char *V4_PAUSE = "interrupt"; -const char *V4_ALL = "all"; -const char *V4_BREAK = "break"; - -const char *V4_FILENAME = "filename"; -const char *V4_LINENUMBER = "linenumber"; - -#define NO_PROTOCOL_TRACING -#ifdef NO_PROTOCOL_TRACING -# define TRACE_PROTOCOL(x) -#else -#include <QtCore/QDebug> -# define TRACE_PROTOCOL(x) x -#endif - -QT_BEGIN_NAMESPACE - -Q_GLOBAL_STATIC(QV4DebugService, v4ServiceInstance) - -class QV4DebugServicePrivate; - -class QV4DebuggerAgent : public QV4::Debugging::DebuggerAgent -{ -public: - QV4DebuggerAgent(QV4DebugServicePrivate *debugServicePrivate) - : debugServicePrivate(debugServicePrivate) - {} - - QV4::Debugging::Debugger *firstDebugger() const - { - // Currently only 1 single engine is supported, so: - if (m_debuggers.isEmpty()) - return 0; - else - return m_debuggers.first(); - } - - bool isRunning() const - { - // Currently only 1 single engine is supported, so: - if (QV4::Debugging::Debugger *debugger = firstDebugger()) - return debugger->state() == QV4::Debugging::Debugger::Running; - else - return false; - } - -public slots: - virtual void debuggerPaused(QV4::Debugging::Debugger *debugger, QV4::Debugging::PauseReason reason); - virtual void sourcesCollected(QV4::Debugging::Debugger *debugger, QStringList sources, int requestSequenceNr); - -private: - QV4DebugServicePrivate *debugServicePrivate; -}; - -class V8CommandHandler; -class UnknownV8CommandHandler; - -class VariableCollector: public QV4::Debugging::Debugger::Collector -{ -public: - VariableCollector(QV4::ExecutionEngine *engine) - : Collector(engine) - , destination(0) - {} - - virtual ~VariableCollector() {} - - void collectScope(QJsonArray *dest, QV4::Debugging::Debugger *debugger, int frameNr, int scopeNr) - { - qSwap(destination, dest); - bool oldIsProp = isProperty(); - setIsProperty(true); - debugger->collectArgumentsInContext(this, frameNr, scopeNr); - debugger->collectLocalsInContext(this, frameNr, scopeNr); - setIsProperty(oldIsProp); - qSwap(destination, dest); - } - - void setDestination(QJsonArray *dest) - { destination = dest; } - - QJsonArray retrieveRefsToInclude() - { - QJsonArray result; - qSwap(refsToInclude, result); - return result; - } - - QJsonValue lookup(int handle, bool addRefs = true) - { - if (handle < 0) - handle = -handle; - - if (addRefs) - foreach (int ref, refsByHandle[handle]) - refsToInclude.append(lookup(ref, false)); - return refs[handle]; - } - - QJsonObject makeRef(int refId) - { - QJsonObject ref; - ref[QLatin1String("ref")] = refId; - return ref; - } - - QJsonObject addFunctionRef(const QString &name) - { - const int refId = newRefId(); - - QJsonObject func; - func[QLatin1String("handle")] = refId; - func[QLatin1String("type")] = QStringLiteral("function"); - func[QLatin1String("className")] = QStringLiteral("Function"); - func[QLatin1String("name")] = name; - insertRef(func, refId); - - return makeRef(refId); - } - - QJsonObject addScriptRef(const QString &name) - { - const int refId = newRefId(); - - QJsonObject func; - func[QLatin1String("handle")] = refId; - func[QLatin1String("type")] = QStringLiteral("script"); - func[QLatin1String("name")] = name; - insertRef(func, refId); - - return makeRef(refId); - } - - QJsonObject addObjectRef(QJsonObject obj, bool anonymous) - { - int ref = newRefId(); - - if (anonymous) - ref = -ref; - obj[QLatin1String("handle")] = ref; - obj[QLatin1String("type")] = QStringLiteral("object"); - insertRef(obj, ref); - QSet<int> used; - qSwap(usedRefs, used); - refsByHandle.insert(ref, used); - - return makeRef(ref); - } - -protected: - virtual void addUndefined(const QString &name) - { - QJsonObject o; - addHandle(name, o, QStringLiteral("undefined")); - } - - virtual void addNull(const QString &name) - { - QJsonObject o; - addHandle(name, o, QStringLiteral("null")); - } - - virtual void addBoolean(const QString &name, bool value) - { - QJsonObject o; - o[QLatin1String("value")] = value; - addHandle(name, o, QStringLiteral("boolean")); - } - - virtual void addString(const QString &name, const QString &value) - { - QJsonObject o; - o[QLatin1String("value")] = value; - addHandle(name, o, QStringLiteral("string")); - } - - virtual void addObject(const QString &name, const QV4::Value &value) - { - QV4::Scope scope(engine()); - QV4::ScopedObject obj(scope, value.asObject()); - - int ref = cachedObjectRef(obj); - if (ref != -1) { - addNameRefPair(name, ref); - } else { - int ref = newRefId(); - cacheObjectRef(obj, ref); - - QJsonArray properties, *prev = &properties; - QSet<int> used; - qSwap(usedRefs, used); - qSwap(destination, prev); - collect(obj); - qSwap(destination, prev); - qSwap(usedRefs, used); - - QJsonObject o; - o[QLatin1String("properties")] = properties; - addHandle(name, o, QStringLiteral("object"), ref); - refsByHandle.insert(ref, used); - } - } - - virtual void addInteger(const QString &name, int value) - { - QJsonObject o; - o[QLatin1String("value")] = value; - addHandle(name, o, QStringLiteral("number")); - } - - virtual void addDouble(const QString &name, double value) - { - QJsonObject o; - o[QLatin1String("value")] = value; - addHandle(name, o, QStringLiteral("number")); - } - -private: - int addHandle(const QString &name, QJsonObject object, const QString &type, int suppliedRef = -1) - { - Q_ASSERT(destination); - - object[QLatin1String("type")] = type; - - QJsonDocument tmp; - tmp.setObject(object); - QByteArray key = tmp.toJson(QJsonDocument::Compact); - - int ref; - if (suppliedRef == -1) { - ref = refCache.value(key, -1); - if (ref == -1) { - ref = newRefId(); - object[QLatin1String("handle")] = ref; - insertRef(object, ref); - refCache.insert(key, ref); - } - } else { - ref = suppliedRef; - object[QLatin1String("handle")] = ref; - insertRef(object, ref); - refCache.insert(key, ref); - } - - addNameRefPair(name, ref); - return ref; - } - - void addNameRefPair(const QString &name, int ref) - { - QJsonObject nameValuePair; - nameValuePair[QLatin1String("name")] = name; - if (isProperty()) { - nameValuePair[QLatin1String("ref")] = ref; - } else { - QJsonObject refObj; - refObj[QLatin1String("ref")] = ref; - nameValuePair[QLatin1String("value")] = refObj; - } - destination->append(nameValuePair); - usedRefs.insert(ref); - } - - int newRefId() - { - int ref = refs.count(); - refs.insert(ref, QJsonValue()); - return ref; - } - - void insertRef(const QJsonValue &value, int refId) - { - if (refId < 0) - refId = -refId; - - refs.insert(refId, value); - refsToInclude.append(value); - } - - void cacheObjectRef(QV4::Value obj, int ref) - { - objectRefs.insert(obj.val, ref); - } - - int cachedObjectRef(QV4::Value obj) const - { - return objectRefs.value(obj.val, -1); - } - -private: - QJsonArray refsToInclude; - QHash<int, QJsonValue> refs; - QHash<QByteArray, int> refCache; - QJsonArray *destination; - QSet<int> usedRefs; - QHash<int, QSet<int> > refsByHandle; - QHash<quint64, int> objectRefs; -}; - -class QV4DebugServicePrivate : public QQmlConfigurableDebugServicePrivate -{ - Q_DECLARE_PUBLIC(QV4DebugService) - -public: - QV4DebugServicePrivate(); - ~QV4DebugServicePrivate() { qDeleteAll(handlers.values()); } - - static QByteArray packMessage(const QByteArray &command, const QByteArray &message = QByteArray()) - { - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); - static const QByteArray cmd("V8DEBUG"); - rs << cmd << command << message; - return reply; - } - - void send(QJsonObject v8Payload) - { - v8Payload[QLatin1String("seq")] = sequence++; - QJsonDocument doc; - doc.setObject(v8Payload); -#ifdef NO_PROTOCOL_TRACING - QByteArray responseData = doc.toJson(QJsonDocument::Compact); -#else - QByteArray responseData = doc.toJson(QJsonDocument::Indented); -#endif - - TRACE_PROTOCOL(qDebug() << "sending response for:" << responseData << endl); - - q_func()->sendMessage(packMessage("v8message", responseData)); - } - - void processCommand(const QByteArray &command, const QByteArray &data); - - QV4DebuggerAgent debuggerAgent; - - QStringList breakOnSignals; - QMap<int, QV4::Debugging::Debugger *> debuggerMap; - static int debuggerIndex; - static int sequence; - const int version; - - V8CommandHandler *v8CommandHandler(const QString &command) const; - - void clearHandles(QV4::ExecutionEngine *engine) - { - theCollector.reset(new VariableCollector(engine)); - } - - QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr, - QV4::Debugging::Debugger *debugger) - { - QJsonObject frame; - frame[QLatin1String("index")] = frameNr; - frame[QLatin1String("debuggerFrame")] = false; - frame[QLatin1String("func")] = theCollector->addFunctionRef(stackFrame.function); - frame[QLatin1String("script")] = theCollector->addScriptRef(stackFrame.source); - frame[QLatin1String("line")] = stackFrame.line - 1; - if (stackFrame.column >= 0) - frame[QLatin1String("column")] = stackFrame.column; - - QJsonArray properties; - theCollector->setDestination(&properties); - if (debugger->collectThisInContext(theCollector.data(), frameNr)) { - QJsonObject obj; - obj[QLatin1String("properties")] = properties; - frame[QLatin1String("receiver")] = theCollector->addObjectRef(obj, false); - } - - QJsonArray scopes; - // Only type and index are used by Qt Creator, so we keep it easy: - QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = debugger->getScopeTypes(frameNr); - for (int i = 0, ei = scopeTypes.count(); i != ei; ++i) { - int type = encodeScopeType(scopeTypes[i]); - if (type == -1) - continue; - - QJsonObject scope; - scope[QLatin1String("index")] = i; - scope[QLatin1String("type")] = type; - scopes.push_back(scope); - } - frame[QLatin1String("scopes")] = scopes; - - return frame; - } - - int encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType) - { - switch (scopeType) { - case QV4::Heap::ExecutionContext::Type_GlobalContext: - return 0; - break; - case QV4::Heap::ExecutionContext::Type_CatchContext: - return 4; - break; - case QV4::Heap::ExecutionContext::Type_WithContext: - return 2; - break; - case QV4::Heap::ExecutionContext::Type_SimpleCallContext: - case QV4::Heap::ExecutionContext::Type_CallContext: - return 1; - break; - case QV4::Heap::ExecutionContext::Type_QmlContext: - default: - return -1; - } - } - - QJsonObject buildScope(int frameNr, int scopeNr, QV4::Debugging::Debugger *debugger) - { - QJsonObject scope; - - QJsonArray properties; - theCollector->collectScope(&properties, debugger, frameNr, scopeNr); - - QJsonObject anonymous; - anonymous[QLatin1String("properties")] = properties; - - QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = debugger->getScopeTypes(frameNr); - scope[QLatin1String("type")] = encodeScopeType(scopeTypes[scopeNr]); - scope[QLatin1String("index")] = scopeNr; - scope[QLatin1String("frameIndex")] = frameNr; - scope[QLatin1String("object")] = theCollector->addObjectRef(anonymous, true); - - return scope; - } - - QJsonValue lookup(int refId) const { return theCollector->lookup(refId); } - - QJsonArray buildRefs() - { - return theCollector->retrieveRefsToInclude(); - } - - VariableCollector *collector() const - { - return theCollector.data(); - } - - void selectFrame(int frameNr) - { theSelectedFrame = frameNr; } - - int selectedFrame() const - { return theSelectedFrame; } - -private: - QScopedPointer<VariableCollector> theCollector; - int theSelectedFrame; - - void addHandler(V8CommandHandler* handler); - QHash<QString, V8CommandHandler*> handlers; - QScopedPointer<UnknownV8CommandHandler> unknownV8CommandHandler; -}; - -int QV4DebugServicePrivate::debuggerIndex = 0; -int QV4DebugServicePrivate::sequence = 0; - -class V8CommandHandler -{ -public: - V8CommandHandler(const QString &command) - : cmd(command) - {} - - virtual ~V8CommandHandler() - {} - - QString command() const { return cmd; } - - void handle(const QJsonObject &request, QQmlDebugService *s, QV4DebugServicePrivate *p) - { - TRACE_PROTOCOL(qDebug() << "handling command" << command() << "..."); - - req = request; - seq = req.value(QStringLiteral("seq")); - debugService = s; - debugServicePrivate = p; - - handleRequest(); - if (!response.isEmpty()) { - response[QLatin1String("type")] = QStringLiteral("response"); - debugServicePrivate->send(response); - } - - debugServicePrivate = 0; - debugService = 0; - seq = QJsonValue(); - req = QJsonObject(); - response = QJsonObject(); - } - - virtual void handleRequest() = 0; - -protected: - void addCommand() { response.insert(QStringLiteral("command"), cmd); } - void addRequestSequence() { response.insert(QStringLiteral("request_seq"), seq); } - void addSuccess(bool success) { response.insert(QStringLiteral("success"), success); } - void addBody(const QJsonObject &body) - { - response.insert(QStringLiteral("body"), body); - } - - void addRunning() - { - response.insert(QStringLiteral("running"), debugServicePrivate->debuggerAgent.isRunning()); - } - - void addRefs() - { - response.insert(QStringLiteral("refs"), debugServicePrivate->buildRefs()); - } - - void createErrorResponse(const QString &msg) - { - QJsonValue command = req.value(QStringLiteral("command")); - response.insert(QStringLiteral("command"), command); - addRequestSequence(); - addSuccess(false); - addRunning(); - response.insert(QStringLiteral("message"), msg); - } - - int requestSequenceNr() const - { return seq.toInt(-1); } - -protected: - QString cmd; - QJsonObject req; - QJsonValue seq; - QQmlDebugService *debugService; - QV4DebugServicePrivate *debugServicePrivate; - QJsonObject response; -}; - -class UnknownV8CommandHandler: public V8CommandHandler -{ -public: - UnknownV8CommandHandler(): V8CommandHandler(QString()) {} - - virtual void handleRequest() - { - QString msg = QStringLiteral("unimplemented command \""); - msg += req.value(QStringLiteral("command")).toString(); - msg += QStringLiteral("\""); - createErrorResponse(msg); - } -}; - -namespace { -class V8VersionRequest: public V8CommandHandler -{ -public: - V8VersionRequest(): V8CommandHandler(QStringLiteral("version")) {} - - virtual void handleRequest() - { - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - QJsonObject body; - body.insert(QStringLiteral("V8Version"), - QLatin1String("this is not V8, this is V4 in Qt " QT_VERSION_STR)); - addBody(body); - } -}; - -class V8SetBreakPointRequest: public V8CommandHandler -{ -public: - V8SetBreakPointRequest(): V8CommandHandler(QStringLiteral("setbreakpoint")) {} - - virtual void handleRequest() - { - // decypher the payload: - QJsonObject args = req.value(QStringLiteral("arguments")).toObject(); - if (args.isEmpty()) - return; - - QString type = args.value(QStringLiteral("type")).toString(); - if (type != QStringLiteral("scriptRegExp")) { - createErrorResponse(QStringLiteral("breakpoint type \"%1\" is not implemented").arg(type)); - return; - } - - QString fileName = args.value(QStringLiteral("target")).toString(); - if (fileName.isEmpty()) { - createErrorResponse(QStringLiteral("breakpoint has no file name")); - return; - } - - int line = args.value(QStringLiteral("line")).toInt(-1); - if (line < 0) { - createErrorResponse(QStringLiteral("breakpoint has an invalid line number")); - return; - } - - bool enabled = args.value(QStringLiteral("enabled")).toBool(true); - QString condition = args.value(QStringLiteral("condition")).toString(); - - // set the break point: - int id = debugServicePrivate->debuggerAgent.addBreakPoint(fileName, line + 1, enabled, condition); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - QJsonObject body; - body.insert(QStringLiteral("type"), type); - body.insert(QStringLiteral("breakpoint"), id); - // It's undocumented, but V8 sends back an actual_locations array too. However, our - // Debugger currently doesn't tell us when it resolved a breakpoint, so we'll leave them - // pending until the breakpoint is hit for the first time. - addBody(body); - } -}; - -class V8ClearBreakPointRequest: public V8CommandHandler -{ -public: - V8ClearBreakPointRequest(): V8CommandHandler(QStringLiteral("clearbreakpoint")) {} - - virtual void handleRequest() - { - // decypher the payload: - QJsonObject args = req.value(QStringLiteral("arguments")).toObject(); - if (args.isEmpty()) - return; - - int id = args.value(QStringLiteral("breakpoint")).toInt(-1); - if (id < 0) { - createErrorResponse(QStringLiteral("breakpoint has an invalid number")); - return; - } - - // remove the break point: - debugServicePrivate->debuggerAgent.removeBreakPoint(id); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - QJsonObject body; - body.insert(QStringLiteral("type"), QStringLiteral("scriptRegExp")); - body.insert(QStringLiteral("breakpoint"), id); - addBody(body); - } -}; - -class V8BacktraceRequest: public V8CommandHandler -{ -public: - V8BacktraceRequest(): V8CommandHandler(QStringLiteral("backtrace")) {} - - virtual void handleRequest() - { - // decypher the payload: - - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - int fromFrame = arguments.value(QStringLiteral("fromFrame")).toInt(0); - int toFrame = arguments.value(QStringLiteral("toFrame")).toInt(fromFrame + 10); - // no idea what the bottom property is for, so we'll ignore it. - - QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger(); - - QJsonArray frameArray; - QVector<QV4::StackFrame> frames = debugger->stackTrace(toFrame); - for (int i = fromFrame; i < toFrame && i < frames.size(); ++i) - frameArray.push_back(debugServicePrivate->buildFrame(frames[i], i, debugger)); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - QJsonObject body; - if (frameArray.isEmpty()) { - body.insert(QStringLiteral("totalFrames"), 0); - } else { - body.insert(QStringLiteral("fromFrame"), fromFrame); - body.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size()); - body.insert(QStringLiteral("frames"), frameArray); - } - addBody(body); - addRefs(); - } -}; - -class V8FrameRequest: public V8CommandHandler -{ -public: - V8FrameRequest(): V8CommandHandler(QStringLiteral("frame")) {} - - virtual void handleRequest() - { - // decypher the payload: - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - const int frameNr = arguments.value(QStringLiteral("number")).toInt(debugServicePrivate->selectedFrame()); - - QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger(); - QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1); - if (frameNr < 0 || frameNr >= frames.size()) { - createErrorResponse(QStringLiteral("frame command has invalid frame number")); - return; - } - - debugServicePrivate->selectFrame(frameNr); - QJsonObject frame = debugServicePrivate->buildFrame(frames[frameNr], frameNr, debugger); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - addBody(frame); - addRefs(); - } -}; - -class V8ScopeRequest: public V8CommandHandler -{ -public: - V8ScopeRequest(): V8CommandHandler(QStringLiteral("scope")) {} - - virtual void handleRequest() - { - // decypher the payload: - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - const int frameNr = arguments.value(QStringLiteral("frameNumber")).toInt(debugServicePrivate->selectedFrame()); - const int scopeNr = arguments.value(QStringLiteral("number")).toInt(0); - - QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger(); - QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1); - if (frameNr < 0 || frameNr >= frames.size()) { - createErrorResponse(QStringLiteral("scope command has invalid frame number")); - return; - } - if (scopeNr < 0) { - createErrorResponse(QStringLiteral("scope command has invalid scope number")); - return; - } - - QJsonObject scope = debugServicePrivate->buildScope(frameNr, scopeNr, debugger); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - addBody(scope); - addRefs(); - } -}; - -class V8LookupRequest: public V8CommandHandler -{ -public: - V8LookupRequest(): V8CommandHandler(QStringLiteral("lookup")) {} - - virtual void handleRequest() - { - // decypher the payload: - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - QJsonArray handles = arguments.value(QStringLiteral("handles")).toArray(); - - QJsonObject body; - foreach (QJsonValue handle, handles) - body[QString::number(handle.toInt())] = debugServicePrivate->lookup(handle.toInt()); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - addBody(body); - addRefs(); - } -}; - -class V8ContinueRequest: public V8CommandHandler -{ -public: - V8ContinueRequest(): V8CommandHandler(QStringLiteral("continue")) {} - - virtual void handleRequest() - { - // decypher the payload: - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - - QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger(); - - if (arguments.empty()) { - debugger->resume(QV4::Debugging::Debugger::FullThrottle); - } else { - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - QString stepAction = arguments.value(QStringLiteral("stepaction")).toString(); - const int stepcount = arguments.value(QStringLiteral("stepcount")).toInt(1); - if (stepcount != 1) - qWarning() << "Step count other than 1 is not supported."; - - if (stepAction == QStringLiteral("in")) { - debugger->resume(QV4::Debugging::Debugger::StepIn); - } else if (stepAction == QStringLiteral("out")) { - debugger->resume(QV4::Debugging::Debugger::StepOut); - } else if (stepAction == QStringLiteral("next")) { - debugger->resume(QV4::Debugging::Debugger::StepOver); - } else { - createErrorResponse(QStringLiteral("continue command has invalid stepaction")); - return; - } - } - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - } -}; - -class V8DisconnectRequest: public V8CommandHandler -{ -public: - V8DisconnectRequest(): V8CommandHandler(QStringLiteral("disconnect")) {} - - virtual void handleRequest() - { - debugServicePrivate->debuggerAgent.removeAllBreakPoints(); - debugServicePrivate->debuggerAgent.resumeAll(); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - } -}; - -class V8SetExceptionBreakRequest: public V8CommandHandler -{ -public: - V8SetExceptionBreakRequest(): V8CommandHandler(QStringLiteral("setexceptionbreak")) {} - - virtual void handleRequest() - { - bool wasEnabled = debugServicePrivate->debuggerAgent.breakOnThrow(); - - //decypher the payload: - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - QString type = arguments.value(QStringLiteral("type")).toString(); - bool enabled = arguments.value(QStringLiteral("number")).toBool(!wasEnabled); - - if (type == QStringLiteral("all")) { - // that's fine - } else if (type == QStringLiteral("uncaught")) { - createErrorResponse(QStringLiteral("breaking only on uncaught exceptions is not supported yet")); - return; - } else { - createErrorResponse(QStringLiteral("invalid type for break on exception")); - return; - } - - // do it: - debugServicePrivate->debuggerAgent.setBreakOnThrow(enabled); - - QJsonObject body; - body[QLatin1String("type")] = type; - body[QLatin1String("enabled")] = debugServicePrivate->debuggerAgent.breakOnThrow(); - - // response: - addBody(body); - addRunning(); - addSuccess(true); - addRequestSequence(); - addCommand(); - } -}; - -class V8ScriptsRequest: public V8CommandHandler -{ -public: - V8ScriptsRequest(): V8CommandHandler(QStringLiteral("scripts")) {} - - virtual void handleRequest() - { - //decypher the payload: - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - int types = arguments.value(QStringLiteral("types")).toInt(-1); - if (types < 0 || types > 7) { - createErrorResponse(QStringLiteral("invalid types value in scripts command")); - return; - } else if (types != 4) { - createErrorResponse(QStringLiteral("unsupported types value in scripts command")); - return; - } - - // do it: - debugServicePrivate->debuggerAgent.firstDebugger()->gatherSources(requestSequenceNr()); - - // response will be send by - } -}; - -// Request: -// { -// "seq": 4, -// "type": "request", -// "command": "evaluate", -// "arguments": { -// "expression": "a", -// "frame": 0 -// } -// } -// -// Response: -// { -// "body": { -// "handle": 3, -// "type": "number", -// "value": 1 -// }, -// "command": "evaluate", -// "refs": [], -// "request_seq": 4, -// "running": false, -// "seq": 5, -// "success": true, -// "type": "response" -// } -// -// The "value" key in "body" is the result of evaluating the expression in the request. -class V8EvaluateRequest: public V8CommandHandler -{ -public: - V8EvaluateRequest(): V8CommandHandler(QStringLiteral("evaluate")) {} - - virtual void handleRequest() - { - //decypher the payload: - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - QString expression = arguments.value(QStringLiteral("expression")).toString(); - const int frame = arguments.value(QStringLiteral("frame")).toInt(0); - - QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger(); - Q_ASSERT(debugger->state() == QV4::Debugging::Debugger::Paused); - - VariableCollector *collector = debugServicePrivate->collector(); - QJsonArray dest; - collector->setDestination(&dest); - debugger->evaluateExpression(frame, expression, collector); - - const int ref = dest.at(0).toObject().value(QStringLiteral("value")).toObject() - .value(QStringLiteral("ref")).toInt(); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - addBody(collector->lookup(ref).toObject()); - addRefs(); - } -}; -} // anonymous namespace - -QV4DebugServicePrivate::QV4DebugServicePrivate() - : debuggerAgent(this) - , version(1) - , theSelectedFrame(0) - , unknownV8CommandHandler(new UnknownV8CommandHandler) -{ - addHandler(new V8VersionRequest); - addHandler(new V8SetBreakPointRequest); - addHandler(new V8ClearBreakPointRequest); - addHandler(new V8BacktraceRequest); - addHandler(new V8FrameRequest); - addHandler(new V8ScopeRequest); - addHandler(new V8LookupRequest); - addHandler(new V8ContinueRequest); - addHandler(new V8DisconnectRequest); - addHandler(new V8SetExceptionBreakRequest); - addHandler(new V8ScriptsRequest); - addHandler(new V8EvaluateRequest); -} - -void QV4DebugServicePrivate::addHandler(V8CommandHandler* handler) -{ - handlers[handler->command()] = handler; -} - -V8CommandHandler *QV4DebugServicePrivate::v8CommandHandler(const QString &command) const -{ - V8CommandHandler *handler = handlers.value(command, 0); - if (handler) - return handler; - else - return unknownV8CommandHandler.data(); -} - -QV4DebugService::QV4DebugService(QObject *parent) - : QQmlConfigurableDebugService(*(new QV4DebugServicePrivate()), - QStringLiteral("V8Debugger"), 1, parent) -{} - -QV4DebugService::~QV4DebugService() -{ -} - -QV4DebugService *QV4DebugService::instance() -{ - return v4ServiceInstance(); -} - -void QV4DebugService::engineAboutToBeAdded(QQmlEngine *engine) -{ - Q_D(QV4DebugService); - QMutexLocker lock(configMutex()); - if (engine) { - QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle()); - if (QQmlDebugServer *server = QQmlDebugServer::instance()) { - if (ee) { - ee->enableDebugger(); - QV4::Debugging::Debugger *debugger = ee->debugger; - d->debuggerMap.insert(d->debuggerIndex++, debugger); - d->debuggerAgent.addDebugger(debugger); - d->debuggerAgent.moveToThread(server->thread()); - moveToThread(server->thread()); - } - } - } - QQmlConfigurableDebugService::engineAboutToBeAdded(engine); -} - -void QV4DebugService::engineAboutToBeRemoved(QQmlEngine *engine) -{ - Q_D(QV4DebugService); - QMutexLocker lock(configMutex()); - if (engine){ - const QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle()); - if (ee) { - QV4::Debugging::Debugger *debugger = ee->debugger; - typedef QMap<int, QV4::Debugging::Debugger *>::const_iterator DebuggerMapIterator; - const DebuggerMapIterator end = d->debuggerMap.constEnd(); - for (DebuggerMapIterator i = d->debuggerMap.constBegin(); i != end; ++i) { - if (i.value() == debugger) { - d->debuggerMap.remove(i.key()); - break; - } - } - d->debuggerAgent.removeDebugger(debugger); - } - } - QQmlConfigurableDebugService::engineAboutToBeRemoved(engine); -} - -void QV4DebugService::signalEmitted(const QString &signal) -{ - //This function is only called by QQmlBoundSignal - //only if there is a slot connected to the signal. Hence, there - //is no need for additional check. - Q_D(QV4DebugService); - - //Parse just the name and remove the class info - //Normalize to Lower case. - QString signalName = signal.left(signal.indexOf(QLatin1Char('('))).toLower(); - - foreach (const QString &signal, d->breakOnSignals) { - if (signal == signalName) { - // TODO: pause debugger - break; - } - } -} - -void QV4DebugService::messageReceived(const QByteArray &message) -{ - Q_D(QV4DebugService); - QMutexLocker lock(configMutex()); - - QQmlDebugStream ms(message); - QByteArray header; - ms >> header; - - TRACE_PROTOCOL(qDebug() << "received message with header" << header); - - if (header == "V8DEBUG") { - QByteArray type; - QByteArray payload; - ms >> type >> payload; - TRACE_PROTOCOL(qDebug() << "... type:" << type); - - if (type == V4_CONNECT) { - sendMessage(d->packMessage(type)); - stopWaiting(); - } else if (type == V4_PAUSE) { - d->debuggerAgent.pauseAll(); - sendSomethingToSomebody(type); - } else if (type == V4_BREAK_ON_SIGNAL) { - QByteArray signal; - bool enabled; - ms >> signal >> enabled; - //Normalize to lower case. - QString signalName(QString::fromUtf8(signal).toLower()); - if (enabled) - d->breakOnSignals.append(signalName); - else - d->breakOnSignals.removeOne(signalName); - } else if (type == "v8request") { - handleV8Request(payload); - } else if (type == V4_DISCONNECT) { - TRACE_PROTOCOL(qDebug() << "... payload:" << payload); - handleV8Request(payload); - } else { - sendSomethingToSomebody(type, 0); - } - } -} - -void QV4DebugService::sendSomethingToSomebody(const char *type, int magicNumber) -{ - Q_D(QV4DebugService); - - QByteArray response; - QQmlDebugStream rs(&response, QIODevice::WriteOnly); - rs << QByteArray(type) - << QByteArray::number(d->version) << QByteArray::number(magicNumber); - sendMessage(d->packMessage(type, response)); -} - -void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::Debugger *debugger, QV4::Debugging::PauseReason reason) -{ - Q_UNUSED(reason); - - debugServicePrivate->clearHandles(debugger->engine()); - - QJsonObject event, body, script; - event.insert(QStringLiteral("type"), QStringLiteral("event")); - - switch (reason) { - case QV4::Debugging::Step: - case QV4::Debugging::PauseRequest: - case QV4::Debugging::BreakPoint: { - event.insert(QStringLiteral("event"), QStringLiteral("break")); - QVector<QV4::StackFrame> frames = debugger->stackTrace(1); - if (frames.isEmpty()) - break; - - const QV4::StackFrame &topFrame = frames.first(); - body.insert(QStringLiteral("invocationText"), topFrame.function); - body.insert(QStringLiteral("sourceLine"), topFrame.line - 1); - if (topFrame.column > 0) - body.insert(QStringLiteral("sourceColumn"), topFrame.column); - QJsonArray breakPoints; - foreach (int breakPointId, breakPointIds(topFrame.source, topFrame.line)) - breakPoints.push_back(breakPointId); - body.insert(QStringLiteral("breakpoints"), breakPoints); - script.insert(QStringLiteral("name"), topFrame.source); - } break; - case QV4::Debugging::Throwing: - // TODO: complete this! - event.insert(QStringLiteral("event"), QStringLiteral("exception")); - break; - } - - if (!script.isEmpty()) - body.insert(QStringLiteral("script"), script); - if (!body.isEmpty()) - event.insert(QStringLiteral("body"), body); - debugServicePrivate->send(event); -} - -void QV4DebuggerAgent::sourcesCollected(QV4::Debugging::Debugger *debugger, QStringList sources, int requestSequenceNr) -{ - QJsonArray body; - foreach (const QString source, sources) { - QJsonObject src; - src[QLatin1String("name")] = source; - src[QLatin1String("scriptType")] = 4; - body.append(src); - } - - QJsonObject response; - response[QLatin1String("success")] = true; - response[QLatin1String("running")] = debugger->state() == QV4::Debugging::Debugger::Running; - response[QLatin1String("body")] = body; - response[QLatin1String("command")] = QStringLiteral("scripts"); - response[QLatin1String("request_seq")] = requestSequenceNr; - response[QLatin1String("type")] = QStringLiteral("response"); - debugServicePrivate->send(response); -} - -void QV4DebugService::handleV8Request(const QByteArray &payload) -{ - Q_D(QV4DebugService); - - TRACE_PROTOCOL(qDebug() << "v8request, payload:" << payload); - - QJsonDocument request = QJsonDocument::fromJson(payload); - QJsonObject o = request.object(); - QJsonValue type = o.value(QStringLiteral("type")); - if (type.toString() == QStringLiteral("request")) { - QJsonValue command = o.value(QStringLiteral("command")); - V8CommandHandler *h = d->v8CommandHandler(command.toString()); - if (h) - h->handle(o, this, d); - } -} - -QT_END_NAMESPACE diff --git a/src/qml/debugger/qv4debugservice_p.h b/src/qml/debugger/qv4debugservice_p.h deleted file mode 100644 index f7b38b11b6..0000000000 --- a/src/qml/debugger/qv4debugservice_p.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QV4DEBUGSERVICE_P_H -#define QV4DEBUGSERVICE_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. -// - -#include "qqmlconfigurabledebugservice_p.h" - -QT_BEGIN_NAMESPACE - -namespace QV4 { struct ExecutionEngine; } -class QQmlEngine; -class QV4DebugServicePrivate; - -class QV4DebugService : public QQmlConfigurableDebugService -{ - Q_OBJECT -public: - explicit QV4DebugService(QObject *parent = 0); - ~QV4DebugService(); - - static QV4DebugService *instance(); - void engineAboutToBeAdded(QQmlEngine *engine); - void engineAboutToBeRemoved(QQmlEngine *engine); - - void signalEmitted(const QString &signal); - -protected: - void messageReceived(const QByteArray &); - void sendSomethingToSomebody(const char *type, int magicNumber = 1); - -private: - void handleV8Request(const QByteArray &payload); - -private: - Q_DISABLE_COPY(QV4DebugService) - Q_DECLARE_PRIVATE(QV4DebugService) -}; - -QT_END_NAMESPACE - -#endif // QV4DEBUGSERVICE_P_H diff --git a/src/qml/debugger/qv4profileradapter.cpp b/src/qml/debugger/qv4profileradapter.cpp deleted file mode 100644 index 2b8183dc69..0000000000 --- a/src/qml/debugger/qv4profileradapter.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qv4profileradapter_p.h" -#include "qqmlprofilerservice_p.h" -#include "qqmldebugservice_p.h" - -QT_BEGIN_NAMESPACE - -QV4ProfilerAdapter::QV4ProfilerAdapter(QQmlProfilerService *service, QV4::ExecutionEngine *engine) : - QQmlAbstractProfilerAdapter(service) -{ - engine->enableProfiler(); - connect(this, SIGNAL(profilingEnabled(quint64)), - engine->profiler, SLOT(startProfiling(quint64))); - connect(this, SIGNAL(profilingEnabledWhileWaiting(quint64)), - engine->profiler, SLOT(startProfiling(quint64)), Qt::DirectConnection); - connect(this, SIGNAL(profilingDisabled()), engine->profiler, SLOT(stopProfiling())); - connect(this, SIGNAL(profilingDisabledWhileWaiting()), engine->profiler, SLOT(stopProfiling()), - Qt::DirectConnection); - connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData())); - connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), - engine->profiler, SLOT(setTimer(QElapsedTimer))); - connect(engine->profiler, SIGNAL(dataReady(QList<QV4::Profiling::FunctionCallProperties>, - QList<QV4::Profiling::MemoryAllocationProperties>)), - this, SLOT(receiveData(QList<QV4::Profiling::FunctionCallProperties>, - QList<QV4::Profiling::MemoryAllocationProperties>))); -} - -qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList<QByteArray> &messages) -{ - QByteArray message; - while (!memory_data.empty() && memory_data.front().timestamp <= until) { - QQmlDebugStream d(&message, QIODevice::WriteOnly); - QV4::Profiling::MemoryAllocationProperties &props = memory_data.front(); - d << props.timestamp << MemoryAllocation << props.type << props.size; - memory_data.pop_front(); - messages.append(message); - } - return memory_data.empty() ? -1 : memory_data.front().timestamp; -} - -qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) -{ - QByteArray message; - while (true) { - while (!stack.empty() && (data.empty() || stack.top() <= data.front().start)) { - if (stack.top() > until) { - qint64 memory_next = appendMemoryEvents(until, messages); - return memory_next == -1 ? stack.top() : qMin(stack.top(), memory_next); - } - appendMemoryEvents(stack.top(), messages); - QQmlDebugStream d(&message, QIODevice::WriteOnly); - d << stack.pop() << RangeEnd << Javascript; - messages.append(message); - } - while (!data.empty() && (stack.empty() || data.front().start < stack.top())) { - const QV4::Profiling::FunctionCallProperties &props = data.front(); - if (props.start > until) { - qint64 memory_next = appendMemoryEvents(until, messages); - return memory_next == -1 ? props.start : qMin(props.start, memory_next); - } - appendMemoryEvents(props.start, messages); - - QQmlDebugStream d_start(&message, QIODevice::WriteOnly); - d_start << props.start << RangeStart << Javascript; - messages.push_back(message); - message.clear(); - QQmlDebugStream d_location(&message, QIODevice::WriteOnly); - d_location << props.start << RangeLocation << Javascript << props.file << props.line - << props.column; - messages.push_back(message); - message.clear(); - QQmlDebugStream d_data(&message, QIODevice::WriteOnly); - d_data << props.start << RangeData << Javascript << props.name; - messages.push_back(message); - message.clear(); - stack.push(props.end); - data.pop_front(); - } - if (stack.empty() && data.empty()) - return appendMemoryEvents(until, messages); - } -} - -void QV4ProfilerAdapter::receiveData(const QList<QV4::Profiling::FunctionCallProperties> &new_data, - const QList<QV4::Profiling::MemoryAllocationProperties> &new_memory_data) -{ - data = new_data; - memory_data = new_memory_data; - stack.clear(); - service->dataReady(this); -} - -QT_END_NAMESPACE diff --git a/src/qml/debugger/qv4profileradapter_p.h b/src/qml/debugger/qv4profileradapter_p.h deleted file mode 100644 index 2f467f4beb..0000000000 --- a/src/qml/debugger/qv4profileradapter_p.h +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QV4PROFILERADAPTER_P_H -#define QV4PROFILERADAPTER_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. -// - -#include "qv4profiling_p.h" -#include "qqmlabstractprofileradapter_p.h" - -#include <QStack> -#include <QList> - -QT_BEGIN_NAMESPACE - -class QQmlProfilerService; -class QV4ProfilerAdapter : public QQmlAbstractProfilerAdapter { - Q_OBJECT - -public: - QV4ProfilerAdapter(QQmlProfilerService *service, QV4::ExecutionEngine *engine); - - virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages); - -public slots: - void receiveData(const QList<QV4::Profiling::FunctionCallProperties> &, - const QList<QV4::Profiling::MemoryAllocationProperties> &); - -private: - QList<QV4::Profiling::FunctionCallProperties> data; - QList<QV4::Profiling::MemoryAllocationProperties> memory_data; - QStack<qint64> stack; - qint64 appendMemoryEvents(qint64 until, QList<QByteArray> &messages); -}; - -QT_END_NAMESPACE - -#endif // QV4PROFILERADAPTER_P_H diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 09e5b14c97..b5765b5705 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -241,16 +241,16 @@ void Assembler::enterStandardStackFrame(const RegisterInformation ®ularRegist subPtr(TrustedImm32(frameSize), StackPointerRegister); Address slotAddr(StackFrameRegister, 0); - for (int i = 0, ei = regularRegistersToSave.size(); i < ei; ++i) { - Q_ASSERT(regularRegistersToSave.at(i).isRegularRegister()); - slotAddr.offset -= RegisterSize; - storePtr(regularRegistersToSave.at(i).reg<RegisterID>(), slotAddr); - } for (int i = 0, ei = fpRegistersToSave.size(); i < ei; ++i) { Q_ASSERT(fpRegistersToSave.at(i).isFloatingPoint()); slotAddr.offset -= sizeof(double); JSC::MacroAssembler::storeDouble(fpRegistersToSave.at(i).reg<FPRegisterID>(), slotAddr); } + for (int i = 0, ei = regularRegistersToSave.size(); i < ei; ++i) { + Q_ASSERT(regularRegistersToSave.at(i).isRegularRegister()); + slotAddr.offset -= RegisterSize; + storePtr(regularRegistersToSave.at(i).reg<RegisterID>(), slotAddr); + } } void Assembler::leaveStandardStackFrame(const RegisterInformation ®ularRegistersToSave, @@ -259,16 +259,16 @@ void Assembler::leaveStandardStackFrame(const RegisterInformation ®ularRegist Address slotAddr(StackFrameRegister, -regularRegistersToSave.size() * RegisterSize - fpRegistersToSave.size() * sizeof(double)); // restore the callee saved registers - for (int i = fpRegistersToSave.size() - 1; i >= 0; --i) { - Q_ASSERT(fpRegistersToSave.at(i).isFloatingPoint()); - JSC::MacroAssembler::loadDouble(slotAddr, fpRegistersToSave.at(i).reg<FPRegisterID>()); - slotAddr.offset += sizeof(double); - } for (int i = regularRegistersToSave.size() - 1; i >= 0; --i) { Q_ASSERT(regularRegistersToSave.at(i).isRegularRegister()); loadPtr(slotAddr, regularRegistersToSave.at(i).reg<RegisterID>()); slotAddr.offset += RegisterSize; } + for (int i = fpRegistersToSave.size() - 1; i >= 0; --i) { + Q_ASSERT(fpRegistersToSave.at(i).isFloatingPoint()); + JSC::MacroAssembler::loadDouble(slotAddr, fpRegistersToSave.at(i).reg<FPRegisterID>()); + slotAddr.offset += sizeof(double); + } Q_ASSERT(slotAddr.offset == 0); diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 3b65acb26c..ab74211d23 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -478,7 +478,7 @@ public: load64(addr, dest); } else { QV4::Value undefined = QV4::Primitive::undefinedValue(); - move(TrustedImm64(undefined.val), dest); + move(TrustedImm64(undefined.rawValue()), dest); } } @@ -491,7 +491,7 @@ public: load64(addr, dest); } else { QV4::Value undefined = QV4::Primitive::undefinedValue(); - move(TrustedImm64(undefined.val), dest); + move(TrustedImm64(undefined.rawValue()), dest); } } @@ -500,7 +500,7 @@ public: Q_UNUSED(argumentNumber); QV4::Value v = convertToValue(c); - move(TrustedImm64(v.val), dest); + move(TrustedImm64(v.rawValue()), dest); } void loadArgumentInRegister(IR::Expr* expr, RegisterID dest, int argumentNumber) @@ -509,7 +509,7 @@ public: if (!expr) { QV4::Value undefined = QV4::Primitive::undefinedValue(); - move(TrustedImm64(undefined.val), dest); + move(TrustedImm64(undefined.rawValue()), dest); } else if (IR::Temp *t = expr->asTemp()){ loadArgumentInRegister(t, dest, argumentNumber); } else if (IR::ArgLocal *al = expr->asArgLocal()) { @@ -565,6 +565,8 @@ public: moveIntsToDouble(JSC::ARMRegisters::r0, JSC::ARMRegisters::r1, dest, FPGpr0); #elif defined(Q_PROCESSOR_X86) moveIntsToDouble(JSC::X86Registers::eax, JSC::X86Registers::edx, dest, FPGpr0); +#elif defined(Q_PROCESSOR_MIPS) + moveIntsToDouble(JSC::MIPSRegisters::v0, JSC::MIPSRegisters::v1, dest, FPGpr0); #else subPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister); Pointer tmp(StackPointerRegister, 0); @@ -595,6 +597,14 @@ public: destination.offset += 4; store32(JSC::ARMRegisters::r1, destination); } +#elif defined(Q_PROCESSOR_MIPS) + void storeReturnValue(const Pointer &dest) + { + Pointer destination = dest; + store32(JSC::MIPSRegisters::v0, destination); + destination.offset += 4; + store32(JSC::MIPSRegisters::v1, destination); + } #endif void storeReturnValue(IR::Expr *target) @@ -781,11 +791,11 @@ public: void storeValue(QV4::Primitive value, Address destination) { #ifdef VALUE_FITS_IN_REGISTER - store64(TrustedImm64(value.val), destination); + store64(TrustedImm64(value.rawValue()), destination); #else - store32(TrustedImm32(value.int_32), destination); + store32(TrustedImm32(value.int_32()), destination); destination.offset += 4; - store32(TrustedImm32(value.tag), destination); + store32(TrustedImm32(value.tag()), destination); #endif } @@ -820,6 +830,8 @@ public: else #if OS(WINDOWS) && CPU(X86_64) loadArgumentOnStack<argumentNumber>(value, argumentNumber); +#elif CPU(MIPS) // Stack space for 4 arguments needs to be allocated for MIPS platforms. + loadArgumentOnStack<argumentNumber>(value, argumentNumber + 4); #else // Sanity: loadArgumentOnStack<argumentNumber - RegisterArgumentCount>(value, argumentNumber); #endif @@ -945,8 +957,8 @@ public: tagAddr.offset += 4; QV4::Primitive v = convertToValue(c); - store32(TrustedImm32(v.int_32), addr); - store32(TrustedImm32(v.tag), tagAddr); + store32(TrustedImm32(v.int_32()), addr); + store32(TrustedImm32(v.tag()), tagAddr); return Pointer(addr); } @@ -961,7 +973,7 @@ public: { store32(reg, addr); addr.offset += 4; - store32(TrustedImm32(QV4::Primitive::fromBoolean(0).tag), addr); + store32(TrustedImm32(QV4::Primitive::fromBoolean(0).tag()), addr); } void storeBool(RegisterID src, RegisterID dest) @@ -1005,7 +1017,7 @@ public: { store32(reg, addr); addr.offset += 4; - store32(TrustedImm32(QV4::Primitive::fromInt32(0).tag), addr); + store32(TrustedImm32(QV4::Primitive::fromInt32(0).tag()), addr); } void storeInt32(RegisterID reg, IR::Expr *target) @@ -1084,7 +1096,7 @@ public: RegisterID toInt32Register(IR::Expr *e, RegisterID scratchReg) { if (IR::Const *c = e->asConst()) { - move(TrustedImm32(convertToValue(c).int_32), scratchReg); + move(TrustedImm32(convertToValue(c).int_32()), scratchReg); return scratchReg; } diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp index c6c8023cd7..8b051fcb3d 100644 --- a/src/qml/jit/qv4binop.cpp +++ b/src/qml/jit/qv4binop.cpp @@ -352,7 +352,9 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta } } - if (op == IR::OpSub) { + // Special cases: + switch (op) { + case IR::OpSub: if (rightSource->asTemp() && rightSource->asTemp()->kind == IR::Temp::PhysicalRegister && targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister @@ -368,11 +370,27 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta } as->storeInt32(targetReg, target); return true; + + case IR::OpLShift: + case IR::OpRShift: + case IR::OpURShift: + if (IR::Const *c = rightSource->asConst()) { + if ((QV4::Primitive::toUInt32(c->value) & 0x1f) == 0) { + Assembler::RegisterID r = as->toInt32Register(leftSource, targetReg); + as->storeInt32(r, target); + return true; + } + } + break; + + default: + break; } Assembler::RegisterID l = as->toInt32Register(leftSource, targetReg); if (IR::Const *c = rightSource->asConst()) { // All cases of Y = X op Const Assembler::TrustedImm32 r(int(c->value)); + Assembler::TrustedImm32 ur(QV4::Primitive::toUInt32(c->value) & 0x1f); switch (op) { case IR::OpBitAnd: as->and32(r, l, targetReg); break; @@ -381,9 +399,9 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta case IR::OpAdd: as->add32(r, l, targetReg); break; case IR::OpMul: as->mul32(r, l, targetReg); break; - case IR::OpLShift: r.m_value &= 0x1f; as->lshift32(l, r, targetReg); break; - case IR::OpRShift: r.m_value &= 0x1f; as->rshift32(l, r, targetReg); break; - case IR::OpURShift: r.m_value &= 0x1f; as->urshift32(l, r, targetReg); + case IR::OpLShift: as->lshift32(l, ur, targetReg); break; + case IR::OpRShift: as->rshift32(l, ur, targetReg); break; + case IR::OpURShift: as->urshift32(l, ur, targetReg); as->storeUInt32(targetReg, target); // IMPORTANT: do NOT do a break here! The stored type of an urshift is different from the other binary operations! return true; @@ -415,32 +433,33 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta case IR::OpAdd: as->add32(l, r, targetReg); break; case IR::OpMul: as->mul32(l, r, targetReg); break; -#if CPU(ARM) || CPU(X86) || CPU(X86_64) - // The ARM assembler will generate an and with 0x1f for us, and Intel will do it on the CPU. - +#if CPU(X86) || CPU(X86_64) + // Intel does the & 0x1f on the CPU, so: case IR::OpLShift: as->lshift32(l, r, targetReg); break; case IR::OpRShift: as->rshift32(l, r, targetReg); break; case IR::OpURShift: as->urshift32(l, r, targetReg); as->storeUInt32(targetReg, target); // IMPORTANT: do NOT do a break here! The stored type of an urshift is different from the other binary operations! return true; #else - case IR::OpLShift: - as->move(r, Assembler::ScratchRegister); - as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); - as->lshift32(l, Assembler::ScratchRegister, targetReg); - break; - - case IR::OpRShift: - as->move(r, Assembler::ScratchRegister); - as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); - as->rshift32(l, Assembler::ScratchRegister, targetReg); - break; - + // Not all CPUs accept shifts over more than 31 bits, and some CPUs (like ARM) will do + // surprising stuff when shifting over 0 bits. +#define CHECK_RHS(op) { \ + as->and32(Assembler::TrustedImm32(0x1f), r, Assembler::ScratchRegister); \ + Assembler::Jump notZero = as->branch32(Assembler::NotEqual, Assembler::ScratchRegister, Assembler::TrustedImm32(0)); \ + as->move(l, targetReg); \ + Assembler::Jump done = as->jump(); \ + notZero.link(as); \ + op; \ + done.link(as); \ +} + case IR::OpLShift: CHECK_RHS(as->lshift32(l, Assembler::ScratchRegister, targetReg)); break; + case IR::OpRShift: CHECK_RHS(as->rshift32(l, Assembler::ScratchRegister, targetReg)); break; case IR::OpURShift: - as->move(r, Assembler::ScratchRegister); - as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); - as->storeUInt32(targetReg, target); // IMPORTANT: do NOT do a break here! The stored type of an urshift is different from the other binary operations! + CHECK_RHS(as->urshift32(l, Assembler::ScratchRegister, targetReg)); + as->storeUInt32(targetReg, target); + // IMPORTANT: do NOT do a break here! The stored type of an urshift is different from the other binary operations! return true; +#undef CHECK_RHS #endif case IR::OpSub: // already handled before diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index da511cd1eb..acead2088b 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -317,7 +317,7 @@ const void *InstructionSelection::addConstantTable(QVector<Primitive> *values) QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection::backendCompileStep() { QQmlRefPointer<QV4::CompiledData::CompilationUnit> result; - result.take(compilationUnit.take()); + result.adopt(compilationUnit.take()); return result; } @@ -574,9 +574,9 @@ void InstructionSelection::loadThisObject(IR::Expr *temp) #endif } -void InstructionSelection::loadQmlIdArray(IR::Expr *temp) +void InstructionSelection::loadQmlContext(IR::Expr *temp) { - generateFunctionCall(temp, Runtime::getQmlIdArray, Assembler::EngineRegister); + generateFunctionCall(temp, Runtime::getQmlContext, Assembler::EngineRegister); } void InstructionSelection::loadQmlImportedScripts(IR::Expr *temp) @@ -584,16 +584,6 @@ void InstructionSelection::loadQmlImportedScripts(IR::Expr *temp) generateFunctionCall(temp, Runtime::getQmlImportedScripts, Assembler::EngineRegister); } -void InstructionSelection::loadQmlContextObject(IR::Expr *temp) -{ - generateFunctionCall(temp, Runtime::getQmlContextObject, Assembler::EngineRegister); -} - -void InstructionSelection::loadQmlScopeObject(IR::Expr *temp) -{ - generateFunctionCall(temp, Runtime::getQmlScopeObject, Assembler::EngineRegister); -} - void InstructionSelection::loadQmlSingleton(const QString &name, IR::Expr *temp) { generateFunctionCall(temp, Runtime::getQmlSingleton, Assembler::EngineRegister, Assembler::StringToIndex(name)); @@ -614,7 +604,7 @@ void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Expr *target) _as->toUInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index); } else if (targetTemp->type == IR::BoolType) { Q_ASSERT(sourceConst->type == IR::BoolType); - _as->move(Assembler::TrustedImm32(convertToValue(sourceConst).int_32), + _as->move(Assembler::TrustedImm32(convertToValue(sourceConst).int_32()), (Assembler::RegisterID) targetTemp->index); } else { Q_UNREACHABLE(); @@ -680,6 +670,18 @@ void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR:: } } +void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int index, IR::Expr *target) +{ + if (kind == IR::Member::MemberOfQmlScopeObject) + generateFunctionCall(target, Runtime::getQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index)); + else if (kind == IR::Member::MemberOfQmlContextObject) + generateFunctionCall(target, Runtime::getQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index)); + else if (kind == IR::Member::MemberOfIdObjectsArray) + generateFunctionCall(target, Runtime::getQmlIdObject, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index)); + else + Q_ASSERT(false); +} + void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target) { if (attachedPropertiesId != 0) @@ -708,6 +710,18 @@ void InstructionSelection::setProperty(IR::Expr *source, IR::Expr *targetBase, } } +void InstructionSelection::setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex) +{ + if (kind == IR::Member::MemberOfQmlScopeObject) + generateFunctionCall(Assembler::Void, Runtime::setQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase), + Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source)); + else if (kind == IR::Member::MemberOfQmlContextObject) + generateFunctionCall(Assembler::Void, Runtime::setQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase), + Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source)); + else + Q_ASSERT(false); +} + void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex) { generateFunctionCall(Assembler::Void, Runtime::setQmlQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase), @@ -901,6 +915,24 @@ void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr binop.generate(leftSource, rightSource, target); } +void InstructionSelection::callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result) +{ + prepareCallData(args, base); + + if (kind == IR::Member::MemberOfQmlScopeObject) + generateFunctionCall(result, Runtime::callQmlScopeObjectProperty, + Assembler::EngineRegister, + Assembler::TrustedImm32(propertyIndex), + baseAddressForCallData()); + else if (kind == IR::Member::MemberOfQmlContextObject) + generateFunctionCall(result, Runtime::callQmlContextObjectProperty, + Assembler::EngineRegister, + Assembler::TrustedImm32(propertyIndex), + baseAddressForCallData()); + else + Q_ASSERT(false); +} + void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) { @@ -1297,11 +1329,11 @@ void InstructionSelection::visitCJump(IR::CJump *s) } else { Address temp = _as->loadAddress(Assembler::ScratchRegister, s->cond); Address tag = temp; - tag.offset += qOffsetOf(QV4::Value, tag); + tag.offset += QV4::Value::tagOffset(); Assembler::Jump booleanConversion = _as->branch32(Assembler::NotEqual, tag, Assembler::TrustedImm32(QV4::Value::Boolean_Type)); Address data = temp; - data.offset += qOffsetOf(QV4::Value, int_32); + data.offset += QV4::Value::valueOffset(); _as->load32(data, Assembler::ReturnValueRegister); Assembler::Jump testBoolean = _as->jump(); @@ -1383,11 +1415,14 @@ void InstructionSelection::visitRet(IR::Ret *s) // this only happens if the method doesn't have a return statement and can // only exit through an exception } else if (IR::Temp *t = s->expr->asTemp()) { -#if CPU(X86) || CPU(ARM) +#if CPU(X86) || CPU(ARM) || CPU(MIPS) # if CPU(X86) Assembler::RegisterID lowReg = JSC::X86Registers::eax; Assembler::RegisterID highReg = JSC::X86Registers::edx; +# elif CPU(MIPS) + Assembler::RegisterID lowReg = JSC::MIPSRegisters::v0; + Assembler::RegisterID highReg = JSC::MIPSRegisters::v1; # else // CPU(ARM) Assembler::RegisterID lowReg = JSC::ARMRegisters::r0; Assembler::RegisterID highReg = JSC::ARMRegisters::r1; @@ -1472,13 +1507,16 @@ void InstructionSelection::visitRet(IR::Ret *s) } else if (IR::Const *c = s->expr->asConst()) { QV4::Primitive retVal = convertToValue(c); #if CPU(X86) - _as->move(Assembler::TrustedImm32(retVal.int_32), JSC::X86Registers::eax); - _as->move(Assembler::TrustedImm32(retVal.tag), JSC::X86Registers::edx); + _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::X86Registers::eax); + _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::X86Registers::edx); #elif CPU(ARM) - _as->move(Assembler::TrustedImm32(retVal.int_32), JSC::ARMRegisters::r0); - _as->move(Assembler::TrustedImm32(retVal.tag), JSC::ARMRegisters::r1); + _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::ARMRegisters::r0); + _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::ARMRegisters::r1); +#elif CPU(MIPS) + _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::MIPSRegisters::v0); + _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::MIPSRegisters::v1); #else - _as->move(Assembler::TrustedImm64(retVal.val), Assembler::ReturnValueRegister); + _as->move(Assembler::TrustedImm64(retVal.rawValue()), Assembler::ReturnValueRegister); #endif } else { Q_UNREACHABLE(); @@ -1499,13 +1537,16 @@ void InstructionSelection::visitRet(IR::Ret *s) _as->exceptionReturnLabel = _as->label(); QV4::Primitive retVal = Primitive::undefinedValue(); #if CPU(X86) - _as->move(Assembler::TrustedImm32(retVal.int_32), JSC::X86Registers::eax); - _as->move(Assembler::TrustedImm32(retVal.tag), JSC::X86Registers::edx); + _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::X86Registers::eax); + _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::X86Registers::edx); #elif CPU(ARM) - _as->move(Assembler::TrustedImm32(retVal.int_32), JSC::ARMRegisters::r0); - _as->move(Assembler::TrustedImm32(retVal.tag), JSC::ARMRegisters::r1); + _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::ARMRegisters::r0); + _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::ARMRegisters::r1); +#elif CPU(MIPS) + _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::MIPSRegisters::v0); + _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::MIPSRegisters::v1); #else - _as->move(Assembler::TrustedImm64(retVal.val), Assembler::ReturnValueRegister); + _as->move(Assembler::TrustedImm64(retVal.rawValue()), Assembler::ReturnValueRegister); #endif _as->jump(leaveStackFrame); } diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h index 87b4a20bfc..6e842f5fb4 100644 --- a/src/qml/jit/qv4isel_masm_p.h +++ b/src/qml/jit/qv4isel_masm_p.h @@ -91,14 +91,13 @@ protected: virtual void callBuiltinSetupArgumentObject(IR::Expr *result); virtual void callBuiltinConvertThisToObject(); virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result); + virtual void callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result); virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result); virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Expr *result); virtual void convertType(IR::Expr *source, IR::Expr *target); virtual void loadThisObject(IR::Expr *temp); - virtual void loadQmlIdArray(IR::Expr *target); + virtual void loadQmlContext(IR::Expr *target); virtual void loadQmlImportedScripts(IR::Expr *target); - virtual void loadQmlContextObject(IR::Expr *target); - virtual void loadQmlScopeObject(IR::Expr *target); virtual void loadQmlSingleton(const QString &name, IR::Expr *target); virtual void loadConst(IR::Const *sourceConst, IR::Expr *target); virtual void loadString(const QString &str, IR::Expr *target); @@ -107,8 +106,10 @@ protected: virtual void setActivationProperty(IR::Expr *source, const QString &targetName); virtual void initClosure(IR::Closure *closure, IR::Expr *target); virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target); + virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target); virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target); virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName); + virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex); virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex); virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target); virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex); diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp index ae06a99d2a..b9178c0ea0 100644 --- a/src/qml/jit/qv4regalloc.cpp +++ b/src/qml/jit/qv4regalloc.cpp @@ -35,7 +35,7 @@ #include <QtCore/QDebug> #include "qv4regalloc_p.h" #include "qv4alloca_p.h" -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <algorithm> #if defined(Q_CC_MINGW) @@ -299,6 +299,16 @@ protected: // IRDecoder addCall(); } + virtual void callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind /*kind*/, int propertyIndex, IR::ExprList *args, IR::Expr *result) + { + Q_UNUSED(propertyIndex) + + addDef(result); + addUses(base->asTemp(), Use::CouldHaveRegister); + addUses(args, Use::CouldHaveRegister); + addCall(); + } + virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) { @@ -421,7 +431,7 @@ protected: // IRDecoder addDef(temp); } - virtual void loadQmlIdArray(IR::Expr *temp) + virtual void loadQmlContext(IR::Expr *temp) { addDef(temp); addCall(); @@ -433,20 +443,6 @@ protected: // IRDecoder addCall(); } - virtual void loadQmlContextObject(Expr *temp) - { - addDef(temp); - addCall(); - } - - virtual void loadQmlScopeObject(Expr *temp) - { - Q_UNUSED(temp); - - addDef(temp); - addCall(); - } - virtual void loadQmlSingleton(const QString &/*name*/, Expr *temp) { Q_UNUSED(temp); @@ -511,6 +507,13 @@ protected: // IRDecoder addCall(); } + virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind /*kind*/, int /*propertyIndex*/) + { + addUses(source->asTemp(), Use::CouldHaveRegister); + addUses(targetBase->asTemp(), Use::CouldHaveRegister); + addCall(); + } + virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int /*propertyIndex*/) { addUses(source->asTemp(), Use::CouldHaveRegister); @@ -518,6 +521,13 @@ protected: // IRDecoder addCall(); } + virtual void getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind /*kind*/, int /*index*/, IR::Expr *target) + { + addDef(target); + addUses(base->asTemp(), Use::CouldHaveRegister); + addCall(); + } + virtual void getQObjectProperty(IR::Expr *base, int /*propertyIndex*/, bool /*captureRequired*/, bool /*isSingleton*/, int /*attachedPropertiesId*/, IR::Expr *target) { addDef(target); diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h index 05741f0ae5..76c768e4f9 100644 --- a/src/qml/jit/qv4targetplatform_p.h +++ b/src/qml/jit/qv4targetplatform_p.h @@ -346,6 +346,71 @@ public: static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(JSC::ARMRegisters::lr); } #endif // Linux on ARM (32 bit) +#if defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX) + enum { RegAllocIsSupported = 1 }; + + static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::MIPSRegisters::fp; + static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::MIPSRegisters::sp; + static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::MIPSRegisters::s0; + static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::MIPSRegisters::s1; + static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::MIPSRegisters::v0; + static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::MIPSRegisters::s2; + static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::MIPSRegisters::f0; + static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::MIPSRegisters::f2; + + static RegisterInformation getPlatformRegisterInfo() + { + typedef RegisterInfo RI; + return RegisterInformation() + // Note: t0, t1, t2, t3 and f16 are already used by MacroAssemblerMIPS. + << RI(JSC::MIPSRegisters::t4, QStringLiteral("t4"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::t5, QStringLiteral("t5"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::t6, QStringLiteral("t6"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::t7, QStringLiteral("t7"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::t8, QStringLiteral("t8"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::s0, QStringLiteral("s0"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::MIPSRegisters::s1, QStringLiteral("s1"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::MIPSRegisters::s2, QStringLiteral("s2"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::MIPSRegisters::s3, QStringLiteral("s3"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f4, QStringLiteral("f4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f6, QStringLiteral("f6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f8, QStringLiteral("f8"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f10, QStringLiteral("f10"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f18, QStringLiteral("f18"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f20, QStringLiteral("f20"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f22, QStringLiteral("f22"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f24, QStringLiteral("f24"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f26, QStringLiteral("f26"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f28, QStringLiteral("f28"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc) + ; + } + +#undef HAVE_ALU_OPS_WITH_MEM_OPERAND +#undef VALUE_FITS_IN_REGISTER + static const int RegisterSize = 4; + +#define ARGUMENTS_IN_REGISTERS + static const int RegisterArgumentCount = 4; + static JSC::MacroAssembler::RegisterID registerForArgument(int index) + { + static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = { + JSC::MIPSRegisters::a0, + JSC::MIPSRegisters::a1, + JSC::MIPSRegisters::a2, + JSC::MIPSRegisters::a3 + }; + + Q_ASSERT(index >= 0 && index < RegisterArgumentCount); + return regs[index]; + }; + + static const int StackAlignment = 8; + static const int StackShadowSpace = 4 * RegisterSize; // Stack space for 4 argument registers. + static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below. + static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { as->push(JSC::MIPSRegisters::ra); } + static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(JSC::MIPSRegisters::ra); } +#endif // Linux on MIPS (32 bit) + public: // utility functions static RegisterInformation getRegisterInfo() { diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index ee27c21aed..d9615d496f 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -77,7 +77,6 @@ Q_DECLARE_METATYPE(QList<int>) \ingroup qtjavascript \inmodule QtQml - \mainclass \section1 Evaluating Scripts @@ -271,7 +270,7 @@ void QJSEngine::installTranslatorFunctions(const QJSValue &object) if (val) obj = val; if (!obj) - obj = scope.engine->globalObject(); + obj = scope.engine->globalObject; #ifndef QT_NO_TRANSLATION obj->defineDefaultProperty(QStringLiteral("qsTranslate"), QV4::GlobalExtensions::method_qsTranslate); obj->defineDefaultProperty(QStringLiteral("QT_TRANSLATE_NOOP"), QV4::GlobalExtensions::method_qsTranslateNoOp); @@ -281,7 +280,7 @@ void QJSEngine::installTranslatorFunctions(const QJSValue &object) obj->defineDefaultProperty(QStringLiteral("QT_TRID_NOOP"), QV4::GlobalExtensions::method_qsTrIdNoOp); // string prototype extension - scope.engine->stringPrototype.asObject()->defineDefaultProperty(QStringLiteral("arg"), + scope.engine->stringPrototype()->defineDefaultProperty(QStringLiteral("arg"), QV4::GlobalExtensions::method_string_arg); #endif } @@ -319,7 +318,7 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in QV4::ExecutionEngine *v4 = d->m_v4Engine; QV4::Scope scope(v4); QV4::ScopedContext ctx(scope, v4->currentContext()); - if (ctx->d() != v4->rootContext()) + if (ctx->d() != v4->rootContext()->d()) ctx = v4->pushGlobalContext(); QV4::ScopedValue result(scope); @@ -331,7 +330,7 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in result = script.run(); if (scope.engine->hasException) result = v4->catchException(); - if (ctx->d() != v4->rootContext()) + if (ctx->d() != v4->rootContext()->d()) v4->popContext(); return QJSValue(v4, result->asReturnedValue()); } @@ -414,7 +413,7 @@ QJSValue QJSEngine::globalObject() const { Q_D(const QJSEngine); QV4::Scope scope(d->m_v4Engine); - QV4::ScopedValue v(scope, d->m_v4Engine->globalObject()); + QV4::ScopedValue v(scope, d->m_v4Engine->globalObject); return QJSValue(d->m_v4Engine, v->asReturnedValue()); } diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index 50669c46a8..6d0c7cfdda 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -37,13 +37,14 @@ #include "qjsengine.h" #include "qjsvalue.h" #include "qjsvalue_p.h" -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #include "qv4object_p.h" #include "qv4functionobject_p.h" #include "qv4dateobject_p.h" #include "qv4runtime_p.h" #include "qv4variantobject_p.h" #include "qv4regexpobject_p.h" +#include "qv4errorobject_p.h" #include "private/qv8engine_p.h" #include <private/qv4mm_p.h> #include <private/qv4scopedvalue_p.h> @@ -57,7 +58,6 @@ \ingroup qtjavascript \inmodule QtQml - \mainclass QJSValue supports the types defined in the \l{ECMA-262} standard: The primitive types, which are Undefined, Null, Boolean, @@ -317,8 +317,7 @@ bool QJSValue::isError() const QV4::Value *val = QJSValuePrivate::getValue(this); if (!val) return false; - Object *o = val->asObject(); - return o && o->asErrorObject(); + return val->as<ErrorObject>(); } /*! @@ -332,7 +331,7 @@ bool QJSValue::isArray() const QV4::Value *val = QJSValuePrivate::getValue(this); if (!val) return false; - return val->asArrayObject(); + return val->as<ArrayObject>(); } /*! @@ -349,7 +348,7 @@ bool QJSValue::isObject() const QV4::Value *val = QJSValuePrivate::getValue(this); if (!val) return false; - return val->asObject(); + return val->as<Object>(); } /*! @@ -363,7 +362,7 @@ bool QJSValue::isCallable() const QV4::Value *val = QJSValuePrivate::getValue(this); if (!val) return false; - return val->asFunctionObject(); + return val->as<FunctionObject>(); } /*! @@ -589,7 +588,7 @@ QVariant QJSValue::toVariant() const QV4::Value *val = QJSValuePrivate::valueForData(this, &scratch); Q_ASSERT(val); - if (Object *o = val->asObject()) + if (Object *o = val->as<Object>()) return o->engine()->toVariant(*val, /*typeHint*/ -1, /*createJSValueForObjects*/ false); if (val->isString()) @@ -628,7 +627,7 @@ QJSValue QJSValue::call(const QJSValueList &args) if (!val) return QJSValue(); - FunctionObject *f = val->asFunctionObject(); + FunctionObject *f = val->as<FunctionObject>(); if (!f) return QJSValue(); @@ -637,7 +636,7 @@ QJSValue QJSValue::call(const QJSValueList &args) Scope scope(engine); ScopedCallData callData(scope, args.length()); - callData->thisObject = engine->globalObject()->asReturnedValue(); + callData->thisObject = engine->globalObject; for (int i = 0; i < args.size(); ++i) { if (!QJSValuePrivate::checkEngine(engine, args.at(i))) { qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine"); @@ -679,7 +678,7 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList if (!val) return QJSValue(); - FunctionObject *f = val->asFunctionObject(); + FunctionObject *f = val->as<FunctionObject>(); if (!f) return QJSValue(); @@ -733,7 +732,7 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args) if (!val) return QJSValue(); - FunctionObject *f = val->asFunctionObject(); + FunctionObject *f = val->as<FunctionObject>(); if (!f) return QJSValue(); @@ -789,7 +788,7 @@ QJSValue QJSValue::prototype() const if (!engine) return QJSValue(); QV4::Scope scope(engine); - ScopedObject o(scope, QJSValuePrivate::getValue(this)->asObject()); + ScopedObject o(scope, QJSValuePrivate::getValue(this)->as<Object>()); if (!o) return QJSValue(); ScopedObject p(scope, o->prototype()); @@ -1029,7 +1028,7 @@ QJSValue QJSValue::property(quint32 arrayIndex) const if (!o) return QJSValue(); - QV4::ScopedValue result(scope, arrayIndex == UINT_MAX ? o->get(engine->id_uintMax) : o->getIndexed(arrayIndex)); + QV4::ScopedValue result(scope, arrayIndex == UINT_MAX ? o->get(engine->id_uintMax()) : o->getIndexed(arrayIndex)); if (engine->hasException) engine->catchException(); return QJSValue(engine, result->asReturnedValue()); @@ -1108,7 +1107,7 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value) if (arrayIndex != UINT_MAX) o->putIndexed(arrayIndex, v); else - o->put(engine->id_uintMax, v); + o->put(engine->id_uintMax(), v); if (engine->hasException) engine->catchException(); } @@ -1224,7 +1223,7 @@ QDateTime QJSValue::toDateTime() const { QV4::Value *val = QJSValuePrivate::getValue(this); if (val) { - QV4::DateObject *date = val->asDateObject(); + QV4::DateObject *date = val->as<DateObject>(); if (date) return date->toQDateTime(); } @@ -1238,7 +1237,7 @@ QDateTime QJSValue::toDateTime() const bool QJSValue::isDate() const { QV4::Value *val = QJSValuePrivate::getValue(this); - return val && val->asDateObject(); + return val && val->as<DateObject>(); } /*! diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h index 93a28a4a5f..08dc184412 100644 --- a/src/qml/jsapi/qjsvalue_p.h +++ b/src/qml/jsapi/qjsvalue_p.h @@ -47,7 +47,7 @@ #include <qjsvalue.h> #include <private/qtqmlglobal_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4string_p.h> #include <private/qv4engine_p.h> #include <private/qv4object_p.h> diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp index 1ee4121f5c..a24953ae3f 100644 --- a/src/qml/jsapi/qjsvalueiterator.cpp +++ b/src/qml/jsapi/qjsvalueiterator.cpp @@ -52,9 +52,6 @@ QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v) QV4::Scope scope(e); QV4::ScopedObject o(scope, QJSValuePrivate::getValue(&v)); iterator.set(e, e->newForEachIteratorObject(o)); - - currentName = (QV4::String *)0; - nextName = (QV4::String *)0; } @@ -102,8 +99,10 @@ QJSValueIterator::QJSValueIterator(const QJSValue& object) QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value()); it->d()->it.flags = QV4::ObjectIterator::NoFlags; QV4::ScopedString nm(scope); - it->d()->it.next(nm.getRef(), &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes); - d_ptr->nextName = nm; + QV4::Property nextProperty; + QV4::PropertyAttributes nextAttributes; + it->d()->it.next(nm.getRef(), &d_ptr->nextIndex, &nextProperty, &nextAttributes); + d_ptr->nextName.set(v4, nm.asReturnedValue()); } /*! @@ -125,7 +124,7 @@ bool QJSValueIterator::hasNext() const QV4::Value *val = QJSValuePrivate::getValue(&d_ptr->value); if (!val || !val->isObject()) return false; - return !!d_ptr->nextName || d_ptr->nextIndex != UINT_MAX; + return d_ptr->nextName.as<QV4::String>() || d_ptr->nextIndex != UINT_MAX; } /*! @@ -143,8 +142,6 @@ bool QJSValueIterator::next() return false; d_ptr->currentName = d_ptr->nextName; d_ptr->currentIndex = d_ptr->nextIndex; - d_ptr->currentProperty.copy(&d_ptr->nextProperty, d_ptr->nextAttributes); - d_ptr->currentAttributes = d_ptr->nextAttributes; QV4::ExecutionEngine *v4 = d_ptr->iterator.engine(); if (!v4) @@ -152,9 +149,11 @@ bool QJSValueIterator::next() QV4::Scope scope(v4); QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value()); QV4::ScopedString nm(scope); - it->d()->it.next(nm.getRef(), &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes); - d_ptr->nextName = nm; - return !!d_ptr->currentName || d_ptr->currentIndex != UINT_MAX; + QV4::Property nextProperty; + QV4::PropertyAttributes nextAttributes; + it->d()->it.next(nm.getRef(), &d_ptr->nextIndex, &nextProperty, &nextAttributes); + d_ptr->nextName.set(v4, nm.asReturnedValue()); + return d_ptr->currentName.as<QV4::String>() || d_ptr->currentIndex != UINT_MAX; } /*! @@ -168,8 +167,8 @@ QString QJSValueIterator::name() const QV4::Value *val = QJSValuePrivate::getValue(&d_ptr->value); if (!val || !val->isObject()) return QString(); - if (!!d_ptr->currentName) - return d_ptr->currentName->toQString(); + if (QV4::String *s = d_ptr->currentName.as<QV4::String>()) + return s->toQString(); if (d_ptr->currentIndex < UINT_MAX) return QString::number(d_ptr->currentIndex); return QString(); @@ -192,10 +191,10 @@ QJSValue QJSValueIterator::value() const if (!obj) return QJSValue(); - if (!d_ptr->currentName && d_ptr->currentIndex == UINT_MAX) + if (!d_ptr->currentName.as<QV4::String>() && d_ptr->currentIndex == UINT_MAX) return QJSValue(); - QV4::ScopedValue v(scope, obj->getValue(*obj, &d_ptr->currentProperty, d_ptr->currentAttributes)); + QV4::ScopedValue v(scope, d_ptr->currentIndex == UINT_MAX ? obj->get(d_ptr->currentName.as<QV4::String>()) : obj->getIndexed(d_ptr->currentIndex)); if (scope.hasException()) { engine->catchException(); return QJSValue(); @@ -214,8 +213,8 @@ QJSValueIterator& QJSValueIterator::operator=(QJSValue& object) d_ptr->value = object; d_ptr->currentIndex = UINT_MAX; d_ptr->nextIndex = UINT_MAX; - d_ptr->currentName = (QV4::String *)0; - d_ptr->nextName = (QV4::String *)0; + d_ptr->currentName.clear(); + d_ptr->nextName.clear(); QV4::ExecutionEngine *v4 = d_ptr->iterator.engine(); if (!v4) { d_ptr->iterator.clear(); @@ -228,8 +227,10 @@ QJSValueIterator& QJSValueIterator::operator=(QJSValue& object) QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value()); it->d()->it.flags = QV4::ObjectIterator::NoFlags; QV4::ScopedString nm(scope); - it->d()->it.next(nm.getRef(), &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes); - d_ptr->nextName = nm; + QV4::Property nextProperty; + QV4::PropertyAttributes nextAttributes; + it->d()->it.next(nm.getRef(), &d_ptr->nextIndex, &nextProperty, &nextAttributes); + d_ptr->nextName.set(v4, nm.asReturnedValue()); return *this; } diff --git a/src/qml/jsapi/qjsvalueiterator_p.h b/src/qml/jsapi/qjsvalueiterator_p.h index c17fedf73e..b0d0b2efda 100644 --- a/src/qml/jsapi/qjsvalueiterator_p.h +++ b/src/qml/jsapi/qjsvalueiterator_p.h @@ -48,15 +48,9 @@ public: QJSValue value; QV4::PersistentValue iterator; - // ### GC - QV4::Property currentProperty; - QV4::PropertyAttributes currentAttributes; - QV4::StringValue currentName; + QV4::PersistentValue currentName; uint currentIndex; - // ### GC - QV4::Property nextProperty; - QV4::PropertyAttributes nextAttributes; - QV4::StringValue nextName; + QV4::PersistentValue nextName; uint nextIndex; }; diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index ef44ca6f4d..5ffdebe328 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -10,7 +10,6 @@ SOURCES += \ $$PWD/qv4lookup.cpp \ $$PWD/qv4identifier.cpp \ $$PWD/qv4identifiertable.cpp \ - $$PWD/qv4mm.cpp \ $$PWD/qv4managed.cpp \ $$PWD/qv4internalclass.cpp \ $$PWD/qv4sparsearray.cpp \ @@ -40,7 +39,6 @@ SOURCES += \ $$PWD/qv4sequenceobject.cpp \ $$PWD/qv4include.cpp \ $$PWD/qv4qobjectwrapper.cpp \ - $$PWD/qv4qmlextensions.cpp \ $$PWD/qv4vme_moth.cpp \ $$PWD/qv4profiling.cpp \ $$PWD/qv4arraybuffer.cpp \ @@ -57,7 +55,6 @@ HEADERS += \ $$PWD/qv4lookup_p.h \ $$PWD/qv4identifier_p.h \ $$PWD/qv4identifiertable_p.h \ - $$PWD/qv4mm_p.h \ $$PWD/qv4managed_p.h \ $$PWD/qv4internalclass_p.h \ $$PWD/qv4sparsearray_p.h \ @@ -90,7 +87,6 @@ HEADERS += \ $$PWD/qv4sequenceobject_p.h \ $$PWD/qv4include_p.h \ $$PWD/qv4qobjectwrapper_p.h \ - $$PWD/qv4qmlextensions_p.h \ $$PWD/qv4vme_moth_p.h \ $$PWD/qv4profiling_p.h \ $$PWD/qv4arraybuffer_p.h \ @@ -102,7 +98,7 @@ HEADERS += \ HEADERS += \ $$PWD/qv4runtime_p.h \ - $$PWD/qv4value_inl_p.h \ + $$PWD/qv4value_p.h \ $$PWD/qv4string_p.h \ $$PWD/qv4value_p.h diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 92c77570af..39dce8efe0 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -33,6 +33,7 @@ #include <qv4argumentsobject_p.h> #include <qv4alloca_p.h> #include <qv4scopedvalue_p.h> +#include "qv4string_p.h" using namespace QV4; @@ -40,11 +41,11 @@ DEFINE_OBJECT_VTABLE(ArgumentsObject); Heap::ArgumentsObject::ArgumentsObject(QV4::CallContext *context) : Heap::Object(context->d()->strictMode ? context->d()->engine->strictArgumentsObjectClass : context->d()->engine->argumentsObjectClass, - context->d()->engine->objectPrototype.asObject()) + context->d()->engine->objectPrototype()) , context(context->d()) , fullyCreated(false) { - Q_ASSERT(vtable == QV4::ArgumentsObject::staticVTable()); + Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable()); ExecutionEngine *v4 = context->d()->engine; Scope scope(v4); @@ -53,21 +54,21 @@ Heap::ArgumentsObject::ArgumentsObject(QV4::CallContext *context) 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)); - args->propertyAt(CalleePropertyIndex)->value = v4->thrower; - args->propertyAt(CalleePropertyIndex)->set = v4->thrower; - args->propertyAt(CallerPropertyIndex)->value = v4->thrower; - args->propertyAt(CallerPropertyIndex)->set = v4->thrower; + Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); + Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(context->d()->engine->id_caller())); + args->propertyAt(CalleePropertyIndex)->value = v4->thrower(); + args->propertyAt(CalleePropertyIndex)->set = v4->thrower(); + args->propertyAt(CallerPropertyIndex)->value = v4->thrower(); + args->propertyAt(CallerPropertyIndex)->set = v4->thrower(); args->arrayReserve(context->argc()); args->arrayPut(0, context->args(), context->argc()); args->d()->fullyCreated = true; } else { - Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee)); + Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); args->memberData()->data[CalleePropertyIndex] = context->d()->function->asReturnedValue(); } - Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length)); + Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length())); args->memberData()->data[LengthPropertyIndex] = Primitive::fromInt32(context->d()->callData->argc); } @@ -144,9 +145,9 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con return result; } -ReturnedValue ArgumentsObject::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue ArgumentsObject::getIndexed(const Managed *m, uint index, bool *hasProperty) { - ArgumentsObject *args = static_cast<ArgumentsObject *>(m); + const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m); if (args->fullyCreated()) return Object::getIndexed(m, index, hasProperty); @@ -199,11 +200,11 @@ PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index) DEFINE_OBJECT_VTABLE(ArgumentsGetterFunction); -ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData) +ReturnedValue ArgumentsGetterFunction::call(const Managed *getter, CallData *callData) { - ExecutionEngine *v4 = static_cast<ArgumentsGetterFunction *>(getter)->engine(); + ExecutionEngine *v4 = static_cast<const ArgumentsGetterFunction *>(getter)->engine(); Scope scope(v4); - Scoped<ArgumentsGetterFunction> g(scope, static_cast<ArgumentsGetterFunction *>(getter)); + Scoped<ArgumentsGetterFunction> g(scope, static_cast<const ArgumentsGetterFunction *>(getter)); Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); if (!o) return v4->throwTypeError(); @@ -214,11 +215,11 @@ ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData) DEFINE_OBJECT_VTABLE(ArgumentsSetterFunction); -ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData) +ReturnedValue ArgumentsSetterFunction::call(const Managed *setter, CallData *callData) { - ExecutionEngine *v4 = static_cast<ArgumentsSetterFunction *>(setter)->engine(); + ExecutionEngine *v4 = static_cast<const ArgumentsSetterFunction *>(setter)->engine(); Scope scope(v4); - Scoped<ArgumentsSetterFunction> s(scope, static_cast<ArgumentsSetterFunction *>(setter)); + Scoped<ArgumentsSetterFunction> s(scope, static_cast<const ArgumentsSetterFunction *>(setter)); Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); if (!o) return v4->throwTypeError(); diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index 43cd6d1dee..aab5e2c156 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -59,9 +59,9 @@ struct ArgumentsObject : Object { CallerPropertyIndex = 3 }; ArgumentsObject(QV4::CallContext *context); - CallContext *context; + Pointer<CallContext> context; bool fullyCreated; - MemberData *mappedArguments; + Pointer<MemberData> mappedArguments; }; } @@ -71,7 +71,7 @@ struct ArgumentsGetterFunction: FunctionObject V4_OBJECT2(ArgumentsGetterFunction, FunctionObject) uint index() const { return d()->index; } - static ReturnedValue call(Managed *that, CallData *d); + static ReturnedValue call(const Managed *that, CallData *d); }; inline @@ -86,7 +86,7 @@ struct ArgumentsSetterFunction: FunctionObject V4_OBJECT2(ArgumentsSetterFunction, FunctionObject) uint index() const { return d()->index; } - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; inline @@ -106,12 +106,12 @@ struct ArgumentsObject: Object { Heap::MemberData *mappedArguments() { return d()->mappedArguments; } static bool isNonStrictArgumentsObject(Managed *m) { - return m->d()->vtable->type == Type_ArgumentsObject && + return m->d()->vtable()->type == Type_ArgumentsObject && !static_cast<ArgumentsObject *>(m)->context()->strictMode; } bool defineOwnProperty(ExecutionEngine *engine, uint index, const Property *desc, PropertyAttributes attrs); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); static void putIndexed(Managed *m, uint index, const Value &value); static bool deleteIndexedProperty(Managed *m, uint index); static PropertyAttributes queryIndexed(const Managed *m, uint index); diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp index dc65b5d21a..23c9695cf4 100644 --- a/src/qml/jsruntime/qv4arraybuffer.cpp +++ b/src/qml/jsruntime/qv4arraybuffer.cpp @@ -33,6 +33,7 @@ #include "qv4arraybuffer_p.h" #include "qv4typedarray_p.h" #include "qv4dataview_p.h" +#include "qv4string_p.h" using namespace QV4; @@ -44,9 +45,9 @@ Heap::ArrayBufferCtor::ArrayBufferCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ArrayBufferCtor::construct(Managed *m, CallData *callData) +ReturnedValue ArrayBufferCtor::construct(const Managed *m, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(m)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(m)->engine(); Scope scope(v4); ScopedValue l(scope, callData->argument(0)); @@ -64,7 +65,7 @@ ReturnedValue ArrayBufferCtor::construct(Managed *m, CallData *callData) } -ReturnedValue ArrayBufferCtor::call(Managed *that, CallData *callData) +ReturnedValue ArrayBufferCtor::call(const Managed *that, CallData *callData) { return construct(that, callData); } @@ -83,7 +84,7 @@ ReturnedValue ArrayBufferCtor::method_isView(CallContext *ctx) Heap::ArrayBuffer::ArrayBuffer(ExecutionEngine *e, size_t length) - : Heap::Object(e->emptyClass, e->arrayBufferPrototype.asObject()) + : Heap::Object(e->emptyClass, e->arrayBufferPrototype()) { data = QTypedArrayData<char>::allocate(length + 1); if (!data) { @@ -96,7 +97,7 @@ Heap::ArrayBuffer::ArrayBuffer(ExecutionEngine *e, size_t length) } Heap::ArrayBuffer::ArrayBuffer(ExecutionEngine *e, const QByteArray& array) - : Heap::Object(e->emptyClass, e->arrayBufferPrototype.asObject()) + : Heap::Object(e->emptyClass, e->arrayBufferPrototype()) , data(const_cast<QByteArray&>(array).data_ptr()) { data->ref.ref(); @@ -138,10 +139,10 @@ void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); ctor->defineDefaultProperty(QStringLiteral("isView"), ArrayBufferCtor::method_isView, 1); - defineDefaultProperty(engine->id_constructor, (o = ctor)); + defineDefaultProperty(engine->id_constructor(), (o = ctor)); defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); defineDefaultProperty(QStringLiteral("slice"), method_slice, 2); } @@ -172,7 +173,7 @@ ReturnedValue ArrayBufferPrototype::method_slice(CallContext *ctx) double first = (start < 0) ? qMax(a->d()->data->size + start, 0.) : qMin(start, (double)a->d()->data->size); double final = (end < 0) ? qMax(a->d()->data->size + end, 0.) : qMin(end, (double)a->d()->data->size); - ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor)); + ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor())); if (!constructor) return scope.engine->throwTypeError(); diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h index fe3150618d..a7f9e92c80 100644 --- a/src/qml/jsruntime/qv4arraybuffer_p.h +++ b/src/qml/jsruntime/qv4arraybuffer_p.h @@ -61,8 +61,8 @@ struct ArrayBufferCtor: FunctionObject { V4_OBJECT2(ArrayBufferCtor, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); static ReturnedValue method_isView(CallContext *ctx); diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index afcfa00905..da91db6aae 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -33,13 +33,14 @@ #include "qv4arraydata_p.h" #include "qv4object_p.h" #include "qv4functionobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4runtime_p.h" #include "qv4argumentsobject_p.h" +#include "qv4string_p.h" using namespace QV4; -const QV4::ManagedVTable QV4::ArrayData::static_vtbl = { +const QV4::VTable QV4::ArrayData::static_vtbl = { 0, QV4::ArrayData::IsExecutionContext, QV4::ArrayData::IsString, @@ -90,6 +91,13 @@ const ArrayVTable SparseArrayData::static_vtbl = Q_STATIC_ASSERT(sizeof(Heap::ArrayData) == sizeof(Heap::SimpleArrayData)); Q_STATIC_ASSERT(sizeof(Heap::ArrayData) == sizeof(Heap::SparseArrayData)); +static Q_ALWAYS_INLINE void storeValue(ReturnedValue *target, uint value) +{ + Value v = Value::fromReturnedValue(*target); + v.setValue(value); + *target = v.asReturnedValue(); +} + void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAttributes) { Scope scope(o->engine()); @@ -165,7 +173,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt Heap::SparseArrayData *sparse = static_cast<Heap::SparseArrayData *>(newData->d()); - uint *lastFree; + ReturnedValue *lastFree; if (d && d->type() == Heap::ArrayData::Sparse) { Heap::SparseArrayData *old = static_cast<Heap::SparseArrayData *>(d->d()); sparse->sparse = old->sparse; @@ -180,20 +188,20 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt SparseArrayNode *n = sparse->sparse->insert(i); n->value = i; } else { - *lastFree = i; - sparse->arrayData[i].tag = Value::Empty_Type; - lastFree = &sparse->arrayData[i].uint_32; + storeValue(lastFree, i); + sparse->arrayData[i].setTag(Value::Empty_Type); + lastFree = &sparse->arrayData[i].rawValueRef(); } } } if (toCopy < sparse->alloc) { for (uint i = toCopy; i < sparse->alloc; ++i) { - *lastFree = i; - sparse->arrayData[i].tag = Value::Empty_Type; - lastFree = &sparse->arrayData[i].uint_32; + storeValue(lastFree, i); + sparse->arrayData[i].setTag(Value::Empty_Type); + lastFree = &sparse->arrayData[i].rawValueRef(); } - *lastFree = UINT_MAX; + storeValue(lastFree, UINT_MAX); } // ### Could explicitly free the old data } @@ -230,7 +238,7 @@ ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index) bool SimpleArrayData::put(Object *o, uint index, const Value &value) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); Q_ASSERT(index >= dd->len || !dd->attrs || !dd->attrs[index].isAccessor()); // ### honour attributes dd->data(index) = value; @@ -244,7 +252,7 @@ bool SimpleArrayData::put(Object *o, uint index, const Value &value) bool SimpleArrayData::del(Object *o, uint index) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (index >= dd->len) return true; @@ -266,12 +274,12 @@ void SimpleArrayData::setAttribute(Object *o, uint index, PropertyAttributes att void SimpleArrayData::push_front(Object *o, const Value *values, uint n) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); Q_ASSERT(!dd->attrs); if (dd->len + n > dd->alloc) { realloc(o, Heap::ArrayData::Simple, dd->len + n, false); Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Simple); - dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } dd->offset = (dd->offset - n) % dd->alloc; dd->len += n; @@ -281,7 +289,7 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n) ReturnedValue SimpleArrayData::pop_front(Object *o) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); Q_ASSERT(!dd->attrs); if (!dd->len) return Encode::undefined(); @@ -294,7 +302,7 @@ ReturnedValue SimpleArrayData::pop_front(Object *o) uint SimpleArrayData::truncate(Object *o, uint newLen) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (dd->len < newLen) return newLen; @@ -318,10 +326,10 @@ uint SimpleArrayData::length(const Heap::ArrayData *d) bool SimpleArrayData::putArray(Object *o, uint index, const Value *values, uint n) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (index + n > dd->alloc) { reallocate(o, index + n + 1, false); - dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } for (uint i = dd->len; i < index; ++i) dd->data(i) = Primitive::emptyValue(); @@ -337,13 +345,10 @@ void SparseArrayData::free(Heap::ArrayData *d, uint idx) Value *v = d->arrayData + idx; if (d->attrs && d->attrs[idx].isAccessor()) { // double slot, free both. Order is important, so we have a double slot for allocation again afterwards. - v[1].tag = Value::Empty_Type; - v[1].uint_32 = d->freeList; - v[0].tag = Value::Empty_Type; - v[0].uint_32 = idx + 1; + v[1].setTagValue(Value::Empty_Type, Value::fromReturnedValue(d->freeList).value()); + v[0].setTagValue(Value::Empty_Type, idx + 1); } else { - v->tag = Value::Empty_Type; - v->uint_32 = d->freeList; + v->setTagValue(Value::Empty_Type, Value::fromReturnedValue(d->freeList).value()); } d->freeList = idx; if (d->attrs) @@ -369,35 +374,37 @@ Heap::ArrayData *SparseArrayData::reallocate(Object *o, uint n, bool enforceAttr uint SparseArrayData::allocate(Object *o, bool doubleSlot) { Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Sparse); - Heap::SparseArrayData *dd = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (doubleSlot) { - uint *last = &dd->freeList; + ReturnedValue *last = &dd->freeList; while (1) { - if (*last == UINT_MAX) { + if (Value::fromReturnedValue(*last).value() == UINT_MAX) { reallocate(o, dd->alloc + 2, true); - dd = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); last = &dd->freeList; - Q_ASSERT(*last != UINT_MAX); + Q_ASSERT(Value::fromReturnedValue(*last).value() != UINT_MAX); } - Q_ASSERT(dd->arrayData[*last].uint_32 != *last); - if (dd->arrayData[*last].uint_32 == (*last + 1)) { + Q_ASSERT(dd->arrayData[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value()); + if (dd->arrayData[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) { // found two slots in a row - uint idx = *last; - *last = dd->arrayData[*last + 1].uint_32; + uint idx = Value::fromReturnedValue(*last).uint_32(); + Value lastV = Value::fromReturnedValue(*last); + lastV.setValue(dd->arrayData[lastV.value() + 1].value()); + *last = lastV.rawValue(); dd->attrs[idx] = Attr_Accessor; return idx; } - last = &dd->arrayData[*last].uint_32; + last = &dd->arrayData[Value::fromReturnedValue(*last).value()].rawValueRef(); } } else { - if (dd->freeList == UINT_MAX) { + if (Value::fromReturnedValue(dd->freeList).value() == UINT_MAX) { reallocate(o, dd->alloc + 1, false); - dd = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } - uint idx = dd->freeList; + uint idx = Value::fromReturnedValue(dd->freeList).value(); Q_ASSERT(idx != UINT_MAX); - dd->freeList = dd->arrayData[idx].uint_32; + dd->freeList = dd->arrayData[idx].uint_32(); if (dd->attrs) dd->attrs[idx] = Attr_Data; return idx; @@ -418,12 +425,12 @@ bool SparseArrayData::put(Object *o, uint index, const Value &value) if (value.isEmpty()) return true; - Heap::SparseArrayData *s = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *s = o->d()->arrayData.cast<Heap::SparseArrayData>(); SparseArrayNode *n = s->sparse->insert(index); Q_ASSERT(n->value == UINT_MAX || !s->attrs || !s->attrs[n->value].isAccessor()); if (n->value == UINT_MAX) n->value = allocate(o); - s = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + s = o->d()->arrayData.cast<Heap::SparseArrayData>(); s->arrayData[n->value] = value; if (s->attrs) s->attrs[n->value] = Attr_Data; @@ -432,7 +439,7 @@ bool SparseArrayData::put(Object *o, uint index, const Value &value) bool SparseArrayData::del(Object *o, uint index) { - Heap::SparseArrayData *dd = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *dd = o->d()->arrayData.cast<Heap::SparseArrayData>(); SparseArrayNode *n = dd->sparse->findNode(index); if (!n) @@ -452,13 +459,10 @@ bool SparseArrayData::del(Object *o, uint index) if (isAccessor) { // free up both indices - dd->arrayData[pidx + 1].tag = Value::Empty_Type; - dd->arrayData[pidx + 1].uint_32 = dd->freeList; - dd->arrayData[pidx].tag = Value::Undefined_Type; - dd->arrayData[pidx].uint_32 = pidx + 1; + dd->arrayData[pidx + 1].setTagValue(Value::Empty_Type, Value::fromReturnedValue(dd->freeList).value()); + dd->arrayData[pidx].setTagValue(Value::Undefined_Type, pidx + 1); } else { - dd->arrayData[pidx].tag = Value::Empty_Type; - dd->arrayData[pidx].uint_32 = dd->freeList; + dd->arrayData[pidx].setTagValue(Value::Empty_Type, Value::fromReturnedValue(dd->freeList).value()); } dd->freeList = pidx; @@ -468,28 +472,28 @@ bool SparseArrayData::del(Object *o, uint index) void SparseArrayData::setAttribute(Object *o, uint index, PropertyAttributes attrs) { - Heap::SparseArrayData *d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>(); SparseArrayNode *n = d->sparse->insert(index); if (n->value == UINT_MAX) { n->value = allocate(o, attrs.isAccessor()); - d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + d = o->d()->arrayData.cast<Heap::SparseArrayData>(); } else if (attrs.isAccessor() != d->attrs[n->value].isAccessor()) { // need to convert the slot free(o->arrayData(), n->value); n->value = allocate(o, attrs.isAccessor()); - d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + d = o->d()->arrayData.cast<Heap::SparseArrayData>(); } d->attrs[n->value] = attrs; } void SparseArrayData::push_front(Object *o, const Value *values, uint n) { - Heap::SparseArrayData *d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>(); Q_ASSERT(!d->attrs); for (int i = n - 1; i >= 0; --i) { uint idx = allocate(o); - d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + d = o->d()->arrayData.cast<Heap::SparseArrayData>(); d->arrayData[idx] = values[i]; d->sparse->push_front(idx); } @@ -497,7 +501,7 @@ void SparseArrayData::push_front(Object *o, const Value *values, uint n) ReturnedValue SparseArrayData::pop_front(Object *o) { - Heap::SparseArrayData *d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>(); Q_ASSERT(!d->attrs); uint idx = d->sparse->pop_front(); ReturnedValue v; @@ -512,7 +516,7 @@ ReturnedValue SparseArrayData::pop_front(Object *o) uint SparseArrayData::truncate(Object *o, uint newLen) { - Heap::SparseArrayData *d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>(); SparseArrayNode *begin = d->sparse->lowerBound(newLen); if (begin != d->sparse->end()) { SparseArrayNode *it = d->sparse->end()->previousNode(); @@ -606,11 +610,11 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n) Property *ArrayData::insert(Object *o, uint index, bool isAccessor) { if (!isAccessor && o->d()->arrayData->type != Heap::ArrayData::Sparse) { - Heap::SimpleArrayData *d = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *d = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (index < 0x1000 || index < d->len + (d->len >> 2)) { if (index >= d->alloc) { o->arrayReserve(index + 1); - d = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + d = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } if (index >= d->len) { // mark possible hole in the array @@ -623,11 +627,11 @@ Property *ArrayData::insert(Object *o, uint index, bool isAccessor) } o->initSparseArray(); - Heap::SparseArrayData *s = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *s = o->d()->arrayData.cast<Heap::SparseArrayData>(); SparseArrayNode *n = s->sparse->insert(index); if (n->value == UINT_MAX) n->value = SparseArrayData::allocate(o, isAccessor); - s = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + s = o->d()->arrayData.cast<Heap::SparseArrayData>(); return reinterpret_cast<Property *>(s->arrayData + n->value); } @@ -737,7 +741,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c if (!arrayData || !arrayData->length()) return; - if (!(comparefn.isUndefined() || comparefn.asObject())) { + if (!(comparefn.isUndefined() || comparefn.as<Object>())) { engine->throwTypeError(); return; } @@ -755,7 +759,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c thisObject->setArrayData(0); ArrayData::realloc(thisObject, Heap::ArrayData::Simple, sparse->sparse()->nEntries(), sparse->attrs() ? true : false); - Heap::SimpleArrayData *d = static_cast<Heap::SimpleArrayData *>(thisObject->d()->arrayData); + Heap::SimpleArrayData *d = thisObject->d()->arrayData.cast<Heap::SimpleArrayData>(); SparseArrayNode *n = sparse->sparse()->begin(); uint i = 0; @@ -795,7 +799,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c } } else { - Heap::SimpleArrayData *d = static_cast<Heap::SimpleArrayData *>(thisObject->d()->arrayData); + Heap::SimpleArrayData *d = thisObject->d()->arrayData.cast<Heap::SimpleArrayData>(); if (len > d->len) len = d->len; diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index 915e862bbb..729e657b1a 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -47,17 +47,17 @@ namespace QV4 { Q_MANAGED_CHECK \ typedef QV4::Heap::DataClass Data; \ static const QV4::ArrayVTable static_vtbl; \ - static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl.managedVTable; } \ + static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \ V4_MANAGED_SIZE_TEST \ - const Data *d() const { return static_cast<const Data *>(m); } \ - Data *d() { return static_cast<Data *>(m); } + const Data *d() const { return static_cast<const Data *>(m()); } \ + Data *d() { return static_cast<Data *>(m()); } struct ArrayData; struct ArrayVTable { - ManagedVTable managedVTable; + VTable vTable; uint type; Heap::ArrayData *(*reallocate)(Object *o, uint n, bool enforceAttributes); ReturnedValue (*get)(const Heap::ArrayData *d, uint index); @@ -86,7 +86,7 @@ struct ArrayData : public Base { PropertyAttributes *attrs; union { uint len; - uint freeList; + ReturnedValue freeList; }; union { uint offset; @@ -96,7 +96,7 @@ struct ArrayData : public Base { bool isSparse() const { return type == Sparse; } - const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(Base::vtable); } + const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(Base::vtable()); } inline ReturnedValue get(uint i) const { return vtable()->get(this, i); @@ -239,8 +239,8 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData V4_ARRAYDATA(SparseArrayData) V4_NEEDS_DESTROY - uint &freeList() { return d()->freeList; } - uint freeList() const { return d()->freeList; } + ReturnedValue &freeList() { return d()->freeList; } + ReturnedValue freeList() const { return d()->freeList; } SparseArray *sparse() const { return d()->sparse; } void setSparse(SparseArray *s) { d()->sparse = s; } diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 231eb93dd5..25d3d9329b 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -37,6 +37,7 @@ #include "qv4scopedvalue_p.h" #include "qv4argumentsobject_p.h" #include "qv4runtime_p.h" +#include "qv4string_p.h" using namespace QV4; @@ -47,9 +48,9 @@ Heap::ArrayCtor::ArrayCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData) +ReturnedValue ArrayCtor::construct(const Managed *m, CallData *callData) { - ExecutionEngine *v4 = static_cast<ArrayCtor *>(m)->engine(); + ExecutionEngine *v4 = static_cast<const ArrayCtor *>(m)->engine(); Scope scope(v4); ScopedArrayObject a(scope, v4->newArrayObject()); uint len; @@ -72,7 +73,7 @@ ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData) return a.asReturnedValue(); } -ReturnedValue ArrayCtor::call(Managed *that, CallData *callData) +ReturnedValue ArrayCtor::call(const Managed *that, CallData *callData) { return construct(that, callData); } @@ -81,11 +82,11 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); ctor->defineDefaultProperty(QStringLiteral("isArray"), method_isArray, 1); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString, 0); + defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0); defineDefaultProperty(QStringLiteral("concat"), method_concat, 1); defineDefaultProperty(QStringLiteral("join"), method_join, 1); @@ -110,7 +111,7 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) ReturnedValue ArrayPrototype::method_isArray(CallContext *ctx) { - bool isArray = ctx->argc() && ctx->args()[0].asArrayObject(); + bool isArray = ctx->argc() && ctx->args()[0].as<ArrayObject>(); return Encode(isArray); } @@ -185,7 +186,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) r4 = arg->toQString(); ScopedObject self(scope, ctx->thisObject()); - ScopedValue length(scope, self->get(ctx->d()->engine->id_length)); + ScopedValue length(scope, self->get(ctx->d()->engine->id_length())); const quint32 r2 = length->isUndefined() ? 0 : length->toUInt32(); if (!r2) @@ -194,7 +195,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) QString R; // ### FIXME - if (ArrayObject *a = self->asArrayObject()) { + if (ArrayObject *a = self->as<ArrayObject>()) { ScopedValue e(scope); for (uint i = 0; i < a->getLength(); ++i) { if (i) @@ -242,7 +243,7 @@ ReturnedValue ArrayPrototype::method_pop(CallContext *ctx) if (!len) { if (!instance->isArrayObject()) - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromInt32(0))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0))); return Encode::undefined(); } @@ -256,7 +257,7 @@ ReturnedValue ArrayPrototype::method_pop(CallContext *ctx) if (instance->isArrayObject()) instance->setArrayLength(len - 1); else - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - 1))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1))); return result->asReturnedValue(); } @@ -282,7 +283,7 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx) } double newLen = l + ctx->argc(); if (!instance->isArrayObject()) - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))); else { ScopedString str(scope, ctx->d()->engine->newString(QStringLiteral("Array.prototype.push: Overflow"))); return ctx->engine()->throwRangeError(str); @@ -303,7 +304,7 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx) if (instance->isArrayObject()) instance->setArrayLengthUnchecked(len); else - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len))); return Encode(len); } @@ -354,7 +355,7 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx) if (!len) { if (!instance->isArrayObject()) - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromInt32(0))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0))); return Encode::undefined(); } @@ -388,7 +389,7 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx) if (instance->isArrayObject()) instance->setArrayLengthUnchecked(len - 1); else - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - 1))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1))); return result->asReturnedValue(); } @@ -523,7 +524,7 @@ ReturnedValue ArrayPrototype::method_splice(CallContext *ctx) } ctx->d()->strictMode = true; - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount))); return newArray.asReturnedValue(); } @@ -561,7 +562,7 @@ ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx) if (instance->isArrayObject()) instance->setArrayLengthUnchecked(newLen); else - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))); return Encode(newLen); } @@ -619,7 +620,7 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx) return Encode(-1); } else { Q_ASSERT(instance->arrayType() == Heap::ArrayData::Simple || instance->arrayType() == Heap::ArrayData::Complex); - Heap::SimpleArrayData *sa = static_cast<Heap::SimpleArrayData *>(instance->d()->arrayData); + Heap::SimpleArrayData *sa = instance->d()->arrayData.cast<Heap::SimpleArrayData>(); if (len > sa->len) len = sa->len; uint idx = fromIndex; diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h index 4e67eb2e31..422a0de675 100644 --- a/src/qml/jsruntime/qv4arrayobject_p.h +++ b/src/qml/jsruntime/qv4arrayobject_p.h @@ -53,8 +53,8 @@ struct ArrayCtor: FunctionObject { V4_OBJECT2(ArrayCtor, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct ArrayPrototype: ArrayObject diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp index 9c293e783b..53f8abf3f2 100644 --- a/src/qml/jsruntime/qv4booleanobject.cpp +++ b/src/qml/jsruntime/qv4booleanobject.cpp @@ -32,6 +32,7 @@ ****************************************************************************/ #include "qv4booleanobject_p.h" +#include "qv4string_p.h" using namespace QV4; @@ -43,14 +44,14 @@ Heap::BooleanCtor::BooleanCtor(QV4::ExecutionContext *scope) { } -ReturnedValue BooleanCtor::construct(Managed *m, CallData *callData) +ReturnedValue BooleanCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<BooleanCtor *>(m)->engine()); + Scope scope(static_cast<const BooleanCtor *>(m)->engine()); bool n = callData->argc ? callData->args[0].toBoolean() : false; return Encode(scope.engine->newBooleanObject(n)); } -ReturnedValue BooleanCtor::call(Managed *, CallData *callData) +ReturnedValue BooleanCtor::call(const Managed *, CallData *callData) { bool value = callData->argc ? callData->args[0].toBoolean() : 0; return Encode(value); @@ -60,11 +61,11 @@ void BooleanPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString); - defineDefaultProperty(engine->id_valueOf, method_valueOf); + defineDefaultProperty(engine->id_toString(), method_toString); + defineDefaultProperty(engine->id_valueOf(), method_valueOf); } ReturnedValue BooleanPrototype::method_toString(CallContext *ctx) @@ -73,7 +74,7 @@ ReturnedValue BooleanPrototype::method_toString(CallContext *ctx) if (ctx->thisObject().isBoolean()) { result = ctx->thisObject().booleanValue(); } else { - BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>(); + const BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>(); if (!thisObject) return ctx->engine()->throwTypeError(); result = thisObject->value(); @@ -87,7 +88,7 @@ ReturnedValue BooleanPrototype::method_valueOf(CallContext *ctx) if (ctx->thisObject().isBoolean()) return ctx->thisObject().asReturnedValue(); - BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>(); + const BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>(); if (!thisObject) return ctx->engine()->throwTypeError(); diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h index 903261bdce..77b5a74fde 100644 --- a/src/qml/jsruntime/qv4booleanobject_p.h +++ b/src/qml/jsruntime/qv4booleanobject_p.h @@ -53,8 +53,8 @@ struct BooleanCtor: FunctionObject { V4_OBJECT2(BooleanCtor, FunctionObject) - static ReturnedValue construct(Managed *, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct BooleanPrototype: BooleanObject diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 9330f10780..f50c5ab017 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -36,10 +36,12 @@ #include <qv4context_p.h> #include <qv4object_p.h> #include <qv4objectproto_p.h> -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include <qv4argumentsobject_p.h> #include "qv4function_p.h" #include "qv4errorobject_p.h" +#include "qv4string_p.h" +#include "private/qqmlcontextwrapper_p.h" using namespace QV4; @@ -48,8 +50,9 @@ DEFINE_MANAGED_VTABLE(CallContext); DEFINE_MANAGED_VTABLE(WithContext); DEFINE_MANAGED_VTABLE(CatchContext); DEFINE_MANAGED_VTABLE(GlobalContext); +DEFINE_MANAGED_VTABLE(QmlContext); -Heap::CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData) +Heap::CallContext *ExecutionContext::newCallContext(const FunctionObject *function, CallData *callData) { Q_ASSERT(function->function()); @@ -90,31 +93,37 @@ Heap::CatchContext *ExecutionContext::newCatchContext(String *exceptionVarName, return d()->engine->memoryManager->alloc<CatchContext>(d()->engine, exceptionVarName, exceptionValue); } -Heap::CallContext *ExecutionContext::newQmlContext(FunctionObject *f, Object *qml) +Heap::QmlContext *ExecutionContext::newQmlContext(QmlContextWrapper *qml) { - Scope scope(this); - Scoped<CallContext> c(scope, d()->engine->memoryManager->allocManaged<CallContext>(requiredMemoryForExecutionContect(f, 0))); - new (c->d()) Heap::CallContext(d()->engine, qml, f); - return c->d(); + return d()->engine->memoryManager->alloc<QmlContext>(this, qml); } - void ExecutionContext::createMutableBinding(String *name, bool deletable) { Scope scope(this); // find the right context to create the binding on - ScopedObject activation(scope, d()->engine->globalObject()); + ScopedObject activation(scope, d()->engine->globalObject); ScopedContext ctx(scope, this); while (ctx) { - if (ctx->d()->type >= Heap::ExecutionContext::Type_CallContext) { + switch (ctx->d()->type) { + case Heap::ExecutionContext::Type_CallContext: + case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); if (!c->activation) c->activation = scope.engine->newObject(); activation = c->activation; break; } + case Heap::ExecutionContext::Type_QmlContext: { + Heap::QmlContext *qml = static_cast<Heap::QmlContext *>(ctx->d()); + activation = qml->qml; + break; + } + default: + break; + } ctx = ctx->d()->outer; } @@ -130,7 +139,7 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) Heap::GlobalContext::GlobalContext(ExecutionEngine *eng) : Heap::ExecutionContext(eng, Heap::ExecutionContext::Type_GlobalContext) { - global = eng->globalObject()->d(); + global = eng->globalObject->d(); } Heap::WithContext::WithContext(ExecutionEngine *engine, QV4::Object *with) @@ -153,34 +162,23 @@ Heap::CatchContext::CatchContext(ExecutionEngine *engine, QV4::String *exception lookups = parent->lookups; compilationUnit = parent->compilationUnit; - this->exceptionVarName = exceptionVarName; + this->exceptionVarName = exceptionVarName->d(); this->exceptionValue = exceptionValue; } -Heap::CallContext::CallContext(ExecutionEngine *engine, QV4::Object *qml, QV4::FunctionObject *function) - : Heap::ExecutionContext(engine, Heap::ExecutionContext::Type_QmlContext) +Heap::QmlContext::QmlContext(QV4::ExecutionContext *outer, QV4::QmlContextWrapper *qml) + : Heap::ExecutionContext(outer->engine(), Heap::ExecutionContext::Type_QmlContext) { - this->function = function->d(); - callData = reinterpret_cast<CallData *>(this + 1); - callData->tag = QV4::Value::_Integer_Type; - callData->argc = 0; - callData->thisObject = Primitive::undefinedValue(); - strictMode = false; - outer = function->scope(); - - activation = qml->d(); - - if (function->function()) { - compilationUnit = function->function()->compilationUnit; - lookups = compilationUnit->runtimeLookups; - } + callData = parent->callData; + this->outer = outer->d(); + lookups = parent->lookups; + compilationUnit = parent->compilationUnit; - locals = (Value *)(this + 1); - if (function->varCount()) - std::fill(locals, locals + function->varCount(), Primitive::undefinedValue()); + this->qml = qml->d(); } + Identifier * const *CallContext::formals() const { return (d()->function && d()->function->function) ? d()->function->function->internalClass->nameMap.constData() : 0; @@ -209,16 +207,28 @@ bool ExecutionContext::deleteProperty(String *name) bool hasWith = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { - if (ctx->d()->type == Heap::ExecutionContext::Type_WithContext) { + switch (ctx->d()->type) { + case Heap::ExecutionContext::Type_CatchContext: { + Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); + if (c->exceptionVarName->isEqualTo(name->d())) + return false; + break; + } + case Heap::ExecutionContext::Type_WithContext: { hasWith = true; ScopedObject withObject(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); if (withObject->hasProperty(name)) return withObject->deleteProperty(name); - } else if (ctx->d()->type == Heap::ExecutionContext::Type_CatchContext) { - Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); - if (c->exceptionVarName->isEqualTo(name)) - return false; - } else if (ctx->d()->type >= Heap::ExecutionContext::Type_CallContext) { + break; + } + case Heap::ExecutionContext::Type_GlobalContext: { + ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); + if (global->hasProperty(name)) + return global->deleteProperty(name); + break; + } + 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) { @@ -227,13 +237,14 @@ bool ExecutionContext::deleteProperty(String *name) // ### throw in strict mode? return false; } - ScopedObject activation(scope, c->activation); - if (activation && activation->hasProperty(name)) - return activation->deleteProperty(name); - } else if (ctx->d()->type == Heap::ExecutionContext::Type_GlobalContext) { - ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); - if (global->hasProperty(name)) - return global->deleteProperty(name); + ScopedObject qml(scope, c->activation); + if (qml && qml->hasProperty(name)) + return qml->deleteProperty(name); + break; + } + case Heap::ExecutionContext::Type_QmlContext: + // can't delete properties on qml objects + break; } } @@ -254,7 +265,27 @@ void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine) if (ctx->outer) ctx->outer->mark(engine); - if (ctx->type >= Heap::ExecutionContext::Type_CallContext) { + switch (ctx->type) { + case Heap::ExecutionContext::Type_CatchContext: { + CatchContext::Data *c = static_cast<CatchContext::Data *>(ctx); + c->exceptionVarName->mark(engine); + c->exceptionValue.mark(engine); + break; + } + case Heap::ExecutionContext::Type_WithContext: { + WithContext::Data *w = static_cast<WithContext::Data *>(ctx); + if (w->withObject) + w->withObject->mark(engine); + break; + } + case Heap::ExecutionContext::Type_GlobalContext: { + GlobalContext::Data *g = static_cast<GlobalContext::Data *>(ctx); + g->global->mark(engine); + break; + } + case Heap::ExecutionContext::Type_SimpleCallContext: + break; + case Heap::ExecutionContext::Type_CallContext: { QV4::Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx); ctx->callData->thisObject.mark(engine); for (int arg = 0; arg < qMax(ctx->callData->argc, (int)c->function->formalParameterCount()); ++arg) @@ -264,17 +295,13 @@ void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine) if (c->activation) c->activation->mark(engine); c->function->mark(engine); - } else if (ctx->type == Heap::ExecutionContext::Type_WithContext) { - WithContext::Data *w = static_cast<WithContext::Data *>(ctx); - if (w->withObject) - w->withObject->mark(engine); - } else if (ctx->type == Heap::ExecutionContext::Type_CatchContext) { - CatchContext::Data *c = static_cast<CatchContext::Data *>(ctx); - c->exceptionVarName->mark(engine); - c->exceptionValue.mark(engine); - } else if (ctx->type == Heap::ExecutionContext::Type_GlobalContext) { - GlobalContext::Data *g = static_cast<GlobalContext::Data *>(ctx); - g->global->mark(engine); + break; + } + case Heap::ExecutionContext::Type_QmlContext: { + QmlContext::Data *g = static_cast<QmlContext::Data *>(ctx); + g->qml->mark(engine); + break; + } } } @@ -282,57 +309,71 @@ void ExecutionContext::setProperty(String *name, const Value &value) { Scope scope(this); ScopedContext ctx(scope, this); + ScopedObject activation(scope); + for (; ctx; ctx = ctx->d()->outer) { - if (ctx->d()->type == Heap::ExecutionContext::Type_WithContext) { + activation = (Object *)0; + switch (ctx->d()->type) { + case Heap::ExecutionContext::Type_CatchContext: { + Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); + if (c->exceptionVarName->isEqualTo(name->d())) { + c->exceptionValue = value; + return; + } + break; + } + case Heap::ExecutionContext::Type_WithContext: { ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); if (w->hasProperty(name)) { w->put(name, value); return; } - } else if (ctx->d()->type == Heap::ExecutionContext::Type_CatchContext && static_cast<Heap::CatchContext *>(ctx->d())->exceptionVarName->isEqualTo(name)) { - static_cast<Heap::CatchContext *>(ctx->d())->exceptionValue = value; - return; - } else { - ScopedObject activation(scope, (Object *)0); - if (ctx->d()->type >= Heap::ExecutionContext::Type_CallContext) { - Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - if (c->function->function) { - uint index = c->function->function->internalClass->find(name); - if (index < UINT_MAX) { - if (index < c->function->formalParameterCount()) { - c->callData->args[c->function->formalParameterCount() - index - 1] = value; - } else { - index -= c->function->formalParameterCount(); - c->locals[index] = value; - } - return; + break; + } + case Heap::ExecutionContext::Type_GlobalContext: { + activation = static_cast<Heap::GlobalContext *>(ctx->d())->global; + break; + } + 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 (index < UINT_MAX) { + if (index < c->function->formalParameterCount()) { + c->callData->args[c->function->formalParameterCount() - index - 1] = value; + } else { + index -= c->function->formalParameterCount(); + c->locals[index] = value; } + return; } - activation = c->activation; - } else if (ctx->d()->type == Heap::ExecutionContext::Type_GlobalContext) { - activation = static_cast<Heap::GlobalContext *>(ctx->d())->global; } + activation = c->activation; + break; + } + case Heap::ExecutionContext::Type_QmlContext: { + activation = static_cast<Heap::QmlContext *>(ctx->d())->qml; + activation->put(name, value); + return; + } + } - if (activation) { - if (ctx->d()->type == Heap::ExecutionContext::Type_QmlContext) { - activation->put(name, value); - return; - } else { - uint member = activation->internalClass()->find(name); - if (member < UINT_MAX) { - activation->putValue(activation->propertyAt(member), activation->internalClass()->propertyData[member], value); - return; - } - } + if (activation) { + uint member = activation->internalClass()->find(name); + if (member < UINT_MAX) { + activation->putValue(activation->propertyAt(member), activation->internalClass()->propertyData[member], value); + return; } } } - if (d()->strictMode || name->equals(d()->engine->id_this)) { + + if (d()->strictMode || name->equals(d()->engine->id_this())) { ScopedValue n(scope, name->asReturnedValue()); engine()->throwReferenceError(n); return; } - d()->engine->globalObject()->put(name, value); + d()->engine->globalObject->put(name, value); } ReturnedValue ExecutionContext::getProperty(String *name) @@ -341,14 +382,22 @@ ReturnedValue ExecutionContext::getProperty(String *name) ScopedValue v(scope); name->makeIdentifier(scope.engine); - if (name->equals(d()->engine->id_this)) + if (name->equals(d()->engine->id_this())) return thisObject().asReturnedValue(); bool hasWith = false; bool hasCatchScope = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { - if (ctx->d()->type == Heap::ExecutionContext::Type_WithContext) { + switch (ctx->d()->type) { + case Heap::ExecutionContext::Type_CatchContext: { + hasCatchScope = true; + Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); + if (c->exceptionVarName->isEqualTo(name->d())) + return c->exceptionValue.asReturnedValue(); + break; + } + case Heap::ExecutionContext::Type_WithContext: { ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); hasWith = true; bool hasProperty = false; @@ -356,17 +405,18 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (hasProperty) { return v->asReturnedValue(); } - continue; + break; } - - else if (ctx->d()->type == Heap::ExecutionContext::Type_CatchContext) { - hasCatchScope = true; - Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); - if (c->exceptionVarName->isEqualTo(name)) - return c->exceptionValue.asReturnedValue(); + case Heap::ExecutionContext::Type_GlobalContext: { + ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); + bool hasProperty = false; + v = global->get(name, &hasProperty); + if (hasProperty) + return v->asReturnedValue(); + break; } - - else if (ctx->d()->type >= Heap::ExecutionContext::Type_CallContext) { + 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)) { @@ -387,85 +437,97 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (f->function() && f->function()->isNamedExpression() && name->equals(ScopedString(scope, f->function()->name()))) return f.asReturnedValue(); + break; } - - else if (ctx->d()->type == Heap::ExecutionContext::Type_GlobalContext) { - ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); + case Heap::ExecutionContext::Type_QmlContext: { + ScopedObject qml(scope, static_cast<Heap::QmlContext *>(ctx->d())->qml); bool hasProperty = false; - v = global->get(name, &hasProperty); + v = qml->get(name, &hasProperty); if (hasProperty) return v->asReturnedValue(); + break; + } } } ScopedValue n(scope, name); return engine()->throwReferenceError(n); } -ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Heap::Object **base) +ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) { Scope scope(this); ScopedValue v(scope); - *base = (Heap::Object *)0; + base->setM(0); name->makeIdentifier(scope.engine); - if (name->equals(d()->engine->id_this)) + if (name->equals(d()->engine->id_this())) return thisObject().asReturnedValue(); bool hasWith = false; bool hasCatchScope = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { - if (ctx->d()->type == Heap::ExecutionContext::Type_WithContext) { + switch (ctx->d()->type) { + case Heap::ExecutionContext::Type_CatchContext: { + hasCatchScope = true; + Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); + if (c->exceptionVarName->isEqualTo(name->d())) + return c->exceptionValue.asReturnedValue(); + break; + } + case Heap::ExecutionContext::Type_WithContext: { ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); hasWith = true; bool hasProperty = false; v = w->get(name, &hasProperty); if (hasProperty) { - *base = w->d(); + base->setM(w->d()); return v->asReturnedValue(); } - continue; + break; } - - else if (ctx->d()->type == Heap::ExecutionContext::Type_CatchContext) { - hasCatchScope = true; - Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); - if (c->exceptionVarName->isEqualTo(name)) - return c->exceptionValue.asReturnedValue(); + case Heap::ExecutionContext::Type_GlobalContext: { + ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); + bool hasProperty = false; + v = global->get(name, &hasProperty); + if (hasProperty) + return v->asReturnedValue(); + break; } - - else if (ctx->d()->type >= Heap::ExecutionContext::Type_CallContext) { + 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 (index < UINT_MAX) { - if (index < f->formalParameterCount()) - return c->callData->args[f->formalParameterCount() - index - 1].asReturnedValue(); - return c->locals[index - f->formalParameterCount()].asReturnedValue(); + if (index < c->function->formalParameterCount()) + return c->callData->args[c->function->formalParameterCount() - index - 1].asReturnedValue(); + return c->locals[index - c->function->formalParameterCount()].asReturnedValue(); } } ScopedObject activation(scope, c->activation); if (activation) { bool hasProperty = false; v = activation->get(name, &hasProperty); - if (hasProperty) { - if (ctx->d()->type == Heap::ExecutionContext::Type_QmlContext) - *base = activation->d(); + if (hasProperty) return v->asReturnedValue(); - } } if (f->function() && f->function()->isNamedExpression() && name->equals(ScopedString(scope, f->function()->name()))) - return c->function->asReturnedValue(); + return f.asReturnedValue(); + break; } - - else if (ctx->d()->type == Heap::ExecutionContext::Type_GlobalContext) { - ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); + case Heap::ExecutionContext::Type_QmlContext: { + ScopedObject qml(scope, static_cast<Heap::QmlContext *>(ctx->d())->qml); bool hasProperty = false; - v = global->get(name, &hasProperty); - if (hasProperty) + v = qml->get(name, &hasProperty); + if (hasProperty) { + base->setM(qml->d()); return v->asReturnedValue(); + } + break; + } } } ScopedValue n(scope, name); @@ -487,3 +549,14 @@ Heap::FunctionObject *ExecutionContext::getFunctionObject() const return 0; } + + +QObject *QmlContext::qmlScope() const +{ + return d()->qml->scopeObject; +} + +QQmlContextData *QmlContext::qmlContext() const +{ + return d()->qml->context; +} diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 8392dd836d..2667bbe0b2 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -38,6 +38,9 @@ QT_BEGIN_NAMESPACE +class QQmlContextData; +class QObject; + namespace QV4 { namespace CompiledData { @@ -45,6 +48,8 @@ struct CompilationUnit; struct Function; } +struct QmlContextWrapper; +struct Identifier; struct CallContext; struct CatchContext; struct WithContext; @@ -74,9 +79,9 @@ struct ExecutionContext : Base { Type_GlobalContext = 0x1, Type_CatchContext = 0x2, Type_WithContext = 0x3, - Type_SimpleCallContext = 0x4, - Type_CallContext = 0x5, - Type_QmlContext = 0x6 + Type_QmlContext = 0x4, + Type_SimpleCallContext = 0x5, + Type_CallContext = 0x6 }; inline ExecutionContext(ExecutionEngine *engine, ContextType t); @@ -84,8 +89,8 @@ struct ExecutionContext : Base { CallData *callData; ExecutionEngine *engine; - ExecutionContext *parent; - ExecutionContext *outer; + Pointer<ExecutionContext> parent; + Pointer<ExecutionContext> outer; Lookup *lookups; CompiledData::CompilationUnit *compilationUnit; @@ -102,29 +107,34 @@ struct CallContext : ExecutionContext { locals = 0; activation = 0; } - CallContext(ExecutionEngine *engine, QV4::Object *qml, QV4::FunctionObject *function); - FunctionObject *function; + Pointer<FunctionObject> function; Value *locals; - Object *activation; + Pointer<Object> activation; }; struct GlobalContext : ExecutionContext { GlobalContext(ExecutionEngine *engine); - Object *global; + Pointer<Object> global; }; struct CatchContext : ExecutionContext { CatchContext(ExecutionEngine *engine, QV4::String *exceptionVarName, const Value &exceptionValue); - StringValue exceptionVarName; + Pointer<String> exceptionVarName; Value exceptionValue; }; struct WithContext : ExecutionContext { WithContext(ExecutionEngine *engine, QV4::Object *with); - Object *withObject; + Pointer<Object> withObject; }; +struct QmlContextWrapper; + +struct QmlContext : ExecutionContext { + QmlContext(QV4::ExecutionContext *outer, QV4::QmlContextWrapper *qml); + Pointer<QmlContextWrapper> qml; +}; } @@ -139,16 +149,16 @@ struct Q_QML_EXPORT ExecutionContext : public Managed ExecutionEngine *engine() const { return d()->engine; } - Heap::CallContext *newCallContext(FunctionObject *f, CallData *callData); + Heap::CallContext *newCallContext(const FunctionObject *f, CallData *callData); Heap::WithContext *newWithContext(Object *with); Heap::CatchContext *newCatchContext(String *exceptionVarName, const Value &exceptionValue); - Heap::CallContext *newQmlContext(FunctionObject *f, Object *qml); + Heap::QmlContext *newQmlContext(QmlContextWrapper *qml); void createMutableBinding(String *name, bool deletable); void setProperty(String *name, const Value &value); ReturnedValue getProperty(String *name); - ReturnedValue getPropertyAndBase(String *name, Heap::Object **base); + ReturnedValue getPropertyAndBase(String *name, Value *base); bool deleteProperty(String *name); inline CallContext *asCallContext(); @@ -160,7 +170,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed static void markObjects(Heap::Base *m, ExecutionEngine *e); - const Value &thisObject() const { + Value &thisObject() const { return d()->callData->thisObject; } int argc() const { @@ -174,7 +184,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed } }; -struct CallContext : public ExecutionContext +struct Q_QML_EXPORT CallContext : public ExecutionContext { V4_MANAGED(CallContext, ExecutionContext) @@ -208,6 +218,14 @@ struct WithContext : public ExecutionContext V4_MANAGED(WithContext, ExecutionContext) }; +struct QmlContext : public ExecutionContext +{ + V4_MANAGED(QmlContext, ExecutionContext) + + QObject *qmlScope() const; + QQmlContextData *qmlContext() const; +}; + inline CallContext *ExecutionContext::asCallContext() { return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<CallContext *>(this) : 0; diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp index 8a66c2cbfc..a741d61d10 100644 --- a/src/qml/jsruntime/qv4dataview.cpp +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -33,6 +33,7 @@ #include "qv4dataview_p.h" #include "qv4arraybuffer_p.h" +#include "qv4string_p.h" #include "qendian.h" @@ -46,9 +47,9 @@ Heap::DataViewCtor::DataViewCtor(QV4::ExecutionContext *scope) { } -ReturnedValue DataViewCtor::construct(Managed *m, CallData *callData) +ReturnedValue DataViewCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<Object *>(m)->engine()); + Scope scope(static_cast<const Object *>(m)->engine()); Scoped<ArrayBuffer> buffer(scope, callData->argument(0)); if (!buffer) return scope.engine->throwTypeError(); @@ -69,14 +70,14 @@ ReturnedValue DataViewCtor::construct(Managed *m, CallData *callData) } -ReturnedValue DataViewCtor::call(Managed *that, CallData *callData) +ReturnedValue DataViewCtor::call(const Managed *that, CallData *callData) { return construct(that, callData); } Heap::DataView::DataView(ExecutionEngine *e) - : Heap::Object(e->emptyClass, e->dataViewPrototype.asObject()), + : Heap::Object(e->emptyClass, e->dataViewPrototype()), buffer(0), byteLength(0), byteOffset(0) @@ -94,9 +95,9 @@ void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(3)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); - defineDefaultProperty(engine->id_constructor, (o = ctor)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(3)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + defineDefaultProperty(engine->id_constructor(), (o = ctor)); defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, 0); defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, 0); diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h index 3f0c1e9e23..e98239396a 100644 --- a/src/qml/jsruntime/qv4dataview_p.h +++ b/src/qml/jsruntime/qv4dataview_p.h @@ -48,7 +48,7 @@ struct DataViewCtor : FunctionObject { struct DataView : Object { DataView(ExecutionEngine *e); - ArrayBuffer *buffer; + Pointer<ArrayBuffer> buffer; uint byteLength; uint byteOffset; }; @@ -59,8 +59,8 @@ struct DataViewCtor: FunctionObject { V4_OBJECT2(DataViewCtor, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct DataView : Object diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 451ef2486d..3f45751695 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -36,6 +36,7 @@ #include "qv4objectproto_p.h" #include "qv4scopedvalue_p.h" #include "qv4runtime_p.h" +#include "qv4string_p.h" #include <QtCore/QDebug> #include <QtCore/QDateTime> @@ -628,14 +629,14 @@ static double getLocalTZA() DEFINE_OBJECT_VTABLE(DateObject); Heap::DateObject::DateObject(QV4::ExecutionEngine *engine, const QDateTime &date) - : Heap::Object(engine->emptyClass, engine->datePrototype.asObject()) + : Heap::Object(engine->emptyClass, engine->datePrototype()) { - value.setDouble(date.isValid() ? date.toMSecsSinceEpoch() : qSNaN()); + this->date = date.isValid() ? date.toMSecsSinceEpoch() : qSNaN(); } QDateTime DateObject::toQDateTime() const { - return ToDateTime(date().asDouble(), Qt::LocalTime); + return ToDateTime(date(), Qt::LocalTime); } DEFINE_OBJECT_VTABLE(DateCtor); @@ -645,9 +646,9 @@ Heap::DateCtor::DateCtor(QV4::ExecutionContext *scope) { } -ReturnedValue DateCtor::construct(Managed *m, CallData *callData) +ReturnedValue DateCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<DateCtor *>(m)->engine()); + Scope scope(static_cast<const DateCtor *>(m)->engine()); double t = 0; if (callData->argc == 0) @@ -655,15 +656,16 @@ ReturnedValue DateCtor::construct(Managed *m, CallData *callData) else if (callData->argc == 1) { ScopedValue arg(scope, callData->args[0]); - if (DateObject *d = arg->asDateObject()) - arg = d->date(); - else + if (DateObject *d = arg->as<DateObject>()) { + t = d->date(); + } else { arg = RuntimeHelpers::toPrimitive(arg, PREFERREDTYPE_HINT); - if (arg->isString()) - t = ParseString(arg->stringValue()->toQString()); - else - t = TimeClip(arg->toNumber()); + if (arg->isString()) + t = ParseString(arg->stringValue()->toQString()); + else + t = TimeClip(arg->toNumber()); + } } else { // d.argc > 1 @@ -683,18 +685,18 @@ ReturnedValue DateCtor::construct(Managed *m, CallData *callData) return Encode(scope.engine->newDateObject(Primitive::fromDouble(t))); } -ReturnedValue DateCtor::call(Managed *m, CallData *) +ReturnedValue DateCtor::call(const Managed *m, CallData *) { double t = currentTime(); - return static_cast<DateCtor *>(m)->engine()->newString(ToString(t))->asReturnedValue(); + return static_cast<const DateCtor *>(m)->engine()->newString(ToString(t))->asReturnedValue(); } void DatePrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(7)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(7)); LocalTZA = getLocalTZA(); ctor->defineDefaultProperty(QStringLiteral("parse"), method_parse, 1); @@ -702,13 +704,13 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor) ctor->defineDefaultProperty(QStringLiteral("now"), method_now, 0); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString, 0); + defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("toDateString"), method_toDateString, 0); defineDefaultProperty(QStringLiteral("toTimeString"), method_toTimeString, 0); defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0); defineDefaultProperty(QStringLiteral("toLocaleDateString"), method_toLocaleDateString, 0); defineDefaultProperty(QStringLiteral("toLocaleTimeString"), method_toLocaleTimeString, 0); - defineDefaultProperty(engine->id_valueOf, method_valueOf, 0); + defineDefaultProperty(engine->id_valueOf(), method_valueOf, 0); defineDefaultProperty(QStringLiteral("getTime"), method_getTime, 0); defineDefaultProperty(QStringLiteral("getYear"), method_getYear, 0); defineDefaultProperty(QStringLiteral("getFullYear"), method_getFullYear, 0); @@ -752,8 +754,8 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor) double DatePrototype::getThisDate(ExecutionContext *ctx) { - if (DateObject *thisObject = ctx->thisObject().asDateObject()) - return thisObject->date().asDouble(); + if (DateObject *thisObject = ctx->thisObject().as<DateObject>()) + return thisObject->date(); else { ctx->engine()->throwTypeError(); return 0; @@ -994,8 +996,8 @@ ReturnedValue DatePrototype::method_setTime(CallContext *ctx) return ctx->engine()->throwTypeError(); double t = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); - self->date().setDouble(TimeClip(t)); - return self->date().asReturnedValue(); + self->setDate(TimeClip(t)); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setMilliseconds(CallContext *ctx) @@ -1005,175 +1007,175 @@ ReturnedValue DatePrototype::method_setMilliseconds(CallContext *ctx) if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double ms = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); - self->date().setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); - return self->date().asReturnedValue(); + self->setDate(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCMilliseconds(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double ms = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); - self->date().setDouble(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))); - return self->date().asReturnedValue(); + self->setDate(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setSeconds(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double sec = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double ms = (ctx->argc() < 2) ? msFromTime(t) : ctx->args()[1].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCSeconds(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double sec = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double ms = (ctx->argc() < 2) ? msFromTime(t) : ctx->args()[1].toNumber(); t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setMinutes(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double min = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double sec = (ctx->argc() < 2) ? SecFromTime(t) : ctx->args()[1].toNumber(); double ms = (ctx->argc() < 3) ? msFromTime(t) : ctx->args()[2].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCMinutes(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double min = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double sec = (ctx->argc() < 2) ? SecFromTime(t) : ctx->args()[1].toNumber(); double ms = (ctx->argc() < 3) ? msFromTime(t) : ctx->args()[2].toNumber(); t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setHours(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double hour = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double min = (ctx->argc() < 2) ? MinFromTime(t) : ctx->args()[1].toNumber(); double sec = (ctx->argc() < 3) ? SecFromTime(t) : ctx->args()[2].toNumber(); double ms = (ctx->argc() < 4) ? msFromTime(t) : ctx->args()[3].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCHours(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double hour = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double min = (ctx->argc() < 2) ? MinFromTime(t) : ctx->args()[1].toNumber(); double sec = (ctx->argc() < 3) ? SecFromTime(t) : ctx->args()[2].toNumber(); double ms = (ctx->argc() < 4) ? msFromTime(t) : ctx->args()[3].toNumber(); t = TimeClip(MakeDate(Day(t), MakeTime(hour, min, sec, ms))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setDate(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double date = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCDate(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double date = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); t = TimeClip(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setMonth(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double month = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double date = (ctx->argc() < 2) ? DateFromTime(t) : ctx->args()[1].toNumber(); t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCMonth(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double month = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double date = (ctx->argc() < 2) ? DateFromTime(t) : ctx->args()[1].toNumber(); t = TimeClip(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setYear(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); if (std::isnan(t)) t = 0; else @@ -1189,49 +1191,49 @@ ReturnedValue DatePrototype::method_setYear(CallContext *ctx) r = UTC(MakeDate(r, TimeWithinDay(t))); r = TimeClip(r); } - self->date().setDouble(r); - return self->date().asReturnedValue(); + self->setDate(r); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCFullYear(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double year = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double month = (ctx->argc() < 2) ? MonthFromTime(t) : ctx->args()[1].toNumber(); double date = (ctx->argc() < 3) ? DateFromTime(t) : ctx->args()[2].toNumber(); t = TimeClip(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setFullYear(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); if (std::isnan(t)) t = 0; double year = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double month = (ctx->argc() < 2) ? MonthFromTime(t) : ctx->args()[1].toNumber(); double date = (ctx->argc() < 3) ? DateFromTime(t) : ctx->args()[2].toNumber(); t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_toUTCString(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); return ctx->d()->engine->newString(ToUTCString(t))->asReturnedValue(); } @@ -1250,11 +1252,11 @@ static void addZeroPrefixedInt(QString &str, int num, int nDigits) ReturnedValue DatePrototype::method_toISOString(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); if (!std::isfinite(t)) return ctx->engine()->throwRangeError(ctx->thisObject()); @@ -1297,7 +1299,7 @@ ReturnedValue DatePrototype::method_toJSON(CallContext *ctx) ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toISOString"))); ScopedValue v(scope, O->objectValue()->get(s)); - FunctionObject *toIso = v->asFunctionObject(); + FunctionObject *toIso = v->as<FunctionObject>(); if (!toIso) return ctx->engine()->throwTypeError(); diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index dad3689054..7a6413e820 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -49,18 +49,19 @@ struct DateObject : Object { DateObject(InternalClass *ic, QV4::Object *prototype) : Object(ic, prototype) { - value = Encode(qSNaN()); + date = qSNaN(); } DateObject(QV4::ExecutionEngine *engine, const Value &date) - : Object(engine->emptyClass, engine->datePrototype.asObject()) + : Object(engine->emptyClass, engine->datePrototype()) { - value = date; + this->date = date.toNumber(); } DateObject(QV4::ExecutionEngine *engine, const QDateTime &date); - Value value; + double date; }; + struct DateCtor : FunctionObject { DateCtor(QV4::ExecutionContext *scope); }; @@ -72,19 +73,23 @@ struct DateObject: Object { Q_MANAGED_TYPE(DateObject) - Value date() const { return d()->value; } - Value &date() { return d()->value; } - void setDate(const Value &date) { d()->value = date; } + double date() const { return d()->date; } + void setDate(double date) { d()->date = date; } QDateTime toQDateTime() const; }; +template<> +inline const DateObject *Value::as() const { + return isManaged() && m() && m()->vtable()->type == Managed::Type_DateObject ? static_cast<const DateObject *>(this) : 0; +} + struct DateCtor: FunctionObject { V4_OBJECT2(DateCtor, FunctionObject) - static ReturnedValue construct(Managed *, CallData *callData); - static ReturnedValue call(Managed *that, CallData *); + static ReturnedValue construct(const Managed *, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *); }; struct DatePrototype: DateObject diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index 36e7a3558c..ceeef80b9f 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -38,69 +38,65 @@ #include "qv4instr_moth_p.h" #include "qv4runtime_p.h" #include "qv4script_p.h" -#include "qv4objectiterator_p.h" #include "qv4identifier_p.h" -#include <iostream> +#include "qv4string_p.h" +#include "qv4objectiterator_p.h" +#include <iostream> #include <algorithm> +#include <QtCore/QJsonArray> +#include <QtCore/QJsonDocument> +#include <QtCore/QJsonValue> + +QT_BEGIN_NAMESPACE + using namespace QV4; using namespace QV4::Debugging; -namespace { -class JavaScriptJob: public Debugger::Job -{ - QV4::ExecutionEngine *engine; - int frameNr; - const QString &script; +Debugger::JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, + const QString &script) + : engine(engine) + , frameNr(frameNr) + , script(script) +{} -public: - JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, const QString &script) - : engine(engine) - , frameNr(frameNr) - , script(script) - {} - - void run() - { - Scope scope(engine); +void Debugger::JavaScriptJob::run() +{ + Scope scope(engine); - ExecutionContextSaver saver(scope, engine->currentContext()); + ExecutionContextSaver saver(scope, engine->currentContext()); - if (frameNr > 0) { - Value *savedContexts = scope.alloc(frameNr); - for (int i = 0; i < frameNr; ++i) { - savedContexts[i] = engine->currentContext(); - engine->popContext(); - } + if (frameNr > 0) { + Value *savedContexts = scope.alloc(frameNr); + for (int i = 0; i < frameNr; ++i) { + savedContexts[i] = engine->currentContext(); + engine->popContext(); } - - ScopedContext ctx(scope, engine->currentContext()); - QV4::Script script(ctx, this->script); - script.strictMode = ctx->d()->strictMode; - // In order for property lookups in QML to work, we need to disable fast v4 lookups. That - // is a side-effect of inheritContext. - script.inheritContext = true; - script.parse(); - QV4::ScopedValue result(scope); - if (!scope.engine->hasException) - result = script.run(); - if (scope.engine->hasException) - result = scope.engine->catchException(); - handleResult(result); } -protected: - virtual void handleResult(QV4::ScopedValue &result) = 0; -}; + ScopedContext ctx(scope, engine->currentContext()); + QV4::Script script(ctx, this->script); + script.strictMode = ctx->d()->strictMode; + // In order for property lookups in QML to work, we need to disable fast v4 lookups. That + // is a side-effect of inheritContext. + script.inheritContext = true; + script.parse(); + QV4::ScopedValue result(scope); + if (!scope.engine->hasException) + result = script.run(); + if (scope.engine->hasException) + result = scope.engine->catchException(); + handleResult(result); +} -class EvalJob: public JavaScriptJob +class EvalJob: public Debugger::JavaScriptJob { bool result; public: EvalJob(QV4::ExecutionEngine *engine, const QString &script) - : JavaScriptJob(engine, /*frameNr*/-1, script) + : Debugger::JavaScriptJob(engine, /*frameNr*/-1, script) , result(false) {} @@ -115,58 +111,8 @@ public: } }; -class ExpressionEvalJob: public JavaScriptJob -{ - Debugger::Collector *collector; - -public: - ExpressionEvalJob(ExecutionEngine *engine, int frameNr, const QString &expression, Debugger::Collector *collector) - : JavaScriptJob(engine, frameNr, expression) - , collector(collector) - { - } - - virtual void handleResult(QV4::ScopedValue &result) - { - collector->collect(QStringLiteral("body"), result); - } -}; - -class GatherSourcesJob: public Debugger::Job -{ - QV4::ExecutionEngine *engine; - const int seq; - -public: - GatherSourcesJob(QV4::ExecutionEngine *engine, int seq) - : engine(engine) - , seq(seq) - {} - - ~GatherSourcesJob() {} - - void run() - { - QStringList sources; - - foreach (QV4::CompiledData::CompilationUnit *unit, engine->compilationUnits) { - QString fileName = unit->fileName(); - if (!fileName.isEmpty()) - sources.append(fileName); - } - - Debugger *debugger = engine->debugger; - QMetaObject::invokeMethod(debugger->agent(), "sourcesCollected", Qt::QueuedConnection, - Q_ARG(QV4::Debugging::Debugger*, debugger), - Q_ARG(QStringList, sources), - Q_ARG(int, seq)); - } -}; -} - Debugger::Debugger(QV4::ExecutionEngine *engine) : m_engine(engine) - , m_agent(0) , m_state(Running) , m_stepping(NotStepping) , m_pauseRequested(false) @@ -180,41 +126,6 @@ Debugger::Debugger(QV4::ExecutionEngine *engine) qMetaTypeId<PauseReason>(); } -Debugger::~Debugger() -{ - detachFromAgent(); -} - -void Debugger::attachToAgent(DebuggerAgent *agent) -{ - Q_ASSERT(!m_agent); - m_agent = agent; -} - -void Debugger::detachFromAgent() -{ - DebuggerAgent *agent = 0; - { - QMutexLocker locker(&m_lock); - agent = m_agent; - m_agent = 0; - } - if (agent) - agent->removeDebugger(this); -} - -void Debugger::gatherSources(int requestSequenceNr) -{ - QMutexLocker locker(&m_lock); - - m_gatherSources = new GatherSourcesJob(m_engine, requestSequenceNr); - if (m_state == Paused) { - runInEngine_havingLock(m_gatherSources); - delete m_gatherSources; - m_gatherSources = 0; - } -} - void Debugger::pause() { QMutexLocker locker(&m_lock); @@ -272,251 +183,6 @@ QVector<StackFrame> Debugger::stackTrace(int frameLimit) const return m_engine->stackTrace(frameLimit); } -static inline Heap::CallContext *findContext(Heap::ExecutionContext *ctxt, int frame) -{ - if (!ctxt) - return 0; - - Scope scope(ctxt->engine); - ScopedContext ctx(scope, ctxt); - while (ctx) { - CallContext *cCtxt = ctx->asCallContext(); - if (cCtxt && cCtxt->d()->function) { - if (frame < 1) - return cCtxt->d(); - --frame; - } - ctx = ctx->d()->parent; - } - - return 0; -} - -static inline Heap::CallContext *findScope(Heap::ExecutionContext *ctxt, int scope) -{ - if (!ctxt) - return 0; - - Scope s(ctxt->engine); - ScopedContext ctx(s, ctxt); - for (; scope > 0 && ctx; --scope) - ctx = ctx->d()->outer; - - return (ctx && ctx->d()) ? ctx->asCallContext()->d() : 0; -} - -void Debugger::collectArgumentsInContext(Collector *collector, int frameNr, int scopeNr) -{ - if (state() != Paused) - return; - - class ArgumentCollectJob: public Job - { - QV4::ExecutionEngine *engine; - Collector *collector; - int frameNr; - int scopeNr; - - public: - ArgumentCollectJob(QV4::ExecutionEngine *engine, Collector *collector, int frameNr, int scopeNr) - : engine(engine) - , collector(collector) - , frameNr(frameNr) - , scopeNr(scopeNr) - {} - - ~ArgumentCollectJob() {} - - void run() - { - if (frameNr < 0) - return; - - Scope scope(engine); - Scoped<CallContext> ctxt(scope, findScope(findContext(engine->currentContext(), frameNr), scopeNr)); - if (!ctxt) - return; - - ScopedValue v(scope); - int nFormals = ctxt->formalCount(); - for (unsigned i = 0, ei = nFormals; i != ei; ++i) { - QString qName; - if (Identifier *name = ctxt->formals()[nFormals - i - 1]) - qName = name->string; - v = ctxt->argument(i); - collector->collect(qName, v); - } - } - }; - - ArgumentCollectJob job(m_engine, collector, frameNr, scopeNr); - runInEngine(&job); -} - -/// Same as \c retrieveArgumentsFromContext, but now for locals. -void Debugger::collectLocalsInContext(Collector *collector, int frameNr, int scopeNr) -{ - if (state() != Paused) - return; - - class LocalCollectJob: public Job - { - QV4::ExecutionEngine *engine; - Collector *collector; - int frameNr; - int scopeNr; - - public: - LocalCollectJob(QV4::ExecutionEngine *engine, Collector *collector, int frameNr, int scopeNr) - : engine(engine) - , collector(collector) - , frameNr(frameNr) - , scopeNr(scopeNr) - {} - - void run() - { - if (frameNr < 0) - return; - - Scope scope(engine); - Scoped<CallContext> ctxt(scope, findScope(findContext(engine->currentContext(), frameNr), scopeNr)); - if (!ctxt) - return; - - ScopedValue v(scope); - for (unsigned i = 0, ei = ctxt->variableCount(); i != ei; ++i) { - QString qName; - if (Identifier *name = ctxt->variables()[i]) - qName = name->string; - v = ctxt->d()->locals[i]; - collector->collect(qName, v); - } - } - }; - - LocalCollectJob job(m_engine, collector, frameNr, scopeNr); - runInEngine(&job); -} - -bool Debugger::collectThisInContext(Debugger::Collector *collector, int frame) -{ - if (state() != Paused) - return false; - - class ThisCollectJob: public Job - { - QV4::ExecutionEngine *engine; - Collector *collector; - int frameNr; - bool *foundThis; - - public: - ThisCollectJob(QV4::ExecutionEngine *engine, Collector *collector, int frameNr, bool *foundThis) - : engine(engine) - , collector(collector) - , frameNr(frameNr) - , foundThis(foundThis) - {} - - void run() - { - *foundThis = myRun(); - } - - bool myRun() - { - Scope scope(engine); - ScopedContext ctxt(scope, findContext(engine->currentContext(), frameNr)); - while (ctxt) { - if (CallContext *cCtxt = ctxt->asCallContext()) - if (cCtxt->d()->activation) - break; - ctxt = ctxt->d()->outer; - } - - if (!ctxt) - return false; - - ScopedObject o(scope, ctxt->asCallContext()->d()->activation); - collector->collect(o); - return true; - } - }; - - bool foundThis = false; - ThisCollectJob job(m_engine, collector, frame, &foundThis); - runInEngine(&job); - return foundThis; -} - -void Debugger::collectThrownValue(Collector *collector) -{ - if (state() != Paused || !m_engine->hasException) - return; - - class ThisCollectJob: public Job - { - QV4::ExecutionEngine *engine; - Collector *collector; - - public: - ThisCollectJob(QV4::ExecutionEngine *engine, Collector *collector) - : engine(engine) - , collector(collector) - {} - - void run() - { - Scope scope(engine); - ScopedValue v(scope, engine->exceptionValue); - collector->collect(QStringLiteral("exception"), v); - } - }; - - ThisCollectJob job(m_engine, collector); - runInEngine(&job); -} - -void Debugger::collectReturnedValue(Collector *collector) const -{ - if (state() != Paused) - return; - - Scope scope(m_engine); - ScopedObject o(scope, m_returnedValue.valueRef()); - collector->collect(o); -} - -QVector<Heap::ExecutionContext::ContextType> Debugger::getScopeTypes(int frame) const -{ - QVector<Heap::ExecutionContext::ContextType> types; - - if (state() != Paused) - return types; - - Scope scope(m_engine); - Scoped<CallContext> sctxt(scope, findContext(m_engine->currentContext(), frame)); - if (!sctxt || sctxt->d()->type < Heap::ExecutionContext::Type_SimpleCallContext) - return types; - - ScopedContext it(scope, sctxt->d()); - for (; it; it = it->d()->outer) - types.append(it->d()->type); - - return types; -} - - -void Debugger::evaluateExpression(int frameNr, const QString &expression, Debugger::Collector *resultsCollector) -{ - Q_ASSERT(state() == Paused); - - Q_ASSERT(m_runningJob == 0); - ExpressionEvalJob job(m_engine, frameNr, expression, resultsCollector); - runInEngine(&job); -} - void Debugger::maybeBreakAtInstruction() { if (m_runningJob) // do not re-enter when we're doing a job for the debugger. @@ -610,9 +276,7 @@ void Debugger::pauseAndWait(PauseReason reason) return; m_state = Paused; - QMetaObject::invokeMethod(m_agent, "debuggerPaused", Qt::QueuedConnection, - Q_ARG(QV4::Debugging::Debugger*, this), - Q_ARG(QV4::Debugging::PauseReason, reason)); + emit debuggerPaused(this, reason); while (true) { m_runningCondition.wait(&m_lock); @@ -662,174 +326,8 @@ void Debugger::runInEngine_havingLock(Debugger::Job *job) m_runningJob = 0; } -void DebuggerAgent::addDebugger(Debugger *debugger) -{ - Q_ASSERT(!m_debuggers.contains(debugger)); - m_debuggers << debugger; - debugger->attachToAgent(this); - - debugger->setBreakOnThrow(m_breakOnThrow); - - foreach (const BreakPoint &breakPoint, m_breakPoints.values()) - if (breakPoint.enabled) - debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition); -} - -void DebuggerAgent::removeDebugger(Debugger *debugger) -{ - m_debuggers.removeAll(debugger); - debugger->detachFromAgent(); -} - -void DebuggerAgent::pause(Debugger *debugger) const -{ - debugger->pause(); -} - -void DebuggerAgent::pauseAll() const -{ - foreach (Debugger *debugger, m_debuggers) - pause(debugger); -} - -void DebuggerAgent::resumeAll() const -{ - foreach (Debugger *debugger, m_debuggers) - if (debugger->state() == Debugger::Paused) - debugger->resume(Debugger::FullThrottle); -} - -int DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber, bool enabled, const QString &condition) -{ - if (enabled) - foreach (Debugger *debugger, m_debuggers) - debugger->addBreakPoint(fileName, lineNumber, condition); - - int id = m_breakPoints.size(); - m_breakPoints.insert(id, BreakPoint(fileName, lineNumber, enabled, condition)); - return id; -} - -void DebuggerAgent::removeBreakPoint(int id) -{ - BreakPoint breakPoint = m_breakPoints.value(id); - if (!breakPoint.isValid()) - return; - - m_breakPoints.remove(id); - - if (breakPoint.enabled) - foreach (Debugger *debugger, m_debuggers) - debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr); -} - -void DebuggerAgent::removeAllBreakPoints() -{ - QList<int> ids = m_breakPoints.keys(); - foreach (int id, ids) - removeBreakPoint(id); -} - -void DebuggerAgent::enableBreakPoint(int id, bool onoff) -{ - BreakPoint &breakPoint = m_breakPoints[id]; - if (!breakPoint.isValid() || breakPoint.enabled == onoff) - return; - breakPoint.enabled = onoff; - - foreach (Debugger *debugger, m_debuggers) { - if (onoff) - debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition); - else - debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr); - } -} - -QList<int> DebuggerAgent::breakPointIds(const QString &fileName, int lineNumber) const -{ - QList<int> ids; - - for (QHash<int, BreakPoint>::const_iterator i = m_breakPoints.begin(), ei = m_breakPoints.end(); i != ei; ++i) - if (i->lineNr == lineNumber && fileName.endsWith(i->fileName)) - ids.push_back(i.key()); - - return ids; -} - -void DebuggerAgent::setBreakOnThrow(bool onoff) -{ - if (onoff != m_breakOnThrow) { - m_breakOnThrow = onoff; - foreach (Debugger *debugger, m_debuggers) - debugger->setBreakOnThrow(onoff); - } -} - -DebuggerAgent::~DebuggerAgent() -{ - foreach (Debugger *debugger, m_debuggers) - debugger->detachFromAgent(); - - Q_ASSERT(m_debuggers.isEmpty()); -} - -Debugger::Collector::~Collector() -{ -} - -void Debugger::Collector::collect(const QString &name, const ScopedValue &value) -{ - switch (value->type()) { - case Value::Empty_Type: - Q_ASSERT(!"empty Value encountered"); - break; - case Value::Undefined_Type: - addUndefined(name); - break; - case Value::Null_Type: - addNull(name); - break; - case Value::Boolean_Type: - addBoolean(name, value->booleanValue()); - break; - case Value::Managed_Type: - if (String *s = value->asString()) - addString(name, s->toQString()); - else - addObject(name, value); - break; - case Value::Integer_Type: - addInteger(name, value->int_32); - break; - default: // double - addDouble(name, value->doubleValue()); - break; - } -} - -void Debugger::Collector::collect(Object *object) -{ - bool property = true; - qSwap(property, m_isProperty); - - Scope scope(m_engine); - ObjectIterator it(scope, object, ObjectIterator::EnumerableOnly); - ScopedValue name(scope); - ScopedValue value(scope); - while (true) { - Value v; - name = it.nextPropertyNameAsString(&v); - if (name->isNull()) - break; - QString key = name->toQStringNoThrow(); - value = v; - collect(key, value); - } - - qSwap(property, m_isProperty); -} - - Debugger::Job::~Job() { } + +QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h index e6a9750351..ac0c934d42 100644 --- a/src/qml/jsruntime/qv4debugging_p.h +++ b/src/qml/jsruntime/qv4debugging_p.h @@ -44,6 +44,8 @@ #include <QMutex> #include <QWaitCondition> +#include <QtCore/QJsonObject> + QT_BEGIN_NAMESPACE namespace QV4 { @@ -59,8 +61,6 @@ enum PauseReason { Step }; -class DebuggerAgent; - struct DebuggerBreakPoint { DebuggerBreakPoint(const QString &fileName, int line) : fileName(fileName), lineNumber(line) @@ -79,43 +79,29 @@ inline bool operator==(const DebuggerBreakPoint &a, const DebuggerBreakPoint &b) typedef QHash<DebuggerBreakPoint, QString> BreakPoints; - -class Q_QML_EXPORT Debugger +class Q_QML_EXPORT Debugger : public QObject { + Q_OBJECT public: - class Job + class Q_QML_EXPORT Job { public: virtual ~Job() = 0; virtual void run() = 0; }; - class Q_QML_EXPORT Collector + class Q_QML_EXPORT JavaScriptJob: public Job { - public: - Collector(ExecutionEngine *engine): m_engine(engine), m_isProperty(false) {} - virtual ~Collector(); + QV4::ExecutionEngine *engine; + int frameNr; + const QString &script; - void collect(const QString &name, const ScopedValue &value); - void collect(Object *object); + public: + JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, const QString &script); + void run(); protected: - virtual void addUndefined(const QString &name) = 0; - virtual void addNull(const QString &name) = 0; - virtual void addBoolean(const QString &name, bool value) = 0; - virtual void addString(const QString &name, const QString &value) = 0; - virtual void addObject(const QString &name, const Value &value) = 0; - virtual void addInteger(const QString &name, int value) = 0; - virtual void addDouble(const QString &name, double value) = 0; - - QV4::ExecutionEngine *engine() const { return m_engine; } - - bool isProperty() const { return m_isProperty; } - void setIsProperty(bool onoff) { m_isProperty = onoff; } - - private: - QV4::ExecutionEngine *m_engine; - bool m_isProperty; + virtual void handleResult(QV4::ScopedValue &result) = 0; }; enum State { @@ -133,16 +119,10 @@ public: }; Debugger(ExecutionEngine *engine); - ~Debugger(); ExecutionEngine *engine() const { return m_engine; } - void attachToAgent(DebuggerAgent *agent); - void detachFromAgent(); - DebuggerAgent *agent() const { return m_agent; } - - void gatherSources(int requestSequenceNr); void pause(); void resume(Speed speed); @@ -166,14 +146,10 @@ public: } QVector<StackFrame> stackTrace(int frameLimit = -1) const; - void collectArgumentsInContext(Collector *collector, int frameNr = 0, int scopeNr = 0); - void collectLocalsInContext(Collector *collector, int frameNr = 0, int scopeNr = 0); - bool collectThisInContext(Collector *collector, int frame = 0); - void collectThrownValue(Collector *collector); - void collectReturnedValue(Collector *collector) const; QVector<Heap::ExecutionContext::ContextType> getScopeTypes(int frame = 0) const; - void evaluateExpression(int frameNr, const QString &expression, Collector *resultsCollector); + Function *getFunction() const; + void runInEngine(Job *job); public: // compile-time interface void maybeBreakAtInstruction(); @@ -183,21 +159,19 @@ public: // execution hooks void leavingFunction(const ReturnedValue &retVal); void aboutToThrow(); -private: - Function *getFunction() const; +signals: + void sourcesCollected(QV4::Debugging::Debugger *self, const QStringList &sources, int seq); + void debuggerPaused(QV4::Debugging::Debugger *self, QV4::Debugging::PauseReason reason); +private: // requires lock to be held void pauseAndWait(PauseReason reason); - bool reallyHitTheBreakPoint(const QString &filename, int linenr); - - void runInEngine(Job *job); void runInEngine_havingLock(Debugger::Job *job); private: QV4::ExecutionEngine *m_engine; QV4::PersistentValue m_currentContext; - DebuggerAgent *m_agent; QMutex m_lock; QWaitCondition m_runningCondition; State m_state; @@ -214,54 +188,6 @@ private: QWaitCondition m_jobIsRunning; }; -class Q_QML_EXPORT DebuggerAgent : public QObject -{ - Q_OBJECT -public: - DebuggerAgent(): m_breakOnThrow(false) {} - ~DebuggerAgent(); - - void addDebugger(Debugger *debugger); - void removeDebugger(Debugger *debugger); - - void pause(Debugger *debugger) const; - void pauseAll() const; - void resumeAll() const; - int addBreakPoint(const QString &fileName, int lineNumber, bool enabled = true, const QString &condition = QString()); - void removeBreakPoint(int id); - void removeAllBreakPoints(); - void enableBreakPoint(int id, bool onoff); - QList<int> breakPointIds(const QString &fileName, int lineNumber) const; - - bool breakOnThrow() const { return m_breakOnThrow; } - void setBreakOnThrow(bool onoff); - - Q_INVOKABLE virtual void debuggerPaused(QV4::Debugging::Debugger *debugger, - QV4::Debugging::PauseReason reason) = 0; - Q_INVOKABLE virtual void sourcesCollected(QV4::Debugging::Debugger *debugger, - QStringList sources, int requestSequenceNr) = 0; - -protected: - QList<Debugger *> m_debuggers; - - struct BreakPoint { - QString fileName; - int lineNr; - bool enabled; - QString condition; - - BreakPoint(): lineNr(-1), enabled(false) {} - BreakPoint(const QString &fileName, int lineNr, bool enabled, const QString &condition) - : fileName(fileName), lineNr(lineNr), enabled(enabled), condition(condition) - {} - - bool isValid() const { return lineNr >= 0 && !fileName.isEmpty(); } - }; - - QHash<int, BreakPoint> m_breakPoints; - bool m_breakOnThrow; -}; - } // namespace Debugging } // namespace QV4 diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index e1282eeca9..7424dc4e4c 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include <qv4engine_p.h> #include <qv4context_p.h> -#include <qv4value_inl_p.h> +#include <qv4value_p.h> #include <qv4object_p.h> #include <qv4objectproto_p.h> #include <qv4objectiterator_p.h> @@ -48,7 +48,7 @@ #include <qv4regexp_p.h> #include <qv4variantobject_p.h> #include <qv4runtime_p.h> -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include <qv4argumentsobject_p.h> #include <qv4dateobject_p.h> #include <qv4jsonobject_p.h> @@ -59,7 +59,6 @@ #include "qv4executableallocator_p.h" #include "qv4sequenceobject_p.h" #include "qv4qobjectwrapper_p.h" -#include "qv4qmlextensions_p.h" #include "qv4memberdata_p.h" #include "qv4arraybuffer_p.h" #include "qv4dataview_p.h" @@ -197,6 +196,7 @@ QQmlEngine *ExecutionEngine::qmlEngine() const ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) : current(0) + , hasException(false) , memoryManager(new QV4::MemoryManager(this)) , executableAllocator(new QV4::ExecutableAllocator) , regExpAllocator(new QV4::ExecutableAllocator) @@ -211,13 +211,9 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) , m_engineId(engineSerial.fetchAndAddOrdered(1)) , regExpCache(0) , m_multiplyWrappedQObjects(0) - , m_qmlExtensions(0) { MemoryManager::GCBlocker gcBlocker(memoryManager); - exceptionValue = Encode::undefined(); - hasException = false; - if (!factory) { #ifdef V4_ENABLE_JIT @@ -241,6 +237,13 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) jsStackBase = (Value *)jsStack->base(); jsStackTop = jsStackBase; + exceptionValue = jsAlloca(1); + globalObject = static_cast<Object *>(jsAlloca(1)); + jsObjects = jsAlloca(NJSObjects); + typedArrayPrototype = static_cast<Object *>(jsAlloca(NTypedArrayTypes)); + typedArrayCtors = static_cast<FunctionObject *>(jsAlloca(NTypedArrayTypes)); + jsStrings = jsAlloca(NJSStrings); + #ifdef V4_USE_VALGRIND VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, 2*JSStackLimit); #endif @@ -251,208 +254,208 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) if (!recheckCStackLimits()) qFatal("Fatal: Not enough stack space available for QML. Please increase the process stack size to more than %d KBytes.", MinimumStackSize); - Scope scope(this); - identifierTable = new IdentifierTable(this); classPool = new InternalClassPool; emptyClass = new (classPool) InternalClass(this); - id_empty = newIdentifier(QString()); - id_undefined = newIdentifier(QStringLiteral("undefined")); - id_null = newIdentifier(QStringLiteral("null")); - id_true = newIdentifier(QStringLiteral("true")); - id_false = newIdentifier(QStringLiteral("false")); - id_boolean = newIdentifier(QStringLiteral("boolean")); - id_number = newIdentifier(QStringLiteral("number")); - id_string = newIdentifier(QStringLiteral("string")); - id_object = newIdentifier(QStringLiteral("object")); - id_function = newIdentifier(QStringLiteral("function")); - id_length = newIdentifier(QStringLiteral("length")); - id_prototype = newIdentifier(QStringLiteral("prototype")); - id_constructor = newIdentifier(QStringLiteral("constructor")); - id_arguments = newIdentifier(QStringLiteral("arguments")); - id_caller = newIdentifier(QStringLiteral("caller")); - id_callee = newIdentifier(QStringLiteral("callee")); - id_this = newIdentifier(QStringLiteral("this")); - id___proto__ = newIdentifier(QStringLiteral("__proto__")); - id_enumerable = newIdentifier(QStringLiteral("enumerable")); - id_configurable = newIdentifier(QStringLiteral("configurable")); - id_writable = newIdentifier(QStringLiteral("writable")); - id_value = newIdentifier(QStringLiteral("value")); - id_get = newIdentifier(QStringLiteral("get")); - id_set = newIdentifier(QStringLiteral("set")); - id_eval = newIdentifier(QStringLiteral("eval")); - id_uintMax = newIdentifier(QStringLiteral("4294967295")); - id_name = newIdentifier(QStringLiteral("name")); - id_index = newIdentifier(QStringLiteral("index")); - id_input = newIdentifier(QStringLiteral("input")); - id_toString = newIdentifier(QStringLiteral("toString")); - id_destroy = newIdentifier(QStringLiteral("destroy")); - id_valueOf = newIdentifier(QStringLiteral("valueOf")); - id_byteLength = newIdentifier(QStringLiteral("byteLength")); - id_byteOffset = newIdentifier(QStringLiteral("byteOffset")); - id_buffer = newIdentifier(QStringLiteral("buffer")); - id_lastIndex = newIdentifier(QStringLiteral("lastIndex")); - - objectPrototype = memoryManager->alloc<ObjectPrototype>(emptyClass, (QV4::Object *)0); - - arrayClass = emptyClass->addMember(id_length, Attr_NotConfigurable|Attr_NotEnumerable); - arrayPrototype = memoryManager->alloc<ArrayPrototype>(arrayClass, objectPrototype.asObject()); - - InternalClass *argsClass = emptyClass->addMember(id_length, Attr_NotEnumerable); - argumentsObjectClass = argsClass->addMember(id_callee, Attr_Data|Attr_NotEnumerable); - strictArgumentsObjectClass = argsClass->addMember(id_callee, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - strictArgumentsObjectClass = strictArgumentsObjectClass->addMember(id_caller, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - - m_globalObject = newObject(); - Q_ASSERT(globalObject()->d()->vtable); + jsStrings[String_Empty] = newIdentifier(QString()); + jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined")); + jsStrings[String_null] = newIdentifier(QStringLiteral("null")); + jsStrings[String_true] = newIdentifier(QStringLiteral("true")); + jsStrings[String_false] = newIdentifier(QStringLiteral("false")); + jsStrings[String_boolean] = newIdentifier(QStringLiteral("boolean")); + jsStrings[String_number] = newIdentifier(QStringLiteral("number")); + jsStrings[String_string] = newIdentifier(QStringLiteral("string")); + jsStrings[String_object] = newIdentifier(QStringLiteral("object")); + jsStrings[String_function] = newIdentifier(QStringLiteral("function")); + jsStrings[String_length] = newIdentifier(QStringLiteral("length")); + jsStrings[String_prototype] = newIdentifier(QStringLiteral("prototype")); + jsStrings[String_constructor] = newIdentifier(QStringLiteral("constructor")); + jsStrings[String_arguments] = newIdentifier(QStringLiteral("arguments")); + jsStrings[String_caller] = newIdentifier(QStringLiteral("caller")); + jsStrings[String_callee] = newIdentifier(QStringLiteral("callee")); + jsStrings[String_this] = newIdentifier(QStringLiteral("this")); + jsStrings[String___proto__] = newIdentifier(QStringLiteral("__proto__")); + jsStrings[String_enumerable] = newIdentifier(QStringLiteral("enumerable")); + jsStrings[String_configurable] = newIdentifier(QStringLiteral("configurable")); + jsStrings[String_writable] = newIdentifier(QStringLiteral("writable")); + jsStrings[String_value] = newIdentifier(QStringLiteral("value")); + jsStrings[String_get] = newIdentifier(QStringLiteral("get")); + jsStrings[String_set] = newIdentifier(QStringLiteral("set")); + jsStrings[String_eval] = newIdentifier(QStringLiteral("eval")); + jsStrings[String_uintMax] = newIdentifier(QStringLiteral("4294967295")); + jsStrings[String_name] = newIdentifier(QStringLiteral("name")); + jsStrings[String_index] = newIdentifier(QStringLiteral("index")); + jsStrings[String_input] = newIdentifier(QStringLiteral("input")); + jsStrings[String_toString] = newIdentifier(QStringLiteral("toString")); + jsStrings[String_destroy] = newIdentifier(QStringLiteral("destroy")); + jsStrings[String_valueOf] = newIdentifier(QStringLiteral("valueOf")); + jsStrings[String_byteLength] = newIdentifier(QStringLiteral("byteLength")); + jsStrings[String_byteOffset] = newIdentifier(QStringLiteral("byteOffset")); + jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer")); + jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex")); + + jsObjects[ObjectProto] = memoryManager->alloc<ObjectPrototype>(emptyClass, (QV4::Object *)0); + + arrayClass = emptyClass->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable); + jsObjects[ArrayProto] = memoryManager->alloc<ArrayPrototype>(arrayClass, objectPrototype()); + + InternalClass *argsClass = emptyClass->addMember(id_length(), Attr_NotEnumerable); + argumentsObjectClass = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable); + strictArgumentsObjectClass = argsClass->addMember(id_callee(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + strictArgumentsObjectClass = strictArgumentsObjectClass->addMember(id_caller(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + + *static_cast<Value *>(globalObject) = newObject(); + Q_ASSERT(globalObject->d()->vtable()); initRootContext(); - stringPrototype = memoryManager->alloc<StringPrototype>(emptyClass, objectPrototype.asObject()); - numberPrototype = memoryManager->alloc<NumberPrototype>(emptyClass, objectPrototype.asObject()); - booleanPrototype = memoryManager->alloc<BooleanPrototype>(emptyClass, objectPrototype.asObject()); - datePrototype = memoryManager->alloc<DatePrototype>(emptyClass, objectPrototype.asObject()); + jsObjects[StringProto] = memoryManager->alloc<StringPrototype>(emptyClass, objectPrototype()); + jsObjects[NumberProto] = memoryManager->alloc<NumberPrototype>(emptyClass, objectPrototype()); + jsObjects[BooleanProto] = memoryManager->alloc<BooleanPrototype>(emptyClass, objectPrototype()); + jsObjects[DateProto] = memoryManager->alloc<DatePrototype>(emptyClass, objectPrototype()); uint index; - InternalClass *functionProtoClass = emptyClass->addMember(id_prototype, Attr_NotEnumerable, &index); + InternalClass *functionProtoClass = emptyClass->addMember(id_prototype(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); - functionPrototype = memoryManager->alloc<FunctionPrototype>(functionProtoClass, objectPrototype.asObject()); - functionClass = emptyClass->addMember(id_prototype, Attr_NotEnumerable|Attr_NotConfigurable, &index); + jsObjects[FunctionProto] = memoryManager->alloc<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); + simpleScriptFunctionClass = functionClass->addMember(id_name(), Attr_ReadOnly, &index); Q_ASSERT(index == Heap::SimpleScriptFunction::Index_Name); - simpleScriptFunctionClass = simpleScriptFunctionClass->addMember(id_length, Attr_ReadOnly, &index); + simpleScriptFunctionClass = simpleScriptFunctionClass->addMember(id_length(), Attr_ReadOnly, &index); Q_ASSERT(index == Heap::SimpleScriptFunction::Index_Length); - protoClass = emptyClass->addMember(id_constructor, Attr_NotEnumerable, &index); + protoClass = emptyClass->addMember(id_constructor(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor); - regExpPrototype = memoryManager->alloc<RegExpPrototype>(this); - regExpExecArrayClass = arrayClass->addMember(id_index, Attr_Data, &index); + jsObjects[RegExpProto] = memoryManager->alloc<RegExpPrototype>(this); + regExpExecArrayClass = arrayClass->addMember(id_index(), Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayIndex); - regExpExecArrayClass = regExpExecArrayClass->addMember(id_input, Attr_Data, &index); + regExpExecArrayClass = regExpExecArrayClass->addMember(id_input(), Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayInput); - errorPrototype = memoryManager->alloc<ErrorPrototype>(emptyClass, objectPrototype.asObject()); - evalErrorPrototype = memoryManager->alloc<EvalErrorPrototype>(emptyClass, errorPrototype.asObject()); - rangeErrorPrototype = memoryManager->alloc<RangeErrorPrototype>(emptyClass, errorPrototype.asObject()); - referenceErrorPrototype = memoryManager->alloc<ReferenceErrorPrototype>(emptyClass, errorPrototype.asObject()); - syntaxErrorPrototype = memoryManager->alloc<SyntaxErrorPrototype>(emptyClass, errorPrototype.asObject()); - typeErrorPrototype = memoryManager->alloc<TypeErrorPrototype>(emptyClass, errorPrototype.asObject()); - uRIErrorPrototype = memoryManager->alloc<URIErrorPrototype>(emptyClass, errorPrototype.asObject()); + jsObjects[ErrorProto] = memoryManager->alloc<ErrorPrototype>(emptyClass, objectPrototype()); + jsObjects[EvalErrorProto] = memoryManager->alloc<EvalErrorPrototype>(emptyClass, errorPrototype()); + jsObjects[RangeErrorProto] = memoryManager->alloc<RangeErrorPrototype>(emptyClass, errorPrototype()); + jsObjects[ReferenceErrorProto] = memoryManager->alloc<ReferenceErrorPrototype>(emptyClass, errorPrototype()); + jsObjects[SyntaxErrorProto] = memoryManager->alloc<SyntaxErrorPrototype>(emptyClass, errorPrototype()); + jsObjects[TypeErrorProto] = memoryManager->alloc<TypeErrorPrototype>(emptyClass, errorPrototype()); + jsObjects[URIErrorProto] = memoryManager->alloc<URIErrorPrototype>(emptyClass, errorPrototype()); - variantPrototype = memoryManager->alloc<VariantPrototype>(emptyClass, objectPrototype.asObject()); - Q_ASSERT(variantPrototype.asObject()->prototype() == objectPrototype.asObject()->d()); + jsObjects[VariantProto] = memoryManager->alloc<VariantPrototype>(emptyClass, objectPrototype()); + Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d()); - sequencePrototype = ScopedValue(scope, memoryManager->alloc<SequencePrototype>(arrayClass, arrayPrototype.asObject())); + Scope scope(this); + jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->alloc<SequencePrototype>(arrayClass, arrayPrototype())); ScopedContext global(scope, rootContext()); - objectCtor = memoryManager->alloc<ObjectCtor>(global); - stringCtor = memoryManager->alloc<StringCtor>(global); - numberCtor = memoryManager->alloc<NumberCtor>(global); - booleanCtor = memoryManager->alloc<BooleanCtor>(global); - arrayCtor = memoryManager->alloc<ArrayCtor>(global); - functionCtor = memoryManager->alloc<FunctionCtor>(global); - dateCtor = memoryManager->alloc<DateCtor>(global); - regExpCtor = memoryManager->alloc<RegExpCtor>(global); - errorCtor = memoryManager->alloc<ErrorCtor>(global); - evalErrorCtor = memoryManager->alloc<EvalErrorCtor>(global); - rangeErrorCtor = memoryManager->alloc<RangeErrorCtor>(global); - referenceErrorCtor = memoryManager->alloc<ReferenceErrorCtor>(global); - syntaxErrorCtor = memoryManager->alloc<SyntaxErrorCtor>(global); - typeErrorCtor = memoryManager->alloc<TypeErrorCtor>(global); - uRIErrorCtor = memoryManager->alloc<URIErrorCtor>(global); - - static_cast<ObjectPrototype *>(objectPrototype.asObject())->init(this, objectCtor.asObject()); - static_cast<StringPrototype *>(stringPrototype.asObject())->init(this, stringCtor.asObject()); - static_cast<NumberPrototype *>(numberPrototype.asObject())->init(this, numberCtor.asObject()); - static_cast<BooleanPrototype *>(booleanPrototype.asObject())->init(this, booleanCtor.asObject()); - static_cast<ArrayPrototype *>(arrayPrototype.asObject())->init(this, arrayCtor.asObject()); - static_cast<DatePrototype *>(datePrototype.asObject())->init(this, dateCtor.asObject()); - static_cast<FunctionPrototype *>(functionPrototype.asObject())->init(this, functionCtor.asObject()); - static_cast<RegExpPrototype *>(regExpPrototype.asObject())->init(this, regExpCtor.asObject()); - static_cast<ErrorPrototype *>(errorPrototype.asObject())->init(this, errorCtor.asObject()); - static_cast<EvalErrorPrototype *>(evalErrorPrototype.asObject())->init(this, evalErrorCtor.asObject()); - static_cast<RangeErrorPrototype *>(rangeErrorPrototype.asObject())->init(this, rangeErrorCtor.asObject()); - static_cast<ReferenceErrorPrototype *>(referenceErrorPrototype.asObject())->init(this, referenceErrorCtor.asObject()); - static_cast<SyntaxErrorPrototype *>(syntaxErrorPrototype.asObject())->init(this, syntaxErrorCtor.asObject()); - static_cast<TypeErrorPrototype *>(typeErrorPrototype.asObject())->init(this, typeErrorCtor.asObject()); - static_cast<URIErrorPrototype *>(uRIErrorPrototype.asObject())->init(this, uRIErrorCtor.asObject()); - - static_cast<VariantPrototype *>(variantPrototype.asObject())->init(); - sequencePrototype.cast<SequencePrototype>()->init(); + jsObjects[Object_Ctor] = memoryManager->alloc<ObjectCtor>(global); + jsObjects[String_Ctor] = memoryManager->alloc<StringCtor>(global); + jsObjects[Number_Ctor] = memoryManager->alloc<NumberCtor>(global); + jsObjects[Boolean_Ctor] = memoryManager->alloc<BooleanCtor>(global); + jsObjects[Array_Ctor] = memoryManager->alloc<ArrayCtor>(global); + jsObjects[Function_Ctor] = memoryManager->alloc<FunctionCtor>(global); + jsObjects[Date_Ctor] = memoryManager->alloc<DateCtor>(global); + jsObjects[RegExp_Ctor] = memoryManager->alloc<RegExpCtor>(global); + jsObjects[Error_Ctor] = memoryManager->alloc<ErrorCtor>(global); + jsObjects[EvalError_Ctor] = memoryManager->alloc<EvalErrorCtor>(global); + jsObjects[RangeError_Ctor] = memoryManager->alloc<RangeErrorCtor>(global); + jsObjects[ReferenceError_Ctor] = memoryManager->alloc<ReferenceErrorCtor>(global); + jsObjects[SyntaxError_Ctor] = memoryManager->alloc<SyntaxErrorCtor>(global); + jsObjects[TypeError_Ctor] = memoryManager->alloc<TypeErrorCtor>(global); + jsObjects[URIError_Ctor] = memoryManager->alloc<URIErrorCtor>(global); + + static_cast<ObjectPrototype *>(objectPrototype())->init(this, objectCtor()); + static_cast<StringPrototype *>(stringPrototype())->init(this, stringCtor()); + static_cast<NumberPrototype *>(numberPrototype())->init(this, numberCtor()); + static_cast<BooleanPrototype *>(booleanPrototype())->init(this, booleanCtor()); + static_cast<ArrayPrototype *>(arrayPrototype())->init(this, arrayCtor()); + static_cast<DatePrototype *>(datePrototype())->init(this, dateCtor()); + static_cast<FunctionPrototype *>(functionPrototype())->init(this, functionCtor()); + static_cast<RegExpPrototype *>(regExpPrototype())->init(this, regExpCtor()); + static_cast<ErrorPrototype *>(errorPrototype())->init(this, errorCtor()); + static_cast<EvalErrorPrototype *>(evalErrorPrototype())->init(this, evalErrorCtor()); + static_cast<RangeErrorPrototype *>(rangeErrorPrototype())->init(this, rangeErrorCtor()); + static_cast<ReferenceErrorPrototype *>(referenceErrorPrototype())->init(this, referenceErrorCtor()); + static_cast<SyntaxErrorPrototype *>(syntaxErrorPrototype())->init(this, syntaxErrorCtor()); + static_cast<TypeErrorPrototype *>(typeErrorPrototype())->init(this, typeErrorCtor()); + static_cast<URIErrorPrototype *>(uRIErrorPrototype())->init(this, uRIErrorCtor()); + + static_cast<VariantPrototype *>(variantPrototype())->init(); + sequencePrototype()->cast<SequencePrototype>()->init(); // typed arrays - arrayBufferCtor = memoryManager->alloc<ArrayBufferCtor>(global); - arrayBufferPrototype = memoryManager->alloc<ArrayBufferPrototype>(emptyClass, objectPrototype.asObject()); - static_cast<ArrayBufferPrototype *>(arrayBufferPrototype.asObject())->init(this, arrayBufferCtor.asObject()); + jsObjects[ArrayBuffer_Ctor] = memoryManager->alloc<ArrayBufferCtor>(global); + jsObjects[ArrayBufferProto] = memoryManager->alloc<ArrayBufferPrototype>(emptyClass, objectPrototype()); + static_cast<ArrayBufferPrototype *>(arrayBufferPrototype())->init(this, arrayBufferCtor()); - dataViewCtor = memoryManager->alloc<DataViewCtor>(global); - dataViewPrototype = memoryManager->alloc<DataViewPrototype>(emptyClass, objectPrototype.asObject()); - static_cast<DataViewPrototype *>(dataViewPrototype.asObject())->init(this, dataViewCtor.asObject()); + jsObjects[DataView_Ctor] = memoryManager->alloc<DataViewCtor>(global); + jsObjects[DataViewProto] = memoryManager->alloc<DataViewPrototype>(emptyClass, objectPrototype()); + static_cast<DataViewPrototype *>(dataViewPrototype())->init(this, dataViewCtor()); + jsObjects[ValueTypeProto] = (Heap::Base *) 0; for (int i = 0; i < Heap::TypedArray::NTypes; ++i) { - typedArrayCtors[i] = memoryManager->alloc<TypedArrayCtor>(global, Heap::TypedArray::Type(i)); - typedArrayPrototype[i] = memoryManager->alloc<TypedArrayPrototype>(this, Heap::TypedArray::Type(i)); - typedArrayPrototype[i].as<TypedArrayPrototype>()->init(this, static_cast<TypedArrayCtor *>(typedArrayCtors[i].asObject())); + static_cast<Value &>(typedArrayCtors[i]) = memoryManager->alloc<TypedArrayCtor>(global, Heap::TypedArray::Type(i)); + static_cast<Value &>(typedArrayPrototype[i]) = memoryManager->alloc<TypedArrayPrototype>(this, Heap::TypedArray::Type(i)); + typedArrayPrototype[i].as<TypedArrayPrototype>()->init(this, static_cast<TypedArrayCtor *>(typedArrayCtors[i].as<Object>())); } // // set up the global object // - rootContext()->global = globalObject()->d(); - rootContext()->callData->thisObject = globalObject(); - Q_ASSERT(globalObject()->d()->vtable); - - globalObject()->defineDefaultProperty(QStringLiteral("Object"), objectCtor); - globalObject()->defineDefaultProperty(QStringLiteral("String"), stringCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Number"), numberCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Boolean"), booleanCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Array"), arrayCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Function"), functionCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Date"), dateCtor); - globalObject()->defineDefaultProperty(QStringLiteral("RegExp"), regExpCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Error"), errorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("EvalError"), evalErrorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("RangeError"), rangeErrorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("ReferenceError"), referenceErrorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("SyntaxError"), syntaxErrorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("TypeError"), typeErrorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("URIError"), uRIErrorCtor); - - globalObject()->defineDefaultProperty(QStringLiteral("ArrayBuffer"), arrayBufferCtor); - globalObject()->defineDefaultProperty(QStringLiteral("DataView"), dataViewCtor); + rootContext()->d()->global = globalObject->d(); + rootContext()->d()->callData->thisObject = globalObject; + Q_ASSERT(globalObject->d()->vtable()); + + globalObject->defineDefaultProperty(QStringLiteral("Object"), *objectCtor()); + globalObject->defineDefaultProperty(QStringLiteral("String"), *stringCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Boolean"), *booleanCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Array"), *arrayCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Function"), *functionCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Date"), *dateCtor()); + globalObject->defineDefaultProperty(QStringLiteral("RegExp"), *regExpCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Error"), *errorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("EvalError"), *evalErrorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("RangeError"), *rangeErrorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("ReferenceError"), *referenceErrorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("SyntaxError"), *syntaxErrorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("TypeError"), *typeErrorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("URIError"), *uRIErrorCtor()); + + globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor()); + globalObject->defineDefaultProperty(QStringLiteral("DataView"), *dataViewCtor()); ScopedString str(scope); for (int i = 0; i < Heap::TypedArray::NTypes; ++i) - globalObject()->defineDefaultProperty((str = typedArrayCtors[i].asFunctionObject()->name())->toQString(), typedArrayCtors[i]); + globalObject->defineDefaultProperty((str = typedArrayCtors[i].as<FunctionObject>()->name())->toQString(), typedArrayCtors[i]); ScopedObject o(scope); - globalObject()->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->alloc<MathObject>(this))); - globalObject()->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->alloc<JsonObject>(this))); + globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->alloc<MathObject>(this))); + globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->alloc<JsonObject>(this))); - globalObject()->defineReadonlyProperty(QStringLiteral("undefined"), Primitive::undefinedValue()); - globalObject()->defineReadonlyProperty(QStringLiteral("NaN"), Primitive::fromDouble(std::numeric_limits<double>::quiet_NaN())); - globalObject()->defineReadonlyProperty(QStringLiteral("Infinity"), Primitive::fromDouble(Q_INFINITY)); + globalObject->defineReadonlyProperty(QStringLiteral("undefined"), Primitive::undefinedValue()); + globalObject->defineReadonlyProperty(QStringLiteral("NaN"), Primitive::fromDouble(std::numeric_limits<double>::quiet_NaN())); + globalObject->defineReadonlyProperty(QStringLiteral("Infinity"), Primitive::fromDouble(Q_INFINITY)); - evalFunction = memoryManager->alloc<EvalFunction>(global); - globalObject()->defineDefaultProperty(QStringLiteral("eval"), (o = evalFunction)); + jsObjects[Eval_Function] = memoryManager->alloc<EvalFunction>(global); + globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction()); - globalObject()->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2); - globalObject()->defineDefaultProperty(QStringLiteral("parseFloat"), GlobalFunctions::method_parseFloat, 1); - globalObject()->defineDefaultProperty(QStringLiteral("isNaN"), GlobalFunctions::method_isNaN, 1); - globalObject()->defineDefaultProperty(QStringLiteral("isFinite"), GlobalFunctions::method_isFinite, 1); - globalObject()->defineDefaultProperty(QStringLiteral("decodeURI"), GlobalFunctions::method_decodeURI, 1); - globalObject()->defineDefaultProperty(QStringLiteral("decodeURIComponent"), GlobalFunctions::method_decodeURIComponent, 1); - globalObject()->defineDefaultProperty(QStringLiteral("encodeURI"), GlobalFunctions::method_encodeURI, 1); - globalObject()->defineDefaultProperty(QStringLiteral("encodeURIComponent"), GlobalFunctions::method_encodeURIComponent, 1); - globalObject()->defineDefaultProperty(QStringLiteral("escape"), GlobalFunctions::method_escape, 1); - globalObject()->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1); + globalObject->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2); + globalObject->defineDefaultProperty(QStringLiteral("parseFloat"), GlobalFunctions::method_parseFloat, 1); + globalObject->defineDefaultProperty(QStringLiteral("isNaN"), GlobalFunctions::method_isNaN, 1); + globalObject->defineDefaultProperty(QStringLiteral("isFinite"), GlobalFunctions::method_isFinite, 1); + globalObject->defineDefaultProperty(QStringLiteral("decodeURI"), GlobalFunctions::method_decodeURI, 1); + globalObject->defineDefaultProperty(QStringLiteral("decodeURIComponent"), GlobalFunctions::method_decodeURIComponent, 1); + globalObject->defineDefaultProperty(QStringLiteral("encodeURI"), GlobalFunctions::method_encodeURI, 1); + globalObject->defineDefaultProperty(QStringLiteral("encodeURIComponent"), GlobalFunctions::method_encodeURIComponent, 1); + globalObject->defineDefaultProperty(QStringLiteral("escape"), GlobalFunctions::method_escape, 1); + globalObject->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1); ScopedString name(scope, newString(QStringLiteral("thrower"))); - thrower = BuiltinFunction::create(global, name, ::throwTypeError); + jsObjects[ThrowerObject] = BuiltinFunction::create(global, name, ::throwTypeError); } ExecutionEngine::~ExecutionEngine() @@ -471,7 +474,6 @@ ExecutionEngine::~ExecutionEngine() foreach (QV4::CompiledData::CompilationUnit *unit, remainingUnits) unit->unlink(); - delete m_qmlExtensions; emptyClass->destroy(); delete classPool; delete bumperPointerAllocator; @@ -504,10 +506,10 @@ void ExecutionEngine::initRootContext() r->d()->callData = reinterpret_cast<CallData *>(r->d() + 1); r->d()->callData->tag = QV4::Value::_Integer_Type; r->d()->callData->argc = 0; - r->d()->callData->thisObject = globalObject(); + r->d()->callData->thisObject = globalObject; r->d()->callData->args[0] = Encode::undefined(); - m_rootContext = r->d(); + jsObjects[RootContect] = r; } InternalClass *ExecutionEngine::newClass(const InternalClass &other) @@ -519,7 +521,7 @@ Heap::ExecutionContext *ExecutionEngine::pushGlobalContext() { Scope scope(this); Scoped<GlobalContext> g(scope, memoryManager->alloc<GlobalContext>(this)); - g->d()->callData = rootContext()->callData; + g->d()->callData = rootContext()->d()->callData; Q_ASSERT(currentContext() == g->d()); return g->d(); @@ -551,10 +553,10 @@ Heap::String *ExecutionEngine::newIdentifier(const QString &text) return identifierTable->insertString(text); } -Heap::Object *ExecutionEngine::newStringObject(const Value &value) +Heap::Object *ExecutionEngine::newStringObject(const String *string) { Scope scope(this); - Scoped<StringObject> object(scope, memoryManager->alloc<StringObject>(this, value)); + Scoped<StringObject> object(scope, memoryManager->alloc<StringObject>(this, string)); return object->d(); } @@ -653,7 +655,7 @@ Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re) Heap::Object *ExecutionEngine::newErrorObject(const Value &value) { Scope scope(this); - ScopedObject object(scope, memoryManager->alloc<ErrorObject>(emptyClass, errorPrototype.asObject(), value)); + ScopedObject object(scope, memoryManager->alloc<ErrorObject>(emptyClass, errorPrototype(), value)); return object->d(); } @@ -723,7 +725,7 @@ Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o) return obj->d(); } -Heap::Object *ExecutionEngine::qmlContextObject() const +Heap::QmlContext *ExecutionEngine::qmlContext() const { Heap::ExecutionContext *ctx = currentContext(); @@ -740,8 +742,28 @@ Heap::Object *ExecutionEngine::qmlContextObject() const if (ctx->type != Heap::ExecutionContext::Type_QmlContext) return 0; - Q_ASSERT(static_cast<Heap::CallContext *>(ctx)->activation); - return static_cast<Heap::CallContext *>(ctx)->activation; + return static_cast<Heap::QmlContext *>(ctx); +} + +Heap::QmlContextWrapper *ExecutionEngine::qmlContextObject() const +{ + Heap::QmlContext *ctx = qmlContext(); + if (!ctx) + return 0; + Q_ASSERT(ctx->qml); + return ctx->qml; +} + +QObject *ExecutionEngine::qmlScopeObject() const +{ + return qmlContextObject()->scopeObject; +} + +QQmlContextData *ExecutionEngine::callingQmlContext() const +{ + Heap::QmlContextWrapper *w = qmlContextObject(); + + return w ? w->context.contextData() : 0; } QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const @@ -777,7 +799,7 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const StackFrame frame; frame.source = globalCode->sourceFile(); frame.function = globalCode->name()->toQString(); - frame.line = rootContext()->lineNumber; + frame.line = rootContext()->d()->lineNumber; frame.column = -1; stack.append(frame); @@ -889,8 +911,6 @@ void ExecutionEngine::markObjects() { identifierTable->mark(this); - globalObject()->mark(this); - for (int i = 0; i < nArgumentsAccessors; ++i) { const Property &pd = argumentsAccessors[i]; if (Heap::FunctionObject *getter = pd.getter()) @@ -904,98 +924,11 @@ void ExecutionEngine::markObjects() Q_ASSERT(c->inUse()); if (!c->isMarked()) { c->setMarkBit(); - c->gcGetVtable()->markObjects(c, this); + c->vtable()->markObjects(c, this); } c = c->parent; } - id_empty->mark(this); - id_undefined->mark(this); - id_null->mark(this); - id_true->mark(this); - id_false->mark(this); - id_boolean->mark(this); - id_number->mark(this); - id_string->mark(this); - id_object->mark(this); - id_function->mark(this); - id_length->mark(this); - id_prototype->mark(this); - id_constructor->mark(this); - id_arguments->mark(this); - id_caller->mark(this); - id_callee->mark(this); - id_this->mark(this); - id___proto__->mark(this); - id_enumerable->mark(this); - id_configurable->mark(this); - id_writable->mark(this); - id_value->mark(this); - id_get->mark(this); - id_set->mark(this); - id_eval->mark(this); - id_uintMax->mark(this); - id_name->mark(this); - id_index->mark(this); - id_input->mark(this); - id_toString->mark(this); - id_destroy->mark(this); - id_valueOf->mark(this); - id_byteLength->mark(this); - id_byteOffset->mark(this); - id_buffer->mark(this); - id_lastIndex->mark(this); - - objectCtor.mark(this); - stringCtor.mark(this); - numberCtor.mark(this); - booleanCtor.mark(this); - arrayCtor.mark(this); - functionCtor.mark(this); - dateCtor.mark(this); - regExpCtor.mark(this); - errorCtor.mark(this); - evalErrorCtor.mark(this); - rangeErrorCtor.mark(this); - referenceErrorCtor.mark(this); - syntaxErrorCtor.mark(this); - typeErrorCtor.mark(this); - uRIErrorCtor.mark(this); - arrayBufferCtor.mark(this); - dataViewCtor.mark(this); - for (int i = 0; i < Heap::TypedArray::NTypes; ++i) - typedArrayCtors[i].mark(this); - - objectPrototype.mark(this); - arrayPrototype.mark(this); - stringPrototype.mark(this); - numberPrototype.mark(this); - booleanPrototype.mark(this); - datePrototype.mark(this); - functionPrototype.mark(this); - regExpPrototype.mark(this); - errorPrototype.mark(this); - evalErrorPrototype.mark(this); - rangeErrorPrototype.mark(this); - referenceErrorPrototype.mark(this); - syntaxErrorPrototype.mark(this); - typeErrorPrototype.mark(this); - uRIErrorPrototype.mark(this); - variantPrototype.mark(this); - sequencePrototype.mark(this); - - arrayBufferPrototype.mark(this); - dataViewPrototype.mark(this); - for (int i = 0; i < Heap::TypedArray::NTypes; ++i) - typedArrayPrototype[i].mark(this); - - exceptionValue.mark(this); - - thrower->mark(this); - - if (m_qmlExtensions) - m_qmlExtensions->markObjects(this); - classPool->markObjects(this); for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd(); @@ -1003,13 +936,6 @@ void ExecutionEngine::markObjects() (*it)->markObjects(this); } -QmlExtensions *ExecutionEngine::qmlExtensions() -{ - if (!m_qmlExtensions) - m_qmlExtensions = new QmlExtensions; - return m_qmlExtensions; -} - ReturnedValue ExecutionEngine::throwError(const Value &value) { // we can get in here with an exception already set, as the runtime @@ -1020,7 +946,7 @@ ReturnedValue ExecutionEngine::throwError(const Value &value) return Encode::undefined(); hasException = true; - exceptionValue = value; + *exceptionValue = value; QV4::Scope scope(this); QV4::Scoped<ErrorObject> error(scope, value); if (!!error) @@ -1041,8 +967,8 @@ ReturnedValue ExecutionEngine::catchException(StackTrace *trace) *trace = exceptionStackTrace; exceptionStackTrace.clear(); hasException = false; - ReturnedValue res = exceptionValue.asReturnedValue(); - exceptionValue = Primitive::emptyValue(); + ReturnedValue res = exceptionValue->asReturnedValue(); + *exceptionValue = Primitive::emptyValue(); return res; } @@ -1175,7 +1101,7 @@ bool ExecutionEngine::recheckCStackLimits() typedef QSet<QV4::Heap::Object *> V4ObjectSet; static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects); static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value); -static QVariant objectToVariant(QV4::ExecutionEngine *e, QV4::Object *o, V4ObjectSet *visitedObjects = 0); +static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects = 0); static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value, const QByteArray &targetType, void **result); @@ -1198,7 +1124,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int Q_ASSERT (!value.isEmpty()); QV4::Scope scope(e); - if (QV4::VariantObject *v = value.as<QV4::VariantObject>()) + if (const QV4::VariantObject *v = value.as<QV4::VariantObject>()) return v->d()->data; if (typeHint == QVariant::Bool) @@ -1210,10 +1136,10 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int if (typeHint == qMetaTypeId<QJSValue>()) return QVariant::fromValue(QJSValue(e, value.asReturnedValue())); - if (value.asObject()) { + if (value.as<Object>()) { QV4::ScopedObject object(scope, value); if (typeHint == QMetaType::QJsonObject - && !value.asArrayObject() && !value.asFunctionObject()) { + && !value.as<ArrayObject>() && !value.as<FunctionObject>()) { return QVariant::fromValue(QV4::JsonObject::toJsonObject(object)); } else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) { return qVariantFromValue<QObject *>(wrapper->object()); @@ -1229,7 +1155,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return QV4::SequencePrototype::toVariant(object); } - if (value.asArrayObject()) { + if (value.as<ArrayObject>()) { QV4::ScopedArrayObject a(scope, value); if (typeHint == qMetaTypeId<QList<QObject *> >()) { QList<QObject *> list; @@ -1267,11 +1193,11 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return value.asDouble(); if (value.isString()) return value.stringValue()->toQString(); - if (QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>()) + if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>()) return ld->d()->locale; - if (QV4::DateObject *d = value.asDateObject()) + if (const QV4::DateObject *d = value.as<DateObject>()) return d->toQDateTime(); - if (QV4::ArrayBuffer *d = value.as<ArrayBuffer>()) + if (const QV4::ArrayBuffer *d = value.as<ArrayBuffer>()) return d->asByteArray(); // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)! @@ -1287,7 +1213,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return objectToVariant(e, o, visitedObjects); } -static QVariant objectToVariant(QV4::ExecutionEngine *e, QV4::Object *o, V4ObjectSet *visitedObjects) +static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects) { Q_ASSERT(o); @@ -1298,7 +1224,7 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, QV4::Object *o, V4Objec // Avoid recursion. // For compatibility with QVariant{List,Map} conversion, we return an // empty object (and no error is thrown). - if (o->asArrayObject()) + if (o->as<ArrayObject>()) return QVariantList(); return QVariantMap(); } @@ -1306,7 +1232,7 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, QV4::Object *o, V4Objec QVariant result; - if (o->asArrayObject()) { + if (o->as<ArrayObject>()) { QV4::Scope scope(e); QV4::ScopedArrayObject a(scope, o->asReturnedValue()); QV4::ScopedValue v(scope); @@ -1319,7 +1245,7 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, QV4::Object *o, V4Objec } result = list; - } else if (!o->asFunctionObject()) { + } else if (!o->as<FunctionObject>()) { QVariantMap map; QV4::Scope scope(e); QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly); @@ -1497,7 +1423,7 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant) return QV4::Encode(newVariantObject(variant)); } -QVariantMap ExecutionEngine::variantMapFromJS(Object *o) +QVariantMap ExecutionEngine::variantMapFromJS(const Object *o) { return objectToVariant(this, o).toMap(); } @@ -1630,93 +1556,90 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data) return 0; } -void ExecutionEngine::assertObjectBelongsToEngine(const Value &v) +void ExecutionEngine::assertObjectBelongsToEngine(const Heap::Base &baseObject) { - Q_UNUSED(v); - Q_ASSERT(!v.isObject() || v.objectValue()->engine() == this); - Q_UNUSED(v); + Q_ASSERT(!baseObject.vtable()->isObject || static_cast<const Heap::Object&>(baseObject).internalClass->engine == this); + Q_UNUSED(baseObject); } // Converts a JS value to a meta-type. // data must point to a place that can store a value of the given type. // Returns true if conversion succeeded, false otherwise. -bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *data) +bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) { - QV4::Scope scope(this); - // check if it's one of the types we know switch (QMetaType::Type(type)) { case QMetaType::Bool: - *reinterpret_cast<bool*>(data) = value.toBoolean(); + *reinterpret_cast<bool*>(data) = value->toBoolean(); return true; case QMetaType::Int: - *reinterpret_cast<int*>(data) = value.toInt32(); + *reinterpret_cast<int*>(data) = value->toInt32(); return true; case QMetaType::UInt: - *reinterpret_cast<uint*>(data) = value.toUInt32(); + *reinterpret_cast<uint*>(data) = value->toUInt32(); return true; case QMetaType::LongLong: - *reinterpret_cast<qlonglong*>(data) = qlonglong(value.toInteger()); + *reinterpret_cast<qlonglong*>(data) = qlonglong(value->toInteger()); return true; case QMetaType::ULongLong: - *reinterpret_cast<qulonglong*>(data) = qulonglong(value.toInteger()); + *reinterpret_cast<qulonglong*>(data) = qulonglong(value->toInteger()); return true; case QMetaType::Double: - *reinterpret_cast<double*>(data) = value.toNumber(); + *reinterpret_cast<double*>(data) = value->toNumber(); return true; case QMetaType::QString: - if (value.isUndefined() || value.isNull()) + if (value->isUndefined() || value->isNull()) *reinterpret_cast<QString*>(data) = QString(); else - *reinterpret_cast<QString*>(data) = value.toQString(); + *reinterpret_cast<QString*>(data) = value->toQString(); return true; case QMetaType::Float: - *reinterpret_cast<float*>(data) = value.toNumber(); + *reinterpret_cast<float*>(data) = value->toNumber(); return true; case QMetaType::Short: - *reinterpret_cast<short*>(data) = short(value.toInt32()); + *reinterpret_cast<short*>(data) = short(value->toInt32()); return true; case QMetaType::UShort: - *reinterpret_cast<unsigned short*>(data) = value.toUInt16(); + *reinterpret_cast<unsigned short*>(data) = value->toUInt16(); return true; case QMetaType::Char: - *reinterpret_cast<char*>(data) = char(value.toInt32()); + *reinterpret_cast<char*>(data) = char(value->toInt32()); return true; case QMetaType::UChar: - *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value.toInt32()); + *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value->toInt32()); return true; case QMetaType::QChar: - if (value.isString()) { - QString str = value.stringValue()->toQString(); + if (value->isString()) { + QString str = value->stringValue()->toQString(); *reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0); } else { - *reinterpret_cast<QChar*>(data) = QChar(ushort(value.toUInt16())); + *reinterpret_cast<QChar*>(data) = QChar(ushort(value->toUInt16())); } return true; case QMetaType::QDateTime: - if (QV4::DateObject *d = value.asDateObject()) { + if (const QV4::DateObject *d = value->as<DateObject>()) { *reinterpret_cast<QDateTime *>(data) = d->toQDateTime(); return true; } break; case QMetaType::QDate: - if (QV4::DateObject *d = value.asDateObject()) { + if (const QV4::DateObject *d = value->as<DateObject>()) { *reinterpret_cast<QDate *>(data) = d->toQDateTime().date(); return true; } break; case QMetaType::QRegExp: - if (QV4::RegExpObject *r = value.as<QV4::RegExpObject>()) { + if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) { *reinterpret_cast<QRegExp *>(data) = r->toQRegExp(); return true; } break; case QMetaType::QObjectStar: { - QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>(); - if (qobjectWrapper || value.isNull()) { - *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(scope.engine, value); + const QV4::QObjectWrapper *qobjectWrapper = value->as<QV4::QObjectWrapper>(); + if (qobjectWrapper || value->isNull()) { + *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(this, *value); return true; } break; } case QMetaType::QStringList: { - QV4::ScopedArrayObject a(scope, value); + const QV4::ArrayObject *a = value->as<QV4::ArrayObject>(); if (a) { *reinterpret_cast<QStringList *>(data) = a->toQStringList(); return true; @@ -1724,15 +1647,15 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da break; } case QMetaType::QVariantList: { - QV4::ScopedArrayObject a(scope, value); + const QV4::ArrayObject *a = value->as<QV4::ArrayObject>(); if (a) { - *reinterpret_cast<QVariantList *>(data) = scope.engine->toVariant(a, /*typeHint*/-1, /*createJSValueForObjects*/false).toList(); + *reinterpret_cast<QVariantList *>(data) = toVariant(*a, /*typeHint*/-1, /*createJSValueForObjects*/false).toList(); return true; } break; } case QMetaType::QVariantMap: { - QV4::ScopedObject o(scope, value); + const QV4::Object *o = value->as<QV4::Object>(); if (o) { *reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(o); return true; @@ -1740,20 +1663,19 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da break; } case QMetaType::QVariant: - *reinterpret_cast<QVariant*>(data) = scope.engine->toVariant(value, /*typeHint*/-1, /*createJSValueForObjects*/false); + *reinterpret_cast<QVariant*>(data) = toVariant(*value, /*typeHint*/-1, /*createJSValueForObjects*/false); return true; case QMetaType::QJsonValue: - *reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(value); + *reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(*value); return true; case QMetaType::QJsonObject: { - QV4::ScopedObject o(scope, value); - *reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(o); + *reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(value->as<Object>()); return true; } case QMetaType::QJsonArray: { - QV4::ScopedArrayObject a(scope, value); + const QV4::ArrayObject *a = value->as<ArrayObject>(); if (a) { - *reinterpret_cast<QJsonArray *>(data) = QV4::JsonObject::toJsonArray(a); + *reinterpret_cast<QJsonArray *>(data) = JsonObject::toJsonArray(a); return true; } break; @@ -1763,7 +1685,7 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da } { - QV4::Scoped<QV4::QQmlValueTypeWrapper> vtw(scope, value); + const QQmlValueTypeWrapper *vtw = value->as<QQmlValueTypeWrapper>(); if (vtw && vtw->typeId() == type) { return vtw->toGadget(data); } @@ -1788,21 +1710,22 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da } #endif - // Try to use magic; for compatibility with qscriptvalue_cast. + // Try to use magic; for compatibility with qjsvalue_cast. QByteArray name = QMetaType::typeName(type); - if (convertToNativeQObject(this, value, name, reinterpret_cast<void* *>(data))) + if (convertToNativeQObject(this, *value, name, reinterpret_cast<void* *>(data))) return true; - if (value.as<QV4::VariantObject>() && name.endsWith('*')) { + if (value->as<QV4::VariantObject>() && name.endsWith('*')) { int valueType = QMetaType::type(name.left(name.size()-1)); - QVariant &var = value.as<QV4::VariantObject>()->d()->data; + QVariant &var = value->as<QV4::VariantObject>()->d()->data; if (valueType == var.userType()) { // We have T t, T* is requested, so return &t. *reinterpret_cast<void* *>(data) = var.data(); return true; - } else if (value.isObject()) { + } else if (value->isObject()) { // Look in the prototype chain. - QV4::ScopedObject proto(scope, value.objectValue()->prototype()); + QV4::Scope scope(this); + QV4::ScopedObject proto(scope, value->objectValue()->prototype()); while (proto) { bool canCast = false; if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) { @@ -1812,7 +1735,7 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da else if (proto->as<QV4::QObjectWrapper>()) { QByteArray className = name.left(name.size()-1); QV4::ScopedObject p(scope, proto.getPointer()); - if (QObject *qobject = qtObjectFromJS(scope.engine, p)) + if (QObject *qobject = qtObjectFromJS(this, p)) canCast = qobject->qt_metacast(className) != 0; } if (canCast) { @@ -1826,11 +1749,11 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da proto = proto->prototype(); } } - } else if (value.isNull() && name.endsWith('*')) { + } else if (value->isNull() && name.endsWith('*')) { *reinterpret_cast<void* *>(data) = 0; return true; } else if (type == qMetaTypeId<QJSValue>()) { - *reinterpret_cast<QJSValue*>(data) = QJSValue(this, value.asReturnedValue()); + *reinterpret_cast<QJSValue*>(data) = QJSValue(this, value->asReturnedValue()); return true; } diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index c0c88abaa5..9f44745e4c 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -37,6 +37,7 @@ #include "private/qv4isel_p.h" #include "qv4managed_p.h" #include "qv4context_p.h" +#include "qv4internalclass_p.h" #include <private/qintrusivelist_p.h> namespace WTF { @@ -50,6 +51,7 @@ class QV8Engine; class QQmlError; class QJSEngine; class QQmlEngine; +class QQmlContextData; namespace QV4 { namespace Debugging { @@ -80,8 +82,6 @@ public: Value *jsStackTop; quint32 hasException; - Heap::GlobalContext *m_rootContext; - Heap::GlobalContext *rootContext() const { return m_rootContext; } MemoryManager *memoryManager; ExecutableAllocator *executableAllocator; @@ -106,14 +106,19 @@ public: --jsStackTop; return jsStackTop->heapObject(); } + Value *jsAlloca(int nValues) { + Value *ptr = jsStackTop; + jsStackTop = ptr + nValues; + memset(ptr, 0, nValues*sizeof(Value)); + return ptr; + } IdentifierTable *identifierTable; QV4::Debugging::Debugger *debugger; QV4::Profiling::Profiler *profiler; - Value m_globalObject; - Object *globalObject() { return reinterpret_cast<Object *>(&m_globalObject); } + Object *globalObject; Function *globalCode; @@ -121,47 +126,97 @@ public: QQmlEngine *qmlEngine() const; QV8Engine *v8Engine; - Value objectCtor; - Value stringCtor; - Value numberCtor; - Value booleanCtor; - Value arrayCtor; - Value functionCtor; - Value dateCtor; - Value regExpCtor; - Value errorCtor; - Value evalErrorCtor; - Value rangeErrorCtor; - Value referenceErrorCtor; - Value syntaxErrorCtor; - Value typeErrorCtor; - Value uRIErrorCtor; - Value arrayBufferCtor; - Value dataViewCtor; - enum { NTypedArrayTypes = 9 }; // avoid header dependency - Value typedArrayCtors[NTypedArrayTypes]; - - Value objectPrototype; - Value arrayPrototype; - Value stringPrototype; - Value numberPrototype; - Value booleanPrototype; - Value datePrototype; - Value functionPrototype; - Value regExpPrototype; - Value errorPrototype; - Value evalErrorPrototype; - Value rangeErrorPrototype; - Value referenceErrorPrototype; - Value syntaxErrorPrototype; - Value typeErrorPrototype; - Value uRIErrorPrototype; - Value variantPrototype; - Value sequencePrototype; - - Value arrayBufferPrototype; - Value dataViewPrototype; - Value typedArrayPrototype[NTypedArrayTypes]; // TypedArray::NValues, avoid including the header here + enum JSObjects { + RootContect, + ObjectProto, + ArrayProto, + StringProto, + NumberProto, + BooleanProto, + DateProto, + FunctionProto, + RegExpProto, + ErrorProto, + EvalErrorProto, + RangeErrorProto, + ReferenceErrorProto, + SyntaxErrorProto, + TypeErrorProto, + URIErrorProto, + VariantProto, + SequenceProto, + ArrayBufferProto, + DataViewProto, + ValueTypeProto, + + Object_Ctor, + String_Ctor, + Number_Ctor, + Boolean_Ctor, + Array_Ctor, + Function_Ctor, + Date_Ctor, + RegExp_Ctor, + Error_Ctor, + EvalError_Ctor, + RangeError_Ctor, + ReferenceError_Ctor, + SyntaxError_Ctor, + TypeError_Ctor, + URIError_Ctor, + ArrayBuffer_Ctor, + DataView_Ctor, + + Eval_Function, + ThrowerObject, + NJSObjects + }; + Value *jsObjects; + enum { NTypedArrayTypes = 9 }; // == TypedArray::NValues, avoid header dependency + + GlobalContext *rootContext() const { return reinterpret_cast<GlobalContext *>(jsObjects + RootContect); } + FunctionObject *objectCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Object_Ctor); } + FunctionObject *stringCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + String_Ctor); } + FunctionObject *numberCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Number_Ctor); } + FunctionObject *booleanCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Boolean_Ctor); } + FunctionObject *arrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Array_Ctor); } + FunctionObject *functionCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Function_Ctor); } + FunctionObject *dateCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Date_Ctor); } + FunctionObject *regExpCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + RegExp_Ctor); } + FunctionObject *errorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Error_Ctor); } + FunctionObject *evalErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + EvalError_Ctor); } + FunctionObject *rangeErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + RangeError_Ctor); } + FunctionObject *referenceErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ReferenceError_Ctor); } + FunctionObject *syntaxErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + SyntaxError_Ctor); } + FunctionObject *typeErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + TypeError_Ctor); } + FunctionObject *uRIErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + URIError_Ctor); } + FunctionObject *arrayBufferCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ArrayBuffer_Ctor); } + FunctionObject *dataViewCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + DataView_Ctor); } + FunctionObject *typedArrayCtors; + + Object *objectPrototype() const { return reinterpret_cast<Object *>(jsObjects + ObjectProto); } + Object *arrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayProto); } + Object *stringPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringProto); } + Object *numberPrototype() const { return reinterpret_cast<Object *>(jsObjects + NumberProto); } + Object *booleanPrototype() const { return reinterpret_cast<Object *>(jsObjects + BooleanProto); } + Object *datePrototype() const { return reinterpret_cast<Object *>(jsObjects + DateProto); } + Object *functionPrototype() const { return reinterpret_cast<Object *>(jsObjects + FunctionProto); } + Object *regExpPrototype() const { return reinterpret_cast<Object *>(jsObjects + RegExpProto); } + Object *errorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ErrorProto); } + Object *evalErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + EvalErrorProto); } + Object *rangeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + RangeErrorProto); } + Object *referenceErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ReferenceErrorProto); } + Object *syntaxErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SyntaxErrorProto); } + Object *typeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + TypeErrorProto); } + Object *uRIErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + URIErrorProto); } + Object *variantPrototype() const { return reinterpret_cast<Object *>(jsObjects + VariantProto); } + Object *sequencePrototype() const { return reinterpret_cast<Object *>(jsObjects + SequenceProto); } + + Object *arrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayBufferProto); } + Object *dataViewPrototype() const { return reinterpret_cast<Object *>(jsObjects + DataViewProto); } + Object *typedArrayPrototype; + + Object *valueTypeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + ValueTypeProto); } InternalClassPool *classPool; InternalClass *emptyClass; @@ -177,48 +232,89 @@ public: InternalClass *argumentsObjectClass; InternalClass *strictArgumentsObjectClass; - Heap::EvalFunction *evalFunction; - Heap::FunctionObject *thrower; + EvalFunction *evalFunction() const { return reinterpret_cast<EvalFunction *>(jsObjects + Eval_Function); } + FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); } Property *argumentsAccessors; int nArgumentsAccessors; - StringValue id_empty; - StringValue id_undefined; - StringValue id_null; - StringValue id_true; - StringValue id_false; - StringValue id_boolean; - StringValue id_number; - StringValue id_string; - StringValue id_object; - StringValue id_function; - StringValue id_length; - StringValue id_prototype; - StringValue id_constructor; - StringValue id_arguments; - StringValue id_caller; - StringValue id_callee; - StringValue id_this; - StringValue id___proto__; - StringValue id_enumerable; - StringValue id_configurable; - StringValue id_writable; - StringValue id_value; - StringValue id_get; - StringValue id_set; - StringValue id_eval; - StringValue id_uintMax; - StringValue id_name; - StringValue id_index; - StringValue id_input; - StringValue id_toString; - StringValue id_destroy; - StringValue id_valueOf; - StringValue id_byteLength; - StringValue id_byteOffset; - StringValue id_buffer; - StringValue id_lastIndex; + enum JSStrings { + String_Empty, + String_undefined, + String_null, + String_true, + String_false, + String_boolean, + String_number, + String_string, + String_object, + String_function, + String_length, + String_prototype, + String_constructor, + String_arguments, + String_caller, + String_callee, + String_this, + String___proto__, + String_enumerable, + String_configurable, + String_writable, + String_value, + String_get, + String_set, + String_eval, + String_uintMax, + String_name, + String_index, + String_input, + String_toString, + String_destroy, + String_valueOf, + String_byteLength, + String_byteOffset, + String_buffer, + String_lastIndex, + NJSStrings + }; + Value *jsStrings; + + String *id_empty() const { return reinterpret_cast<String *>(jsStrings + String_Empty); } + String *id_undefined() const { return reinterpret_cast<String *>(jsStrings + String_undefined); } + String *id_null() const { return reinterpret_cast<String *>(jsStrings + String_null); } + String *id_true() const { return reinterpret_cast<String *>(jsStrings + String_true); } + String *id_false() const { return reinterpret_cast<String *>(jsStrings + String_false); } + String *id_boolean() const { return reinterpret_cast<String *>(jsStrings + String_boolean); } + String *id_number() const { return reinterpret_cast<String *>(jsStrings + String_number); } + String *id_string() const { return reinterpret_cast<String *>(jsStrings + String_string); } + String *id_object() const { return reinterpret_cast<String *>(jsStrings + String_object); } + String *id_function() const { return reinterpret_cast<String *>(jsStrings + String_function); } + String *id_length() const { return reinterpret_cast<String *>(jsStrings + String_length); } + String *id_prototype() const { return reinterpret_cast<String *>(jsStrings + String_prototype); } + String *id_constructor() const { return reinterpret_cast<String *>(jsStrings + String_constructor); } + String *id_arguments() const { return reinterpret_cast<String *>(jsStrings + String_arguments); } + String *id_caller() const { return reinterpret_cast<String *>(jsStrings + String_caller); } + String *id_callee() const { return reinterpret_cast<String *>(jsStrings + String_callee); } + String *id_this() const { return reinterpret_cast<String *>(jsStrings + String_this); } + String *id___proto__() const { return reinterpret_cast<String *>(jsStrings + String___proto__); } + String *id_enumerable() const { return reinterpret_cast<String *>(jsStrings + String_enumerable); } + String *id_configurable() const { return reinterpret_cast<String *>(jsStrings + String_configurable); } + String *id_writable() const { return reinterpret_cast<String *>(jsStrings + String_writable); } + String *id_value() const { return reinterpret_cast<String *>(jsStrings + String_value); } + String *id_get() const { return reinterpret_cast<String *>(jsStrings + String_get); } + String *id_set() const { return reinterpret_cast<String *>(jsStrings + String_set); } + String *id_eval() const { return reinterpret_cast<String *>(jsStrings + String_eval); } + String *id_uintMax() const { return reinterpret_cast<String *>(jsStrings + String_uintMax); } + String *id_name() const { return reinterpret_cast<String *>(jsStrings + String_name); } + String *id_index() const { return reinterpret_cast<String *>(jsStrings + String_index); } + String *id_input() const { return reinterpret_cast<String *>(jsStrings + String_input); } + String *id_toString() const { return reinterpret_cast<String *>(jsStrings + String_toString); } + String *id_destroy() const { return reinterpret_cast<String *>(jsStrings + String_destroy); } + String *id_valueOf() const { return reinterpret_cast<String *>(jsStrings + String_valueOf); } + String *id_byteLength() const { return reinterpret_cast<String *>(jsStrings + String_byteLength); } + String *id_byteOffset() const { return reinterpret_cast<String *>(jsStrings + String_byteOffset); } + String *id_buffer() const { return reinterpret_cast<String *>(jsStrings + String_buffer); } + String *id_lastIndex() const { return reinterpret_cast<String *>(jsStrings + String_lastIndex); } QSet<CompiledData::CompilationUnit*> compilationUnits; @@ -261,7 +357,7 @@ public: Heap::String *newString(const QString &s = QString()); Heap::String *newIdentifier(const QString &text); - Heap::Object *newStringObject(const Value &value); + Heap::Object *newStringObject(const String *string); Heap::Object *newNumberObject(double value); Heap::Object *newBooleanObject(bool b); @@ -291,7 +387,11 @@ public: Heap::Object *newForEachIteratorObject(Object *o); - Heap::Object *qmlContextObject() const; + Heap::QmlContext *qmlContext() const; + QV4::Heap::QmlContextWrapper *qmlContextObject() const; + QObject *qmlScopeObject() const; + QQmlContextData *callingQmlContext() const; + StackTrace stackTrace(int frameLimit = -1) const; StackFrame currentStackFrame() const; @@ -305,12 +405,10 @@ public: InternalClass *newClass(const InternalClass &other); - QmlExtensions *qmlExtensions(); - bool recheckCStackLimits(); // Exception handling - Value exceptionValue; + Value *exceptionValue; StackTrace exceptionStackTrace; ReturnedValue throwError(const Value &value); @@ -335,15 +433,12 @@ public: QVariant toVariant(const QV4::Value &value, int typeHint, bool createJSValueForObjects = true); QV4::ReturnedValue fromVariant(const QVariant &); - QVariantMap variantMapFromJS(QV4::Object *o); + QVariantMap variantMapFromJS(const QV4::Object *o); - bool metaTypeFromJS(const Value &value, int type, void *data); + bool metaTypeFromJS(const Value *value, int type, void *data); QV4::ReturnedValue metaTypeToJS(int type, const void *data); - void assertObjectBelongsToEngine(const Value &v); - -private: - QmlExtensions *m_qmlExtensions; + void assertObjectBelongsToEngine(const Heap::Base &baseObject); }; inline void ExecutionEngine::pushContext(CallContext *context) @@ -376,29 +471,26 @@ Heap::ExecutionContext::ExecutionContext(ExecutionEngine *engine, ContextType t) } -// ### Remove me inline -void Managed::mark(QV4::ExecutionEngine *engine) +void Heap::Base::mark(QV4::ExecutionEngine *engine) { Q_ASSERT(inUse()); - if (markBit()) + if (isMarked()) return; #ifndef QT_NO_DEBUG engine->assertObjectBelongsToEngine(*this); #endif - d()->setMarkBit(); - engine->pushForGC(d()); + setMarkBit(); + engine->pushForGC(this); } - -inline -void Heap::Base::mark(QV4::ExecutionEngine *engine) +inline void Value::mark(ExecutionEngine *e) { - Q_ASSERT(inUse()); - if (isMarked()) + if (!_val) return; - setMarkBit(); - engine->pushForGC(this); + Managed *m = as<Managed>(); + if (m) + m->d()->mark(e); } diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index 9034dee6a0..a6c2a25b91 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -33,11 +33,14 @@ #include "qv4errorobject_p.h" -#include "qv4mm_p.h" +#include <QtCore/qnumeric.h> +#include <QtCore/qmath.h> #include <QtCore/QDateTime> #include <QtCore/QStringList> #include <QtCore/QDebug> +#include "qv4string_p.h" +#include <private/qv4mm_p.h> #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> #include <private/qqmljsparser_p.h> @@ -179,57 +182,57 @@ DEFINE_OBJECT_VTABLE(ErrorObject); DEFINE_OBJECT_VTABLE(SyntaxErrorObject); Heap::SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const Value &msg) - : Heap::ErrorObject(engine->emptyClass, engine->syntaxErrorPrototype.asObject(), msg, SyntaxError) + : Heap::ErrorObject(engine->emptyClass, engine->syntaxErrorPrototype(), msg, SyntaxError) { } Heap::SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber) - : Heap::ErrorObject(engine->emptyClass, engine->syntaxErrorPrototype.asObject(), msg, fileName, lineNumber, columnNumber, SyntaxError) + : Heap::ErrorObject(engine->emptyClass, engine->syntaxErrorPrototype(), msg, fileName, lineNumber, columnNumber, SyntaxError) { } Heap::EvalErrorObject::EvalErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->evalErrorPrototype.asObject(), message, EvalError) + : Heap::ErrorObject(engine->emptyClass, engine->evalErrorPrototype(), message, EvalError) { } Heap::RangeErrorObject::RangeErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->rangeErrorPrototype.asObject(), message, RangeError) + : Heap::ErrorObject(engine->emptyClass, engine->rangeErrorPrototype(), message, RangeError) { } Heap::RangeErrorObject::RangeErrorObject(ExecutionEngine *engine, const QString &message) - : Heap::ErrorObject(engine->emptyClass, engine->rangeErrorPrototype.asObject(), message, RangeError) + : Heap::ErrorObject(engine->emptyClass, engine->rangeErrorPrototype(), message, RangeError) { } Heap::ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype.asObject(), message, ReferenceError) + : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype(), message, ReferenceError) { } Heap::ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &message) - : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype.asObject(), message, ReferenceError) + : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype(), message, ReferenceError) { } Heap::ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber) - : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype.asObject(), msg, fileName, lineNumber, columnNumber, ReferenceError) + : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype(), msg, fileName, lineNumber, columnNumber, ReferenceError) { } Heap::TypeErrorObject::TypeErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->typeErrorPrototype.asObject(), message, TypeError) + : Heap::ErrorObject(engine->emptyClass, engine->typeErrorPrototype(), message, TypeError) { } Heap::TypeErrorObject::TypeErrorObject(ExecutionEngine *engine, const QString &message) - : Heap::ErrorObject(engine->emptyClass, engine->typeErrorPrototype.asObject(), message, TypeError) + : Heap::ErrorObject(engine->emptyClass, engine->typeErrorPrototype(), message, TypeError) { } Heap::URIErrorObject::URIErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->uRIErrorPrototype.asObject(), message, URIError) + : Heap::ErrorObject(engine->emptyClass, engine->uRIErrorPrototype(), message, URIError) { } @@ -251,16 +254,16 @@ Heap::ErrorCtor::ErrorCtor(QV4::ExecutionContext *scope, const QString &name) { } -ReturnedValue ErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue ErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<ErrorCtor *>(m)->engine()); + Scope scope(static_cast<const ErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); return Encode(scope.engine->newErrorObject(v)); } -ReturnedValue ErrorCtor::call(Managed *that, CallData *callData) +ReturnedValue ErrorCtor::call(const Managed *that, CallData *callData) { - return static_cast<Object *>(that)->construct(callData); + return static_cast<const Object *>(that)->construct(callData); } Heap::EvalErrorCtor::EvalErrorCtor(QV4::ExecutionContext *scope) @@ -268,9 +271,9 @@ Heap::EvalErrorCtor::EvalErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue EvalErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue EvalErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<EvalErrorCtor *>(m)->engine()); + Scope scope(static_cast<const EvalErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); return (scope.engine->memoryManager->alloc<EvalErrorObject>(scope.engine, v))->asReturnedValue(); } @@ -280,9 +283,9 @@ Heap::RangeErrorCtor::RangeErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue RangeErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue RangeErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<RangeErrorCtor *>(m)->engine()); + Scope scope(static_cast<const RangeErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); return (scope.engine->memoryManager->alloc<RangeErrorObject>(scope.engine, v))->asReturnedValue(); } @@ -292,9 +295,9 @@ Heap::ReferenceErrorCtor::ReferenceErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ReferenceErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue ReferenceErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<ReferenceErrorCtor *>(m)->engine()); + Scope scope(static_cast<const ReferenceErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); return (scope.engine->memoryManager->alloc<ReferenceErrorObject>(scope.engine, v))->asReturnedValue(); } @@ -304,9 +307,9 @@ Heap::SyntaxErrorCtor::SyntaxErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue SyntaxErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue SyntaxErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<SyntaxErrorCtor *>(m)->engine()); + Scope scope(static_cast<const SyntaxErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); return (scope.engine->memoryManager->alloc<SyntaxErrorObject>(scope.engine, v))->asReturnedValue(); } @@ -316,9 +319,9 @@ Heap::TypeErrorCtor::TypeErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue TypeErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue TypeErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<TypeErrorCtor *>(m)->engine()); + Scope scope(static_cast<const TypeErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); return (scope.engine->memoryManager->alloc<TypeErrorObject>(scope.engine, v))->asReturnedValue(); } @@ -328,9 +331,9 @@ Heap::URIErrorCtor::URIErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue URIErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue URIErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<URIErrorCtor *>(m)->engine()); + Scope scope(static_cast<const URIErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); return (scope.engine->memoryManager->alloc<URIErrorObject>(scope.engine, v))->asReturnedValue(); } @@ -340,10 +343,10 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj) Scope scope(engine); ScopedString s(scope); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_prototype, (o = obj)); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = obj)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); obj->defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - obj->defineDefaultProperty(engine->id_toString, method_toString, 0); + obj->defineDefaultProperty(engine->id_toString(), method_toString, 0); obj->defineDefaultProperty(QStringLiteral("message"), (s = engine->newString())); } @@ -351,18 +354,18 @@ ReturnedValue ErrorPrototype::method_toString(CallContext *ctx) { Scope scope(ctx); - Object *o = ctx->thisObject().asObject(); + Object *o = ctx->thisObject().as<Object>(); if (!o) return ctx->engine()->throwTypeError(); - ScopedValue name(scope, o->get(ctx->d()->engine->id_name)); + ScopedValue name(scope, o->get(ctx->d()->engine->id_name())); QString qname; if (name->isUndefined()) - qname = QString::fromLatin1("Error"); + qname = QStringLiteral("Error"); else qname = name->toQString(); - ScopedString s(scope, ctx->d()->engine->newString(QString::fromLatin1("message"))); + ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("message"))); ScopedValue message(scope, o->get(s)); QString qmessage; if (!message->isUndefined()) diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 071f5b8c9a..e0fbcb4d8d 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -62,7 +62,7 @@ struct ErrorObject : Object { ErrorType errorType; StackTrace stackTrace; - String *stack; + Pointer<String> stack; }; struct EvalErrorObject : ErrorObject { @@ -141,8 +141,8 @@ struct ErrorObject: Object { }; template<> -inline ErrorObject *value_cast(const Value &v) { - return v.asErrorObject(); +inline const ErrorObject *Value::as() const { + return isManaged() && m() && m()->vtable()->isErrorObject ? reinterpret_cast<const ErrorObject *>(this) : 0; } struct EvalErrorObject: ErrorObject { @@ -183,50 +183,50 @@ struct ErrorCtor: FunctionObject { V4_OBJECT2(ErrorCtor, FunctionObject) - static ReturnedValue construct(Managed *, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct EvalErrorCtor: ErrorCtor { V4_OBJECT2(EvalErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; struct RangeErrorCtor: ErrorCtor { V4_OBJECT2(RangeErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; struct ReferenceErrorCtor: ErrorCtor { V4_OBJECT2(ReferenceErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; struct SyntaxErrorCtor: ErrorCtor { V4_OBJECT2(SyntaxErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; struct TypeErrorCtor: ErrorCtor { V4_OBJECT2(TypeErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; struct URIErrorCtor: ErrorCtor { V4_OBJECT2(URIErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index be63b31e1e..98a4490211 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -34,10 +34,10 @@ #include "qv4function_p.h" #include "qv4managed_p.h" #include "qv4string_p.h" -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #include "qv4engine_p.h" #include "qv4lookup_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 0a12d013ac..da01592c0d 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -37,7 +37,7 @@ #include "qv4objectproto_p.h" #include "qv4stringobject_p.h" #include "qv4function_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4arrayobject_p.h" #include "qv4scopedvalue_p.h" @@ -63,7 +63,7 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(FunctionObject); Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, QV4::String *name, bool createProto) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype.asObject()) + : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) , scope(scope->d()) , function(Q_NULLPTR) { @@ -73,7 +73,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, QV4::String * } Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, Function *function, bool createProto) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype.asObject()) + : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) , scope(scope->d()) , function(Q_NULLPTR) { @@ -84,7 +84,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, Function *fun } Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const QString &name, bool createProto) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype.asObject()) + : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) , scope(scope->d()) , function(Q_NULLPTR) { @@ -95,7 +95,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const QString } Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto) - : Heap::Object(scope->engine->functionClass, scope->engine->functionPrototype.asObject()) + : Heap::Object(scope->engine->functionClass, scope->engine->functionPrototype()) , scope(scope) , function(Q_NULLPTR) { @@ -106,7 +106,7 @@ Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const QString &nam } Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const ReturnedValue name) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype.asObject()) + : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) , scope(scope->d()) , function(Q_NULLPTR) { @@ -117,7 +117,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const Returne } Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValue name) - : Heap::Object(scope->engine->functionClass, scope->engine->functionPrototype.asObject()) + : Heap::Object(scope->engine->functionClass, scope->engine->functionPrototype()) , scope(scope) , function(Q_NULLPTR) { @@ -129,7 +129,7 @@ Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValu Heap::FunctionObject::FunctionObject(InternalClass *ic, QV4::Object *prototype) : Heap::Object(ic, prototype) - , scope(ic->engine->rootContext()) + , scope(ic->engine->rootContext()->d()) , function(Q_NULLPTR) { Scope scope(ic->engine); @@ -152,7 +152,7 @@ void FunctionObject::init(String *n, bool createProto) ensureMemberIndex(s.engine, Heap::FunctionObject::Index_Prototype); if (createProto) { - ScopedObject proto(s, scope()->engine->newObject(s.engine->protoClass, s.engine->objectPrototype.asObject())); + ScopedObject proto(s, scope()->engine->newObject(s.engine->protoClass, s.engine->objectPrototype())); proto->ensureMemberIndex(s.engine, Heap::FunctionObject::Index_ProtoConstructor); proto->memberData()->data[Heap::FunctionObject::Index_ProtoConstructor] = this->asReturnedValue(); memberData()->data[Heap::FunctionObject::Index_Prototype] = proto.asReturnedValue(); @@ -161,12 +161,12 @@ void FunctionObject::init(String *n, bool createProto) } ScopedValue v(s, n); - defineReadonlyProperty(s.engine->id_name, v); + defineReadonlyProperty(s.engine->id_name(), v); } -ReturnedValue FunctionObject::name() +ReturnedValue FunctionObject::name() const { - return get(scope()->engine->id_name); + return get(scope()->engine->id_name()); } @@ -177,13 +177,12 @@ ReturnedValue FunctionObject::newInstance() return construct(callData); } -ReturnedValue FunctionObject::construct(Managed *that, CallData *) +ReturnedValue FunctionObject::construct(const Managed *that, CallData *) { - static_cast<FunctionObject *>(that)->internalClass()->engine->throwTypeError(); - return Encode::undefined(); + return static_cast<const FunctionObject *>(that)->engine()->throwTypeError(); } -ReturnedValue FunctionObject::call(Managed *, CallData *) +ReturnedValue FunctionObject::call(const Managed *, CallData *) { return Encode::undefined(); } @@ -209,12 +208,12 @@ Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *sco bool FunctionObject::isBinding() const { - return d()->vtable == QQmlBindingFunction::staticVTable(); + return d()->vtable() == QQmlBindingFunction::staticVTable(); } bool FunctionObject::isBoundFunction() const { - return d()->vtable == BoundFunction::staticVTable(); + return d()->vtable() == BoundFunction::staticVTable(); } QQmlSourceLocation FunctionObject::sourceLocation() const @@ -237,10 +236,10 @@ Heap::FunctionCtor::FunctionCtor(QV4::ExecutionContext *scope) } // 15.3.2 -ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData) +ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) { - Scope scope(static_cast<Object *>(that)->engine()); - Scoped<FunctionCtor> f(scope, static_cast<FunctionCtor *>(that)); + Scope scope(static_cast<const Object *>(that)->engine()); + Scoped<FunctionCtor> f(scope, static_cast<const FunctionCtor *>(that)); ScopedContext ctx(scope, scope.engine->currentContext()); QString arguments; QString body; @@ -287,7 +286,7 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData) } // 15.3.1: This is equivalent to new Function(...) -ReturnedValue FunctionCtor::call(Managed *that, CallData *callData) +ReturnedValue FunctionCtor::call(const Managed *that, CallData *callData) { return construct(that, callData); } @@ -304,12 +303,12 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor) Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); - defineReadonlyProperty(engine->id_length, Primitive::fromInt32(0)); + defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(0)); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString, 0); + defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("apply"), method_apply, 2); defineDefaultProperty(QStringLiteral("call"), method_call, 1); defineDefaultProperty(QStringLiteral("bind"), method_bind, 1); @@ -318,7 +317,7 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor) ReturnedValue FunctionPrototype::method_toString(CallContext *ctx) { - FunctionObject *fun = ctx->thisObject().asFunctionObject(); + FunctionObject *fun = ctx->thisObject().as<FunctionObject>(); if (!fun) return ctx->engine()->throwTypeError(); @@ -328,7 +327,7 @@ ReturnedValue FunctionPrototype::method_toString(CallContext *ctx) ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) { Scope scope(ctx); - ScopedFunctionObject o(scope, ctx->thisObject().asFunctionObject()); + ScopedFunctionObject o(scope, ctx->thisObject().as<FunctionObject>()); if (!o) return ctx->engine()->throwTypeError(); @@ -370,7 +369,7 @@ ReturnedValue FunctionPrototype::method_call(CallContext *ctx) { Scope scope(ctx); - ScopedFunctionObject o(scope, ctx->thisObject().asFunctionObject()); + ScopedFunctionObject o(scope, ctx->thisObject().as<FunctionObject>()); if (!o) return ctx->engine()->throwTypeError(); @@ -409,15 +408,15 @@ Heap::ScriptFunction::ScriptFunction(QV4::ExecutionContext *scope, Function *fun { } -ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData) +ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(that)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<ScriptFunction> f(scope, static_cast<ScriptFunction *>(that)); + Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); InternalClass *ic = scope.engine->emptyClass; ScopedObject proto(scope, f->protoForConstructor()); @@ -441,15 +440,15 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData) return obj.asReturnedValue(); } -ReturnedValue ScriptFunction::call(Managed *that, CallData *callData) +ReturnedValue ScriptFunction::call(const Managed *that, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(that)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<ScriptFunction> f(scope, static_cast<ScriptFunction *>(that)); + Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); ScopedContext context(scope, v4->currentContext()); Scoped<CallContext> ctx(scope, context->newCallContext(f, callData)); @@ -458,7 +457,7 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData) ScopedValue result(scope, Q_V4_PROFILE(v4, f->function())); if (f->function()->compiledFunction->hasQmlDependencies()) - QmlContextWrapper::registerQmlDependencies(ctx->d()->engine, f->function()->compiledFunction); + QmlContextWrapper::registerQmlDependencies(scope.engine, f->function()->compiledFunction); return result->asReturnedValue(); } @@ -466,7 +465,7 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData) DEFINE_OBJECT_VTABLE(SimpleScriptFunction); Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, Function *function, bool createProto) - : Heap::FunctionObject(function->compilationUnit->engine->simpleScriptFunctionClass, function->compilationUnit->engine->functionPrototype.asObject()) + : Heap::FunctionObject(function->compilationUnit->engine->simpleScriptFunctionClass, function->compilationUnit->engine->functionPrototype()) { this->scope = scope->d(); @@ -481,7 +480,7 @@ Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, F if (createProto) { ScopedString name(s, function->name()); f->init(name, createProto); - f->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(f->formalParameterCount())); + f->defineReadonlyProperty(scope->d()->engine->id_length(), Primitive::fromInt32(f->formalParameterCount())); } else { f->ensureMemberIndex(s.engine, Index_Length); memberData->data[Index_Name] = function->name(); @@ -490,22 +489,22 @@ Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, F if (scope->d()->strictMode) { ScopedProperty pd(s); - pd->value = s.engine->thrower; - pd->set = s.engine->thrower; - f->insertMember(scope->d()->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - f->insertMember(scope->d()->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + pd->value = s.engine->thrower(); + pd->set = s.engine->thrower(); + f->insertMember(scope->d()->engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + f->insertMember(scope->d()->engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); } } -ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData) +ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(that)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<SimpleScriptFunction> f(scope, static_cast<SimpleScriptFunction *>(that)); + Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); InternalClass *ic = scope.engine->emptyClass; ScopedObject proto(scope, f->protoForConstructor()); @@ -514,7 +513,10 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData) ExecutionContextSaver ctxSaver(scope, v4->currentContext()); CallContext::Data ctx(v4); - ctx.vtable = CallContext::staticVTable(); +#ifndef QT_NO_DEBUG + ctx.mm_data = 0; // make sure we don't run into the assertion in setVTable when allocating a context on the stack +#endif + ctx.setVtable(CallContext::staticVTable()); ctx.strictMode = f->strictMode(); ctx.callData = callData; ctx.function = f->d(); @@ -536,20 +538,23 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData) return result.asReturnedValue(); } -ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData) +ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData) { - ExecutionEngine *v4 = static_cast<SimpleScriptFunction *>(that)->internalClass()->engine; + ExecutionEngine *v4 = static_cast<const SimpleScriptFunction *>(that)->internalClass()->engine; if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<SimpleScriptFunction> f(scope, static_cast<SimpleScriptFunction *>(that)); + Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); ExecutionContextSaver ctxSaver(scope, v4->currentContext()); CallContext::Data ctx(v4); - ctx.vtable = CallContext::staticVTable(); +#ifndef QT_NO_DEBUG + ctx.mm_data = 0; // make sure we don't run into the assertion in setVTable when allocating a context on the stack +#endif + ctx.setVtable(CallContext::staticVTable()); ctx.strictMode = f->strictMode(); ctx.callData = callData; ctx.function = f->d(); @@ -575,7 +580,7 @@ Heap::Object *SimpleScriptFunction::protoForConstructor() ScopedObject p(scope, protoProperty()); if (p) return p->d(); - return scope.engine->objectPrototype.asObject()->d(); + return scope.engine->objectPrototype()->d(); } @@ -588,14 +593,14 @@ Heap::BuiltinFunction::BuiltinFunction(QV4::ExecutionContext *scope, QV4::String { } -ReturnedValue BuiltinFunction::construct(Managed *f, CallData *) +ReturnedValue BuiltinFunction::construct(const Managed *f, CallData *) { - return static_cast<BuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); + return static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); } -ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData) +ReturnedValue BuiltinFunction::call(const Managed *that, CallData *callData) { - BuiltinFunction *f = static_cast<BuiltinFunction *>(that); + const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that); ExecutionEngine *v4 = f->internalClass()->engine; if (v4->hasException) return Encode::undefined(); @@ -605,7 +610,10 @@ ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData) ExecutionContextSaver ctxSaver(scope, v4->currentContext()); CallContext::Data ctx(v4); - ctx.vtable = CallContext::staticVTable(); +#ifndef QT_NO_DEBUG + ctx.mm_data = 0; // make sure we don't run into the assertion in setVTable when allocating a context on the stack +#endif + ctx.setVtable(CallContext::staticVTable()); ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context? ctx.callData = callData; Q_ASSERT(v4->currentContext() == &ctx); @@ -614,9 +622,9 @@ ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData) return f->d()->code(sctx); } -ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData) +ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callData) { - IndexedBuiltinFunction *f = static_cast<IndexedBuiltinFunction *>(that); + const IndexedBuiltinFunction *f = static_cast<const IndexedBuiltinFunction *>(that); ExecutionEngine *v4 = f->internalClass()->engine; if (v4->hasException) return Encode::undefined(); @@ -626,7 +634,10 @@ ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData) ExecutionContextSaver ctxSaver(scope, v4->currentContext()); CallContext::Data ctx(v4); - ctx.vtable = CallContext::staticVTable(); +#ifndef QT_NO_DEBUG + ctx.mm_data = 0; // make sure we don't run into the assertion in setVTable when allocating a context on the stack +#endif + ctx.setVtable(CallContext::staticVTable()); ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context? ctx.callData = callData; Q_ASSERT(v4->currentContext() == &ctx); @@ -650,24 +661,24 @@ Heap::BoundFunction::BoundFunction(QV4::ExecutionContext *scope, QV4::FunctionOb Scope s(scope); ScopedObject f(s, this); - ScopedValue l(s, target->get(s.engine->id_length)); + ScopedValue l(s, target->get(s.engine->id_length())); int len = l->toUInt32(); if (boundArgs) len -= boundArgs->size(); if (len < 0) len = 0; - f->defineReadonlyProperty(s.engine->id_length, Primitive::fromInt32(len)); + f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(len)); ScopedProperty pd(s); - pd->value = s.engine->thrower; - pd->set = s.engine->thrower; - f->insertMember(s.engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - f->insertMember(s.engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + pd->value = s.engine->thrower(); + pd->set = s.engine->thrower(); + f->insertMember(s.engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); } -ReturnedValue BoundFunction::call(Managed *that, CallData *dd) +ReturnedValue BoundFunction::call(const Managed *that, CallData *dd) { - BoundFunction *f = static_cast<BoundFunction *>(that); + const BoundFunction *f = static_cast<const BoundFunction *>(that); Scope scope(f->engine()); if (scope.hasException()) return Encode::undefined(); @@ -685,9 +696,9 @@ ReturnedValue BoundFunction::call(Managed *that, CallData *dd) return t->call(callData); } -ReturnedValue BoundFunction::construct(Managed *that, CallData *dd) +ReturnedValue BoundFunction::construct(const Managed *that, CallData *dd) { - BoundFunction *f = static_cast<BoundFunction *>(that); + const BoundFunction *f = static_cast<const BoundFunction *>(that); Scope scope(f->engine()); if (scope.hasException()) return Encode::undefined(); diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 252ff40a1a..2c6a195746 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -36,7 +36,7 @@ #include "qv4object_p.h" #include "qv4function_p.h" #include "qv4context_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> QT_BEGIN_NAMESPACE @@ -65,7 +65,7 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; } bool needsActivation() const { return function ? function->needsActivation() : false; } - ExecutionContext *scope; + Pointer<ExecutionContext> scope; Function *function; }; @@ -102,9 +102,9 @@ struct ScriptFunction : SimpleScriptFunction { struct BoundFunction : FunctionObject { BoundFunction(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs); - FunctionObject *target; + Pointer<FunctionObject> target; Value boundThis; - MemberData *boundArgs; + Pointer<MemberData> boundArgs; }; } @@ -117,12 +117,12 @@ struct Q_QML_EXPORT FunctionObject: Object { Q_MANAGED_TYPE(FunctionObject) V4_NEEDS_DESTROY - Heap::ExecutionContext *scope() { return d()->scope; } - Function *function() { return d()->function; } + Heap::ExecutionContext *scope() const { return d()->scope; } + Function *function() const { return d()->function; } - ReturnedValue name(); - unsigned int formalParameterCount() { return d()->formalParameterCount(); } - unsigned int varCount() { return d()->varCount(); } + ReturnedValue name() const; + unsigned int formalParameterCount() const { return d()->formalParameterCount(); } + unsigned int varCount() const { return d()->varCount(); } void init(String *name, bool createProto); @@ -130,12 +130,8 @@ struct Q_QML_EXPORT FunctionObject: Object { using Object::construct; using Object::call; - static ReturnedValue construct(Managed *that, CallData *); - static ReturnedValue call(Managed *that, CallData *d); - - static FunctionObject *cast(const Value &v) { - return v.asFunctionObject(); - } + static ReturnedValue construct(const Managed *that, CallData *); + static ReturnedValue call(const Managed *that, CallData *d); static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true); @@ -152,16 +148,17 @@ struct Q_QML_EXPORT FunctionObject: Object { }; template<> -inline FunctionObject *value_cast(const Value &v) { - return v.asFunctionObject(); +inline const FunctionObject *Value::as() const { + return isManaged() && m() && m()->vtable()->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : 0; } + struct FunctionCtor: FunctionObject { V4_OBJECT2(FunctionCtor, FunctionObject) - static ReturnedValue construct(Managed *that, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct FunctionPrototype: FunctionObject @@ -184,20 +181,20 @@ struct Q_QML_EXPORT BuiltinFunction: FunctionObject { return scope->engine()->memoryManager->alloc<BuiltinFunction>(scope, name, code); } - static ReturnedValue construct(Managed *, CallData *); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *, CallData *); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct IndexedBuiltinFunction: FunctionObject { V4_OBJECT2(IndexedBuiltinFunction, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *) + static ReturnedValue construct(const Managed *m, CallData *) { - return static_cast<IndexedBuiltinFunction *>(m)->engine()->throwTypeError(); + return static_cast<const IndexedBuiltinFunction *>(m)->engine()->throwTypeError(); } - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; Heap::IndexedBuiltinFunction::IndexedBuiltinFunction(QV4::ExecutionContext *scope, uint index, @@ -212,8 +209,8 @@ Heap::IndexedBuiltinFunction::IndexedBuiltinFunction(QV4::ExecutionContext *scop struct SimpleScriptFunction: FunctionObject { V4_OBJECT2(SimpleScriptFunction, FunctionObject) - static ReturnedValue construct(Managed *, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); Heap::Object *protoForConstructor(); }; @@ -221,8 +218,8 @@ struct SimpleScriptFunction: FunctionObject { struct ScriptFunction: SimpleScriptFunction { V4_OBJECT2(ScriptFunction, FunctionObject) - static ReturnedValue construct(Managed *, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; @@ -234,12 +231,12 @@ struct BoundFunction: FunctionObject { return scope->engine()->memoryManager->alloc<BoundFunction>(scope, target, boundThis, boundArgs); } - Heap::FunctionObject *target() { return d()->target; } + Heap::FunctionObject *target() const { return d()->target; } Value boundThis() const { return d()->boundThis; } Heap::MemberData *boundArgs() const { return d()->boundArgs; } - static ReturnedValue construct(Managed *, CallData *d); - static ReturnedValue call(Managed *that, CallData *dd); + static ReturnedValue construct(const Managed *, CallData *d); + static ReturnedValue call(const Managed *that, CallData *dd); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 4b08194b60..759c6795e2 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -88,6 +88,8 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); } #define V4_ENABLE_JIT #endif +#elif defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX) +#define V4_ENABLE_JIT #endif // Black list some platforms @@ -168,7 +170,7 @@ struct Property; struct Value; struct Lookup; struct ArrayData; -struct ManagedVTable; +struct VTable; struct BooleanObject; struct NumberObject; @@ -211,7 +213,6 @@ class WeakValue; struct IdentifierTable; class RegExpCache; class MultiplyWrappedQObjectMap; -struct QmlExtensions; namespace Global { enum { @@ -277,8 +278,6 @@ struct PropertyAttributes setConfigurable(!(f & Attr_NotConfigurable)); } } - PropertyAttributes(const PropertyAttributes &other) : m_all(other.m_all) {} - PropertyAttributes & operator=(const PropertyAttributes &other) { m_all = other.m_all; return *this; } void setType(Type t) { m_type = t; type_set = true; } Type type() const { return type_set ? (Type)m_type : Generic; } diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 8e33cec57f..ec7b9b3f7d 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -32,13 +32,15 @@ ****************************************************************************/ #include "qv4globalobject_p.h" -#include "qv4mm_p.h" -#include "qv4value_inl_p.h" +#include <private/qv4mm_p.h> +#include "qv4value_p.h" #include "qv4context_p.h" #include "qv4function_p.h" #include "qv4debugging_p.h" +#include "qv4profiling_p.h" #include "qv4script_p.h" #include "qv4scopedvalue_p.h" +#include "qv4string_p.h" #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> @@ -47,6 +49,7 @@ #include <qv4jsir_p.h> #include <qv4codegen_p.h> #include "private/qlocale_tools_p.h" +#include "private/qtools_p.h" #include <QtCore/QDebug> #include <QtCore/QString> @@ -56,25 +59,8 @@ #include <wtf/MathExtras.h> using namespace QV4; - - -static inline char toHex(char c) -{ - static const char hexnumbers[] = "0123456789ABCDEF"; - return hexnumbers[c & 0xf]; -} - -static int fromHex(QChar ch) -{ - ushort c = ch.unicode(); - if ((c >= '0') && (c <= '9')) - return c - '0'; - if ((c >= 'A') && (c <= 'F')) - return c - 'A' + 10; - if ((c >= 'a') && (c <= 'f')) - return c - 'a' + 10; - return -1; -} +using QtMiscUtils::toHexUpper; +using QtMiscUtils::fromHex; static QString escape(const QString &input) { @@ -93,16 +79,16 @@ static QString escape(const QString &input) output.append(QChar(uc)); } else { output.append('%'); - output.append(QLatin1Char(toHex(uc >> 4))); - output.append(QLatin1Char(toHex(uc))); + output.append(QLatin1Char(toHexUpper(uc >> 4))); + output.append(QLatin1Char(toHexUpper(uc))); } } else { output.append('%'); output.append('u'); - output.append(QLatin1Char(toHex(uc >> 12))); - output.append(QLatin1Char(toHex(uc >> 8))); - output.append(QLatin1Char(toHex(uc >> 4))); - output.append(QLatin1Char(toHex(uc))); + output.append(QLatin1Char(toHexUpper(uc >> 12))); + output.append(QLatin1Char(toHexUpper(uc >> 8))); + output.append(QLatin1Char(toHexUpper(uc >> 4))); + output.append(QLatin1Char(toHexUpper(uc))); } } return output; @@ -119,10 +105,10 @@ static QString unescape(const QString &input) if ((c == '%') && (i + 1 < length)) { QChar a = input.at(i); if ((a == 'u') && (i + 4 < length)) { - int d3 = fromHex(input.at(i+1)); - int d2 = fromHex(input.at(i+2)); - int d1 = fromHex(input.at(i+3)); - int d0 = fromHex(input.at(i+4)); + int d3 = fromHex(input.at(i+1).unicode()); + int d2 = fromHex(input.at(i+2).unicode()); + int d1 = fromHex(input.at(i+3).unicode()); + int d0 = fromHex(input.at(i+4).unicode()); if ((d3 != -1) && (d2 != -1) && (d1 != -1) && (d0 != -1)) { ushort uc = ushort((d3 << 12) | (d2 << 8) | (d1 << 4) | d0); result.append(QChar(uc)); @@ -131,8 +117,8 @@ static QString unescape(const QString &input) result.append(c); } } else { - int d1 = fromHex(a); - int d0 = fromHex(input.at(i+1)); + int d1 = fromHex(a.unicode()); + int d0 = fromHex(input.at(i+1).unicode()); if ((d1 != -1) && (d0 != -1)) { c = (d1 << 4) | d0; i += 2; @@ -153,8 +139,8 @@ static const char uriUnescapedReserved[] = "-_.!~*'();/?:@&=+$,#"; static void addEscapeSequence(QString &output, uchar ch) { output.append(QLatin1Char('%')); - output.append(QLatin1Char(toHex(ch >> 4))); - output.append(QLatin1Char(toHex(ch & 0xf))); + output.append(QLatin1Char(toHexUpper(ch >> 4))); + output.append(QLatin1Char(toHexUpper(ch & 0xf))); } static QString encode(const QString &input, const char *unescapedSet, bool *ok) @@ -246,8 +232,8 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok) if (i + 2 >= length) goto error; - int d1 = fromHex(input.at(i+1)); - int d0 = fromHex(input.at(i+2)); + int d1 = fromHex(input.at(i+1).unicode()); + int d0 = fromHex(input.at(i+2).unicode()); if ((d1 == -1) || (d0 == -1)) goto error; @@ -281,8 +267,8 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok) if (input.at(i) != percent) goto error; - d1 = fromHex(input.at(i+1)); - d0 = fromHex(input.at(i+2)); + d1 = fromHex(input.at(i+1).unicode()); + d0 = fromHex(input.at(i+2).unicode()); if ((d1 == -1) || (d0 == -1)) goto error; @@ -339,14 +325,14 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok) DEFINE_OBJECT_VTABLE(EvalFunction); Heap::EvalFunction::EvalFunction(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope, scope->d()->engine->id_eval) + : Heap::FunctionObject(scope, scope->d()->engine->id_eval()) { Scope s(scope); ScopedFunctionObject f(s, this); - f->defineReadonlyProperty(s.engine->id_length, Primitive::fromInt32(1)); + f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(1)); } -ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) +ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const { if (callData->argc < 1) return Encode::undefined(); @@ -395,14 +381,14 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) ctx->d()->strictMode = false; ctx->d()->compilationUnit = function->compilationUnit; - return function->code(ctx->engine(), function->codeData); + return Q_V4_PROFILE(ctx->engine(), function); } -ReturnedValue EvalFunction::call(Managed *that, CallData *callData) +ReturnedValue EvalFunction::call(const Managed *that, CallData *callData) { // indirect call - return static_cast<EvalFunction *>(that)->evalCall(callData, false); + return static_cast<const EvalFunction *>(that)->evalCall(callData, false); } diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h index 74de233b47..ba1d5d2e0b 100644 --- a/src/qml/jsruntime/qv4globalobject_p.h +++ b/src/qml/jsruntime/qv4globalobject_p.h @@ -52,10 +52,10 @@ struct Q_QML_EXPORT EvalFunction : FunctionObject { V4_OBJECT2(EvalFunction, FunctionObject) - ReturnedValue evalCall(CallData *callData, bool directCall); + ReturnedValue evalCall(CallData *callData, bool directCall) const; using Object::construct; - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct GlobalFunctions diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h index ff374225f4..58f808b4d5 100644 --- a/src/qml/jsruntime/qv4identifiertable_p.h +++ b/src/qml/jsruntime/qv4identifiertable_p.h @@ -80,8 +80,8 @@ public: if (!entry || entry->isMarked()) continue; entry->setMarkBit(); - Q_ASSERT(entry->gcGetVtable()->markObjects); - entry->gcGetVtable()->markObjects(entry, e); + Q_ASSERT(entry->vtable()->markObjects); + entry->vtable()->markObjects(entry, e); } } }; diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index e4bd460966..2eb61081c7 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -54,7 +54,7 @@ QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QQmlContex : v4(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0), m_context(context) { m_qmlglobal.set(engine, qmlglobal); - if (callback.asFunctionObject()) + if (callback.as<QV4::FunctionObject>()) m_callbackFunction.set(engine, callback); m_resultObject.set(v4, resultValue(v4)); @@ -94,14 +94,14 @@ void QV4Include::callback(const QV4::Value &callback, const QV4::Value &status) { if (!callback.isObject()) return; - QV4::ExecutionEngine *v4 = callback.asObject()->engine(); + QV4::ExecutionEngine *v4 = callback.as<QV4::Object>()->engine(); QV4::Scope scope(v4); QV4::ScopedFunctionObject f(scope, callback); if (!f) return; QV4::ScopedCallData callData(scope, 1); - callData->thisObject = v4->globalObject()->asReturnedValue(); + callData->thisObject = v4->globalObject->asReturnedValue(); callData->args[0] = status; f->call(callData); if (scope.hasException()) @@ -176,7 +176,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) return QV4::Encode::undefined(); QV4::Scope scope(ctx->engine()); - QQmlContextData *context = QV4::QmlContextWrapper::callingContext(scope.engine); + QQmlContextData *context = scope.engine->callingQmlContext(); if (!context || !context->isJSContext) V4THROW_ERROR("Qt.include(): Can only be called from JavaScript files"); @@ -184,7 +184,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) QUrl url(scope.engine->resolvedUrl(ctx->args()[0].toQStringNoThrow())); QV4::ScopedValue callbackFunction(scope, QV4::Primitive::undefinedValue()); - if (ctx->argc() >= 2 && ctx->args()[1].asFunctionObject()) + if (ctx->argc() >= 2 && ctx->args()[1].as<QV4::FunctionObject>()) callbackFunction = ctx->args()[1]; QString localFile = QQmlFile::urlToLocalFileOrQrc(url); @@ -224,7 +224,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) QV4::ScopedValue ex(scope, scope.engine->catchException()); result = resultValue(scope.engine, Exception); QV4::ScopedString exception(scope, scope.engine->newString(QStringLiteral("exception"))); - result->asObject()->put(exception, ex); + result->as<QV4::Object>()->put(exception, ex); } else { result = resultValue(scope.engine, Ok); } diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h index 5dc94e8555..5ef4442b03 100644 --- a/src/qml/jsruntime/qv4include_p.h +++ b/src/qml/jsruntime/qv4include_p.h @@ -50,7 +50,7 @@ #include <private/qqmlcontext_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4context_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 3289058cb7..80590fe72e 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -46,7 +46,7 @@ struct String; struct ExecutionEngine; struct Object; struct Identifier; -struct ManagedVTable; +struct VTable; struct PropertyHashData; struct PropertyHash diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index e7905974df..f703e85399 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -38,8 +38,8 @@ #include <qv4objectiterator_p.h> #include <qv4scopedvalue_p.h> #include <qv4runtime_p.h> +#include "qv4string_p.h" -#include <qjsondocument.h> #include <qstack.h> #include <qstringlist.h> @@ -62,33 +62,6 @@ static int indent = 0; DEFINE_OBJECT_VTABLE(JsonObject); -class JsonParser -{ -public: - JsonParser(ExecutionEngine *engine, const QChar *json, int length); - - ReturnedValue parse(QJsonParseError *error); - -private: - inline bool eatSpace(); - inline QChar nextToken(); - - ReturnedValue parseObject(); - ReturnedValue parseArray(); - bool parseMember(Object *o); - bool parseString(QString *string); - bool parseValue(Value *val); - bool parseNumber(Value *val); - - ExecutionEngine *engine; - const QChar *head; - const QChar *json; - const QChar *end; - - int nestingLevel; - QJsonParseError::ParseError lastError; -}; - static const int nestingLimit = 1024; @@ -639,17 +612,22 @@ bool JsonParser::parseString(QString *string) struct Stringify { - ExecutionContext *ctx; + ExecutionEngine *v4; FunctionObject *replacerFunction; - // ### GC - QVector<Heap::String *> propertyList; + QV4::String *propertyList; + int propertyListSize; QString gap; QString indent; + QStack<Object *> stack; - // ### GC - QStack<Heap::Object *> stack; + bool stackContains(Object *o) { + for (int i = 0; i < stack.size(); ++i) + if (stack.at(i)->d() == o->d()) + return true; + return false; + } - Stringify(ExecutionContext *ctx) : ctx(ctx), replacerFunction(0) {} + Stringify(ExecutionEngine *e) : v4(e), replacerFunction(0), propertyList(0), propertyListSize(0) {} QString Str(const QString &key, const Value &v); QString JA(ArrayObject *a); @@ -701,26 +679,26 @@ static QString quote(const QString &str) QString Stringify::Str(const QString &key, const Value &v) { - Scope scope(ctx); + Scope scope(v4); ScopedValue value(scope, v); ScopedObject o(scope, value); if (o) { - ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toJSON"))); + ScopedString s(scope, v4->newString(QStringLiteral("toJSON"))); ScopedFunctionObject toJSON(scope, o->get(s)); if (!!toJSON) { ScopedCallData callData(scope, 1); callData->thisObject = value; - callData->args[0] = ctx->d()->engine->newString(key); + callData->args[0] = v4->newString(key); value = toJSON->call(callData); } } if (replacerFunction) { - ScopedObject holder(scope, ctx->d()->engine->newObject()); + ScopedObject holder(scope, v4->newObject()); holder->put(scope.engine, QString(), value); ScopedCallData callData(scope, 2); - callData->args[0] = ctx->d()->engine->newString(key); + callData->args[0] = v4->newString(key); callData->args[1] = value; callData->thisObject = holder; value = replacerFunction->call(callData); @@ -728,11 +706,11 @@ QString Stringify::Str(const QString &key, const Value &v) o = value->asReturnedValue(); if (o) { - if (NumberObject *n = o->asNumberObject()) + if (NumberObject *n = o->as<NumberObject>()) value = Encode(n->value()); - else if (StringObject *so = o->asStringObject()) - value = so->d()->value; - else if (BooleanObject *b =o->asBooleanObject()) + else if (StringObject *so = o->as<StringObject>()) + value = so->d()->string; + else if (BooleanObject *b = o->as<BooleanObject>()) value = Encode(b->value()); } @@ -750,8 +728,8 @@ QString Stringify::Str(const QString &key, const Value &v) o = value->asReturnedValue(); if (o) { - if (!o->asFunctionObject()) { - if (o->asArrayObject()) { + if (!o->as<FunctionObject>()) { + if (o->as<ArrayObject>()) { return JA(static_cast<ArrayObject *>(o.getPointer())); } else { return JO(o); @@ -777,20 +755,20 @@ QString Stringify::makeMember(const QString &key, const Value &v) QString Stringify::JO(Object *o) { - if (stack.contains(o->d())) { - ctx->engine()->throwTypeError(); + if (stackContains(o)) { + v4->throwTypeError(); return QString(); } - Scope scope(ctx); + Scope scope(v4); QString result; - stack.push(o->d()); + stack.push(o); QString stepback = indent; indent += gap; QStringList partial; - if (propertyList.isEmpty()) { + if (!propertyListSize) { ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); ScopedValue name(scope); @@ -805,11 +783,13 @@ QString Stringify::JO(Object *o) partial += member; } } else { - ScopedString s(scope); - for (int i = 0; i < propertyList.size(); ++i) { + ScopedValue v(scope); + for (int i = 0; i < propertyListSize; ++i) { bool exists; - s = propertyList.at(i); - ScopedValue v(scope, o->get(s, &exists)); + String *s = propertyList + i; + if (!s) + continue; + v = o->get(s, &exists); if (!exists) continue; QString member = makeMember(s->toQString(), v); @@ -834,15 +814,15 @@ QString Stringify::JO(Object *o) QString Stringify::JA(ArrayObject *a) { - if (stack.contains(a->d())) { - ctx->engine()->throwTypeError(); + if (stackContains(a)) { + v4->throwTypeError(); return QString(); } Scope scope(a->engine()); QString result; - stack.push(a->d()); + stack.push(a); QString stepback = indent; indent += gap; @@ -879,7 +859,7 @@ QString Stringify::JA(ArrayObject *a) Heap::JsonObject::JsonObject(ExecutionEngine *e) - : Heap::Object(e->emptyClass, e->objectPrototype.asObject()) + : Heap::Object(e->emptyClass, e->objectPrototype()) { Scope scope(e); ScopedObject o(scope, this); @@ -911,32 +891,38 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx) { Scope scope(ctx); - Stringify stringify(ctx); + Stringify stringify(scope.engine); ScopedObject o(scope, ctx->argument(1)); if (o) { - stringify.replacerFunction = o->asFunctionObject(); + stringify.replacerFunction = o->as<FunctionObject>(); if (o->isArrayObject()) { uint arrayLen = o->getLength(); - ScopedValue v(scope); + stringify.propertyList = static_cast<QV4::String *>(scope.alloc(arrayLen)); for (uint i = 0; i < arrayLen; ++i) { - v = o->getIndexed(i); - if (v->asNumberObject() || v->asStringObject() || v->isNumber()) - v = RuntimeHelpers::toString(scope.engine, v); - if (v->isString()) { - String *s = v->stringValue(); - if (!stringify.propertyList.contains(s->d())) - stringify.propertyList.append(s->d()); + Value *v = stringify.propertyList + i; + *v = o->getIndexed(i); + if (v->as<NumberObject>() || v->as<StringObject>() || v->isNumber()) + *v = RuntimeHelpers::toString(scope.engine, *v); + if (!v->isString()) { + v->setM(0); + } else { + for (uint j = 0; j <i; ++j) { + if (stringify.propertyList[j].m() == v->m()) { + v->setM(0); + break; + } + } } } } } ScopedValue s(scope, ctx->argument(2)); - if (NumberObject *n = s->asNumberObject()) + if (NumberObject *n = s->as<NumberObject>()) s = Encode(n->value()); - else if (StringObject *so = s->asStringObject()) - s = so->d()->value; + else if (StringObject *so = s->as<StringObject>()) + s = so->d()->string; if (s->isNumber()) { stringify.gap = QString(qMin(10, (int)s->toInteger()), ' '); @@ -986,7 +972,7 @@ QJsonValue JsonObject::toJsonValue(const Value &value, V4ObjectSet &visitedObjec return QJsonValue(value.toQString()); Q_ASSERT(value.isObject()); - Scope scope(value.asObject()->engine()); + Scope scope(value.as<Object>()->engine()); ScopedArrayObject a(scope, value); if (a) return toJsonArray(a, visitedObjects); @@ -1009,22 +995,22 @@ QV4::ReturnedValue JsonObject::fromJsonObject(ExecutionEngine *engine, const QJs return o.asReturnedValue(); } -QJsonObject JsonObject::toJsonObject(Object *o, V4ObjectSet &visitedObjects) +QJsonObject JsonObject::toJsonObject(const Object *o, V4ObjectSet &visitedObjects) { QJsonObject result; - if (!o || o->asFunctionObject()) + if (!o || o->as<FunctionObject>()) return result; Scope scope(o->engine()); - if (visitedObjects.contains(o->d())) { + if (visitedObjects.contains(ObjectItem(o))) { // Avoid recursion. // For compatibility with QVariant{List,Map} conversion, we return an // empty object (and no error is thrown). return result; } - visitedObjects.insert(o->d()); + visitedObjects.insert(ObjectItem(o)); ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); ScopedValue name(scope); @@ -1035,11 +1021,11 @@ QJsonObject JsonObject::toJsonObject(Object *o, V4ObjectSet &visitedObjects) break; QString key = name->toQStringNoThrow(); - if (!val->asFunctionObject()) + if (!val->as<FunctionObject>()) result.insert(key, toJsonValue(val, visitedObjects)); } - visitedObjects.remove(o->d()); + visitedObjects.remove(ObjectItem(o)); return result; } @@ -1057,7 +1043,7 @@ QV4::ReturnedValue JsonObject::fromJsonArray(ExecutionEngine *engine, const QJso return a.asReturnedValue(); } -QJsonArray JsonObject::toJsonArray(ArrayObject *a, V4ObjectSet &visitedObjects) +QJsonArray JsonObject::toJsonArray(const ArrayObject *a, V4ObjectSet &visitedObjects) { QJsonArray result; if (!a) @@ -1065,25 +1051,25 @@ QJsonArray JsonObject::toJsonArray(ArrayObject *a, V4ObjectSet &visitedObjects) Scope scope(a->engine()); - if (visitedObjects.contains(a->d())) { + if (visitedObjects.contains(ObjectItem(a))) { // Avoid recursion. // For compatibility with QVariant{List,Map} conversion, we return an // empty array (and no error is thrown). return result; } - visitedObjects.insert(a->d()); + visitedObjects.insert(ObjectItem(a)); ScopedValue v(scope); quint32 length = a->getLength(); for (quint32 i = 0; i < length; ++i) { v = a->getIndexed(i); - if (v->asFunctionObject()) + if (v->as<FunctionObject>()) v = Encode::null(); result.append(toJsonValue(v, visitedObjects)); } - visitedObjects.remove(a->d()); + visitedObjects.remove(ObjectItem(a)); return result; } diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h index 81a783ee92..1ad0e2c5de 100644 --- a/src/qml/jsruntime/qv4jsonobject_p.h +++ b/src/qml/jsruntime/qv4jsonobject_p.h @@ -37,6 +37,8 @@ #include <qjsonarray.h> #include <qjsonobject.h> #include <qjsonvalue.h> +#include <qjsondocument.h> +#include <qhash.h> QT_BEGIN_NAMESPACE @@ -50,12 +52,23 @@ struct JsonObject : Object { } +struct ObjectItem { + const QV4::Object *o; + ObjectItem(const QV4::Object *o) : o(o) {} +}; + +inline bool operator ==(const ObjectItem &a, const ObjectItem &b) +{ return a.o->d() == b.o->d(); } + +inline int qHash(const ObjectItem &i, uint seed = 0) +{ return ::qHash((void *)i.o->d(), seed); } + struct JsonObject : Object { Q_MANAGED_TYPE(JsonObject) V4_OBJECT2(JsonObject, Object) private: - // ### GC - typedef QSet<QV4::Heap::Base *> V4ObjectSet; + + typedef QSet<ObjectItem> V4ObjectSet; public: static ReturnedValue method_parse(CallContext *ctx); @@ -67,18 +80,45 @@ public: static inline QJsonValue toJsonValue(const QV4::Value &value) { V4ObjectSet visitedObjects; return toJsonValue(value, visitedObjects); } - static inline QJsonObject toJsonObject(QV4::Object *o) + static inline QJsonObject toJsonObject(const QV4::Object *o) { V4ObjectSet visitedObjects; return toJsonObject(o, visitedObjects); } - static inline QJsonArray toJsonArray(QV4::ArrayObject *a) + static inline QJsonArray toJsonArray(const QV4::ArrayObject *a) { V4ObjectSet visitedObjects; return toJsonArray(a, visitedObjects); } private: static QJsonValue toJsonValue(const QV4::Value &value, V4ObjectSet &visitedObjects); - static QJsonObject toJsonObject(Object *o, V4ObjectSet &visitedObjects); - static QJsonArray toJsonArray(ArrayObject *a, V4ObjectSet &visitedObjects); + static QJsonObject toJsonObject(const Object *o, V4ObjectSet &visitedObjects); + static QJsonArray toJsonArray(const ArrayObject *a, V4ObjectSet &visitedObjects); }; +class JsonParser +{ +public: + JsonParser(ExecutionEngine *engine, const QChar *json, int length); + + ReturnedValue parse(QJsonParseError *error); + +private: + inline bool eatSpace(); + inline QChar nextToken(); + + ReturnedValue parseObject(); + ReturnedValue parseArray(); + bool parseMember(Object *o); + bool parseString(QString *string); + bool parseValue(Value *val); + bool parseNumber(Value *val); + + ExecutionEngine *engine; + const QChar *head; + const QChar *json; + const QChar *end; + + int nestingLevel; + QJsonParseError::ParseError lastError; +}; + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 82b20337cb..443427b024 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -33,6 +33,7 @@ #include "qv4lookup_p.h" #include "qv4functionobject_p.h" #include "qv4scopedvalue_p.h" +#include "qv4string_p.h" QT_BEGIN_NAMESPACE @@ -72,7 +73,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu return Primitive::emptyValue().asReturnedValue(); } -ReturnedValue Lookup::lookup(Object *thisObject, PropertyAttributes *attrs) +ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs) { Heap::Object *obj = thisObject->d(); ExecutionEngine *engine = thisObject->engine(); @@ -123,7 +124,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons ScopedObject o(scope, object); if (!o) { if (idx < UINT_MAX) { - if (String *str = object.asString()) { + if (const String *str = object.as<String>()) { if (idx >= (uint)str->toQString().length()) { return Encode::undefined(); } @@ -168,7 +169,7 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con Object *o = object.objectValue(); if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { - Heap::SimpleArrayData *s = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (idx < s->len) if (!s->data(idx).isEmpty()) return s->data(idx).asReturnedValue(); @@ -200,7 +201,7 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value & uint idx = index.asArrayIndex(); if (idx < UINT_MAX) { if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { - Heap::SimpleArrayData *s = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (idx < s->len) { s->data(idx) = value; return; @@ -224,7 +225,7 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value Object *o = object.objectValue(); if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { - Heap::SimpleArrayData *s = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (idx < s->len) { s->data(idx) = v; return; @@ -235,7 +236,7 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (Object *o = object.asObject()) + if (const Object *o = object.as<Object>()) return o->getLookup(l); Object *proto; @@ -244,14 +245,14 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va case Value::Null_Type: return engine->throwTypeError(); case Value::Boolean_Type: - proto = engine->booleanPrototype.asObject(); + proto = engine->booleanPrototype(); break; case Value::Managed_Type: { Q_ASSERT(object.isString()); - proto = engine->stringPrototype.asObject(); + proto = engine->stringPrototype(); Scope scope(engine); ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); - if (name->equals(engine->id_length)) { + if (name->equals(engine->id_length())) { // special case, as the property is on the object itself l->getter = stringLengthGetter; return stringLengthGetter(l, engine, object); @@ -260,7 +261,7 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va } case Value::Integer_Type: default: // Number - proto = engine->numberPrototype.asObject(); + proto = engine->numberPrototype(); } PropertyAttributes attrs; @@ -291,7 +292,7 @@ ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Lookup l1 = *l; if (l1.getter == Lookup::getter0 || l1.getter == Lookup::getter1) { - if (Object *o = object.asObject()) { + if (const Object *o = object.as<Object>()) { ReturnedValue v = o->getLookup(l); Lookup l2 = *l; @@ -560,7 +561,7 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engin ReturnedValue Lookup::stringLengthGetter(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (String *s = object.asString()) + if (const String *s = object.as<String>()) return Encode(s->d()->length()); l->getter = getterGeneric; @@ -569,7 +570,7 @@ ReturnedValue Lookup::stringLengthGetter(Lookup *l, ExecutionEngine *engine, con ReturnedValue Lookup::arrayLengthGetter(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (ArrayObject *a = object.asArrayObject()) + if (const ArrayObject *a = object.as<ArrayObject>()) return a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].asReturnedValue(); l->getter = getterGeneric; @@ -579,7 +580,7 @@ ReturnedValue Lookup::arrayLengthGetter(Lookup *l, ExecutionEngine *engine, cons ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine) { - Object *o = engine->globalObject(); + Object *o = engine->globalObject; PropertyAttributes attrs; ReturnedValue v = l->lookup(o, &attrs); if (v != Primitive::emptyValue().asReturnedValue()) { @@ -608,7 +609,7 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionEngine *engine) { - Object *o = engine->globalObject(); + Object *o = engine->globalObject; if (l->classList[0] == o->internalClass()) return o->memberData()->data[l->index].asReturnedValue(); @@ -618,7 +619,7 @@ ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetter1(Lookup *l, ExecutionEngine *engine) { - Object *o = engine->globalObject(); + Object *o = engine->globalObject; if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) return o->prototype()->memberData->data[l->index].asReturnedValue(); @@ -629,7 +630,7 @@ ReturnedValue Lookup::globalGetter1(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetter2(Lookup *l, ExecutionEngine *engine) { - Heap::Object *o = engine->globalObject()->d(); + Heap::Object *o = engine->globalObject->d(); if (l->classList[0] == o->internalClass) { o = o->prototype; if (l->classList[1] == o->internalClass) { @@ -645,7 +646,7 @@ ReturnedValue Lookup::globalGetter2(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionEngine *engine) { - Object *o = engine->globalObject(); + Object *o = engine->globalObject; if (l->classList[0] == o->internalClass()) { Scope scope(o->engine()); ScopedFunctionObject getter(scope, o->propertyAt(l->index)->getter()); @@ -662,7 +663,7 @@ ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionEngine *engine) { - Object *o = engine->globalObject(); + Object *o = engine->globalObject; if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) { Scope scope(o->engine()); @@ -680,7 +681,7 @@ ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine) { - Heap::Object *o = engine->globalObject()->d(); + Heap::Object *o = engine->globalObject->d(); if (l->classList[0] == o->internalClass) { o = o->prototype; if (l->classList[1] == o->internalClass) { @@ -701,7 +702,7 @@ ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine) return globalGetterGeneric(l, engine); } -void Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { Scope scope(engine); ScopedObject o(scope, object); @@ -716,11 +717,11 @@ void Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, const Value &obje o->setLookup(l, value); } -void Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { Lookup l1 = *l; - if (Object *o = object.asObject()) { + if (Object *o = object.as<Object>()) { o->setLookup(l, value); if (l->setter == Lookup::setter0) { @@ -735,7 +736,7 @@ void Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &o setterFallback(l, engine, object, value); } -void Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { QV4::Scope scope(engine); QV4::ScopedObject o(scope, object.toObject(scope.engine)); @@ -745,9 +746,9 @@ void Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, const Value &obj } } -void Lookup::setter0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = static_cast<Object *>(object.asManaged()); + Object *o = object.as<Object>(); if (o && o->internalClass() == l->classList[0]) { o->memberData()->data[l->index] = value; return; @@ -756,9 +757,9 @@ void Lookup::setter0(Lookup *l, ExecutionEngine *engine, const Value &object, co setterTwoClasses(l, engine, object, value); } -void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = static_cast<Object *>(object.asManaged()); + Object *o = object.as<Object>(); if (o && o->internalClass() == l->classList[0]) { if (!o->prototype()) { if (!o->memberData() || l->index >= o->memberData()->size) @@ -773,9 +774,9 @@ void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, const Value &obje setterFallback(l, engine, object, value); } -void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = static_cast<Object *>(object.asManaged()); + Object *o = object.as<Object>(); if (o && o->internalClass() == l->classList[0]) { Heap::Object *p = o->prototype(); if (p && p->internalClass == l->classList[1]) { @@ -791,9 +792,9 @@ void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, const Value &obje setterFallback(l, engine, object, value); } -void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = static_cast<Object *>(object.asManaged()); + Object *o = object.as<Object>(); if (o && o->internalClass() == l->classList[0]) { Heap::Object *p = o->prototype(); if (p && p->internalClass == l->classList[1]) { @@ -812,9 +813,9 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, const Value &obje setterFallback(l, engine, object, value); } -void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = static_cast<Object *>(object.asManaged()); + Object *o = object.as<Object>(); if (o) { if (o->internalClass() == l->classList[0]) { o->memberData()->data[l->index] = value; diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 88397dc36c..232e909c48 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -51,7 +51,7 @@ struct Lookup { void (*indexedSetter)(Lookup *l, const Value &object, const Value &index, const Value &v); ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object); ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine); - void (*setter)(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &v); + void (*setter)(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v); }; union { ExecutionEngine *engine; @@ -107,17 +107,17 @@ struct Lookup { static ReturnedValue globalGetterAccessor1(Lookup *l, ExecutionEngine *engine); static ReturnedValue globalGetterAccessor2(Lookup *l, ExecutionEngine *engine); - static void setterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setter0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setterInsert0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setterInsert1(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setterInsert2(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setter0setter0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); + static void setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); ReturnedValue lookup(const Value &thisObject, Object *obj, PropertyAttributes *attrs); - ReturnedValue lookup(Object *obj, PropertyAttributes *attrs); + ReturnedValue lookup(const Object *obj, PropertyAttributes *attrs); }; diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index c4b9fc597e..bb7ee43b4e 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -32,13 +32,13 @@ ****************************************************************************/ #include "qv4managed_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4errorobject_p.h" using namespace QV4; -const ManagedVTable Managed::static_vtbl = +const VTable Managed::static_vtbl = { 0, Managed::IsExecutionContext, @@ -59,7 +59,7 @@ const ManagedVTable Managed::static_vtbl = QString Managed::className() const { const char *s = 0; - switch (Type(d()->vtable->type)) { + switch (Type(d()->vtable()->type)) { case Type_Invalid: case Type_String: return QString(); diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 0fe5c7ee49..6f5564300f 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -35,7 +35,7 @@ #include "qv4global_p.h" #include "qv4value_p.h" -#include "qv4internalclass_p.h" +#include <private/qv4heap_p.h> QT_BEGIN_NAMESPACE @@ -65,10 +65,10 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} Q_MANAGED_CHECK \ typedef QV4::Heap::DataClass Data; \ typedef superClass SuperClass; \ - static const QV4::ManagedVTable static_vtbl; \ - static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl; } \ + static const QV4::VTable static_vtbl; \ + static inline const QV4::VTable *staticVTable() { return &static_vtbl; } \ V4_MANAGED_SIZE_TEST \ - QV4::Heap::DataClass *d() const { return static_cast<QV4::Heap::DataClass *>(m); } + QV4::Heap::DataClass *d() const { return static_cast<QV4::Heap::DataClass *>(m()); } #define Q_MANAGED_TYPE(type) \ public: \ @@ -78,31 +78,6 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} (classname::func == QV4::Managed::func ? 0 : classname::func) -struct GCDeletable -{ - GCDeletable() : next(0), lastCall(false) {} - virtual ~GCDeletable() {} - GCDeletable *next; - bool lastCall; -}; - -struct ManagedVTable -{ - const ManagedVTable * const parent; - uint isExecutionContext : 1; - uint isString : 1; - uint isObject : 1; - uint isFunctionObject : 1; - uint isErrorObject : 1; - uint isArrayData : 1; - uint unused : 18; - uint type : 8; - const char *className; - void (*destroy)(Heap::Base *); - void (*markObjects)(Heap::Base *, ExecutionEngine *e); - bool (*isEqualTo)(Managed *m, Managed *other); -}; - #define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \ { \ parentVTable, \ @@ -121,7 +96,7 @@ struct ManagedVTable } #define DEFINE_MANAGED_VTABLE(classname) \ -const QV4::ManagedVTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname, 0) +const QV4::VTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname, 0) struct Q_QML_PRIVATE_EXPORT Managed : Value { @@ -141,8 +116,6 @@ private: public: - inline void mark(QV4::ExecutionEngine *engine); - enum Type { Type_Invalid, Type_String, @@ -167,55 +140,15 @@ public: }; Q_MANAGED_TYPE(Invalid) - template <typename T> - T *as() { - Q_ASSERT(d()->vtable); -#if !defined(QT_NO_QOBJECT_CHECK) - static_cast<T *>(this)->qt_check_for_QMANAGED_macro(static_cast<T *>(this)); -#endif - const ManagedVTable *vt = d()->vtable; - while (vt) { - if (vt == T::staticVTable()) - return static_cast<T *>(this); - vt = vt->parent; - } - return 0; - } - template <typename T> - const T *as() const { - Q_ASSERT(d()->vtable); -#if !defined(QT_NO_QOBJECT_CHECK) - static_cast<T *>(this)->qt_check_for_QMANAGED_macro(static_cast<T *>(const_cast<Managed *>(this))); -#endif - const ManagedVTable *vt = d()->vtable; - while (vt) { - if (vt == T::staticVTable()) - return static_cast<T *>(this); - vt = vt->parent; - } - return 0; - } - - String *asString() { return d()->vtable->isString ? reinterpret_cast<String *>(this) : 0; } - Object *asObject() { return d()->vtable->isObject ? reinterpret_cast<Object *>(this) : 0; } - ArrayObject *asArrayObject() { return d()->vtable->type == Type_ArrayObject ? reinterpret_cast<ArrayObject *>(this) : 0; } - FunctionObject *asFunctionObject() { return d()->vtable->isFunctionObject ? reinterpret_cast<FunctionObject *>(this) : 0; } - BooleanObject *asBooleanObject() { return d()->vtable->type == Type_BooleanObject ? reinterpret_cast<BooleanObject *>(this) : 0; } - NumberObject *asNumberObject() { return d()->vtable->type == Type_NumberObject ? reinterpret_cast<NumberObject *>(this) : 0; } - StringObject *asStringObject() { return d()->vtable->type == Type_StringObject ? reinterpret_cast<StringObject *>(this) : 0; } - DateObject *asDateObject() { return d()->vtable->type == Type_DateObject ? reinterpret_cast<DateObject *>(this) : 0; } - ErrorObject *asErrorObject() { return d()->vtable->isErrorObject ? reinterpret_cast<ErrorObject *>(this) : 0; } - ArgumentsObject *asArgumentsObject() { return d()->vtable->type == Type_ArgumentsObject ? reinterpret_cast<ArgumentsObject *>(this) : 0; } - - bool isListType() const { return d()->vtable->type == Type_QmlSequence; } - - bool isArrayObject() const { return d()->vtable->type == Type_ArrayObject; } - bool isStringObject() const { return d()->vtable->type == Type_StringObject; } + bool isListType() const { return d()->vtable()->type == Type_QmlSequence; } + + bool isArrayObject() const { return d()->vtable()->type == Type_ArrayObject; } + bool isStringObject() const { return d()->vtable()->type == Type_StringObject; } QString className() const; bool isEqualTo(const Managed *other) const - { return d()->vtable->isEqualTo(const_cast<Managed *>(this), const_cast<Managed *>(other)); } + { return d()->vtable()->isEqualTo(const_cast<Managed *>(this), const_cast<Managed *>(other)); } static bool isEqualTo(Managed *m, Managed *other); @@ -231,37 +164,15 @@ private: template<> -inline Managed *value_cast(const Value &v) { - return v.asManaged(); +inline const Managed *Value::as() const { + if (isManaged()) + return managed(); + return 0; } -template<typename T> -inline T *managed_cast(Managed *m) -{ - return m ? m->as<T>() : 0; -} - -template<> -inline String *managed_cast(Managed *m) -{ - return m ? m->asString() : 0; -} template<> -inline Object *managed_cast(Managed *m) -{ - return m ? m->asObject() : 0; -} -template<> -inline FunctionObject *managed_cast(Managed *m) -{ - return m ? m->asFunctionObject() : 0; -} - -inline Value Value::fromManaged(Managed *m) -{ - if (!m) - return QV4::Primitive::undefinedValue(); - return *m; +inline const Object *Value::as() const { + return isManaged() && m() && m()->vtable()->isObject ? objectValue() : 0; } } diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp index 473e05bf88..c498160c36 100644 --- a/src/qml/jsruntime/qv4mathobject.cpp +++ b/src/qml/jsruntime/qv4mathobject.cpp @@ -48,7 +48,7 @@ DEFINE_OBJECT_VTABLE(MathObject); static const double qt_PI = 2.0 * ::asin(1.0); Heap::MathObject::MathObject(ExecutionEngine *e) - : Heap::Object(e->emptyClass, e->objectPrototype.asObject()) + : Heap::Object(e->emptyClass, e->objectPrototype()) { Scope scope(e); ScopedObject m(scope, this); diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index 03dfee3dcf..5ec5cb1f58 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -32,7 +32,8 @@ ****************************************************************************/ #include "qv4memberdata_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> +#include "qv4value_p.h" using namespace QV4; diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index 4a1a94e872..4ae30a7f35 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -33,6 +33,7 @@ #include "qv4numberobject_p.h" #include "qv4runtime_p.h" +#include "qv4string_p.h" #include <QtCore/qnumeric.h> #include <QtCore/qmath.h> @@ -50,14 +51,14 @@ Heap::NumberCtor::NumberCtor(QV4::ExecutionContext *scope) { } -ReturnedValue NumberCtor::construct(Managed *m, CallData *callData) +ReturnedValue NumberCtor::construct(const Managed *m, CallData *callData) { Scope scope(m->cast<NumberCtor>()->engine()); double dbl = callData->argc ? callData->args[0].toNumber() : 0.; return Encode(scope.engine->newNumberObject(dbl)); } -ReturnedValue NumberCtor::call(Managed *, CallData *callData) +ReturnedValue NumberCtor::call(const Managed *, CallData *callData) { double dbl = callData->argc ? callData->args[0].toNumber() : 0.; return Encode(dbl); @@ -67,8 +68,8 @@ void NumberPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); ctor->defineReadonlyProperty(QStringLiteral("NaN"), Primitive::fromDouble(qSNaN())); ctor->defineReadonlyProperty(QStringLiteral("NEGATIVE_INFINITY"), Primitive::fromDouble(-qInf())); @@ -81,9 +82,9 @@ QT_WARNING_DISABLE_INTEL(239) QT_WARNING_POP defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString); + defineDefaultProperty(engine->id_toString(), method_toString); defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); - defineDefaultProperty(engine->id_valueOf, method_valueOf); + defineDefaultProperty(engine->id_valueOf(), method_valueOf); defineDefaultProperty(QStringLiteral("toFixed"), method_toFixed, 1); defineDefaultProperty(QStringLiteral("toExponential"), method_toExponential); defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision); @@ -93,7 +94,7 @@ inline ReturnedValue thisNumberValue(ExecutionContext *ctx) { if (ctx->thisObject().isNumber()) return ctx->thisObject().asReturnedValue(); - NumberObject *n = ctx->thisObject().asNumberObject(); + NumberObject *n = ctx->thisObject().as<NumberObject>(); if (!n) return ctx->engine()->throwTypeError(); return Encode(n->value()); @@ -103,7 +104,7 @@ inline double thisNumber(ExecutionContext *ctx) { if (ctx->thisObject().isNumber()) return ctx->thisObject().asDouble(); - NumberObject *n = ctx->thisObject().asNumberObject(); + NumberObject *n = ctx->thisObject().as<NumberObject>(); if (!n) return ctx->engine()->throwTypeError(); return n->value(); @@ -119,7 +120,7 @@ ReturnedValue NumberPrototype::method_toString(CallContext *ctx) if (ctx->argc() && !ctx->args()[0].isUndefined()) { int radix = ctx->args()[0].toInt32(); if (radix < 2 || radix > 36) - return ctx->engine()->throwError(QString::fromLatin1("Number.prototype.toString: %0 is not a valid radix") + return ctx->engine()->throwError(QStringLiteral("Number.prototype.toString: %0 is not a valid radix") .arg(radix)); if (std::isnan(num)) { @@ -197,7 +198,7 @@ ReturnedValue NumberPrototype::method_toFixed(CallContext *ctx) QString str; if (std::isnan(v)) - str = QString::fromLatin1("NaN"); + str = QStringLiteral("NaN"); else if (qIsInf(v)) str = QString::fromLatin1(v < 0 ? "-Infinity" : "Infinity"); else if (v < 1.e21) { diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h index 205995701b..04798d31fc 100644 --- a/src/qml/jsruntime/qv4numberobject_p.h +++ b/src/qml/jsruntime/qv4numberobject_p.h @@ -53,8 +53,8 @@ struct NumberCtor: FunctionObject { V4_OBJECT2(NumberCtor, FunctionObject) - static ReturnedValue construct(Managed *that, CallData *callData); - static ReturnedValue call(Managed *, CallData *callData); + static ReturnedValue construct(const Managed *that, CallData *callData); + static ReturnedValue call(const Managed *, CallData *callData); }; struct NumberPrototype: NumberObject diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 211fd1812e..b3c0863e3e 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -37,12 +37,13 @@ #include "qv4objectproto_p.h" #include "qv4stringobject_p.h" #include "qv4argumentsobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4lookup_p.h" #include "qv4scopedvalue_p.h" #include "qv4memberdata_p.h" #include "qv4objectiterator_p.h" #include "qv4identifier_p.h" +#include "qv4string_p.h" #include <stdint.h> @@ -138,7 +139,7 @@ void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(Ca ScopedString s(scope, e->newIdentifier(name)); ScopedContext global(scope, e->rootContext()); ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code)); - function->defineReadonlyProperty(e->id_length, Primitive::fromInt32(argumentCount)); + function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(s, function); } @@ -148,7 +149,7 @@ void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallConte Scope scope(e); ScopedContext global(scope, e->rootContext()); ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code)); - function->defineReadonlyProperty(e->id_length, Primitive::fromInt32(argumentCount)); + function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(name, function); } @@ -219,50 +220,50 @@ void Object::insertMember(String *s, const Property *p, PropertyAttributes attri } // Section 8.12.1 -Property *Object::__getOwnProperty__(String *name, PropertyAttributes *attrs) +void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p) { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) - return __getOwnProperty__(idx, attrs); + return getOwnProperty(idx, attrs, p); uint member = internalClass()->find(name); if (member < UINT_MAX) { - if (attrs) - *attrs = internalClass()->propertyData[member]; - return propertyAt(member); + *attrs = internalClass()->propertyData[member]; + if (p) + p->copy(propertyAt(member), *attrs); + return; } if (attrs) *attrs = Attr_Invalid; - return 0; + return; } -Property *Object::__getOwnProperty__(uint index, PropertyAttributes *attrs) +void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p) { - Property *p = arrayData() ? arrayData()->getProperty(index) : 0; - if (p) { - if (attrs) - *attrs = arrayData()->attributes(index); - return p; + Property *pd = arrayData() ? arrayData()->getProperty(index) : 0; + if (pd) { + *attrs = arrayData()->attributes(index); + if (p) + p->copy(pd, *attrs); + return; } if (isStringObject()) { - if (attrs) - *attrs = Attr_NotConfigurable|Attr_NotWritable; - return static_cast<StringObject *>(this)->getIndex(index); + *attrs = Attr_NotConfigurable|Attr_NotWritable; + if (p) + p->value = static_cast<StringObject *>(this)->getIndex(index); + return; } if (attrs) *attrs = Attr_Invalid; - return 0; + return; } // Section 8.12.2 Property *Object::__getPropertyDescriptor__(String *name, PropertyAttributes *attrs) const { - uint idx = name->asArrayIndex(); - if (idx != UINT_MAX) - return __getPropertyDescriptor__(idx, attrs); - + Q_ASSERT(name->asArrayIndex() == UINT_MAX); const Heap::Object *o = d(); while (o) { @@ -286,16 +287,15 @@ Property *Object::__getPropertyDescriptor__(uint index, PropertyAttributes *attr while (o) { Property *p = o->arrayData ? o->arrayData->getProperty(index) : 0; if (p) { - if (attrs) - *attrs = o->arrayData->attributes(index); + *attrs = o->arrayData->attributes(index); return p; } - if (o->vtable->type == Type_StringObject) { - Property *p = static_cast<const Heap::StringObject *>(o)->getIndex(index); - if (p) { - if (attrs) - *attrs = (Attr_NotWritable|Attr_NotConfigurable); - return p; + if (o->vtable()->type == Type_StringObject) { + if (index < static_cast<const Heap::StringObject *>(o)->length()) { + // this is an evil hack, but it works, as the method is only ever called from putIndexed, + // where we don't use the returned pointer there for non writable attributes + *attrs = (Attr_NotWritable|Attr_NotConfigurable); + return reinterpret_cast<Property *>(0x1); } } o = o->prototype; @@ -356,8 +356,7 @@ bool Object::hasOwnProperty(uint index) const return true; if (isStringObject()) { - String *s = static_cast<const StringObject *>(this)->d()->value.asString(); - if (index < (uint)s->d()->length()) + if (index < static_cast<const StringObject *>(this)->length()) return true; } if (!queryIndexed(index).isEmpty()) @@ -365,24 +364,24 @@ bool Object::hasOwnProperty(uint index) const return false; } -ReturnedValue Object::construct(Managed *m, CallData *) +ReturnedValue Object::construct(const Managed *m, CallData *) { - return static_cast<Object *>(m)->engine()->throwTypeError(); + return static_cast<const Object *>(m)->engine()->throwTypeError(); } -ReturnedValue Object::call(Managed *m, CallData *) +ReturnedValue Object::call(const Managed *m, CallData *) { - return static_cast<Object *>(m)->engine()->throwTypeError(); + return static_cast<const Object *>(m)->engine()->throwTypeError(); } -ReturnedValue Object::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue Object::get(const Managed *m, String *name, bool *hasProperty) { - return static_cast<Object *>(m)->internalGet(name, hasProperty); + return static_cast<const Object *>(m)->internalGet(name, hasProperty); } -ReturnedValue Object::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue Object::getIndexed(const Managed *m, uint index, bool *hasProperty) { - return static_cast<Object *>(m)->internalGetIndexed(index, hasProperty); + return static_cast<const Object *>(m)->internalGetIndexed(index, hasProperty); } void Object::put(Managed *m, String *name, const Value &value) @@ -416,8 +415,7 @@ PropertyAttributes Object::queryIndexed(const Managed *m, uint index) return o->arrayData()->attributes(index); if (o->isStringObject()) { - String *s = static_cast<const StringObject *>(o)->d()->value.asString(); - if (index < (uint)s->d()->length()) + if (index < static_cast<const StringObject *>(o)->length()) return (Attr_NotWritable|Attr_NotConfigurable); } return Attr_Invalid; @@ -433,9 +431,9 @@ bool Object::deleteIndexedProperty(Managed *m, uint index) return static_cast<Object *>(m)->internalDeleteIndexedProperty(index); } -ReturnedValue Object::getLookup(Managed *m, Lookup *l) +ReturnedValue Object::getLookup(const Managed *m, Lookup *l) { - Object *o = static_cast<Object *>(m); + const Object *o = static_cast<const Object *>(m); PropertyAttributes attrs; ReturnedValue v = l->lookup(o, &attrs); if (v != Primitive::emptyValue().asReturnedValue()) { @@ -516,10 +514,10 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value) l->setter = Lookup::setterGeneric; } -void Object::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *pd, PropertyAttributes *attrs) +void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *pd, PropertyAttributes *attrs) { Object *o = static_cast<Object *>(m); - *name = 0; + name->setM(0); *index = UINT_MAX; if (o->arrayData()) { @@ -531,7 +529,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name while (it->arrayNode != o->sparseEnd()) { int k = it->arrayNode->key(); uint pidx = it->arrayNode->value; - Heap::SparseArrayData *sa = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *sa = o->d()->arrayData.cast<Heap::SparseArrayData>(); Property *p = reinterpret_cast<Property *>(sa->arrayData + pidx); it->arrayNode = it->arrayNode->nextNode(); PropertyAttributes a = sa->attrs ? sa->attrs[pidx] : Attr_Data; @@ -548,7 +546,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name } // dense arrays while (it->arrayIndex < o->d()->arrayData->len) { - Heap::SimpleArrayData *sa = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *sa = o->d()->arrayData.cast<Heap::SimpleArrayData>(); Value &val = sa->data(it->arrayIndex); PropertyAttributes a = o->arrayData()->attributes(it->arrayIndex); ++it->arrayIndex; @@ -574,7 +572,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name PropertyAttributes a = o->internalClass()->propertyData[it->memberIndex]; ++it->memberIndex; if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { - *name = o->engine()->newString(n->string); + name->setM(o->engine()->newString(n->string)); *attrs = a; pd->copy(p, a); return; @@ -585,7 +583,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name } // Section 8.12.3 -ReturnedValue Object::internalGet(String *name, bool *hasProperty) +ReturnedValue Object::internalGet(String *name, bool *hasProperty) const { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) @@ -611,7 +609,7 @@ ReturnedValue Object::internalGet(String *name, bool *hasProperty) return Encode::undefined(); } -ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) +ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const { Property *pd = 0; PropertyAttributes attrs; @@ -625,10 +623,12 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) break; } if (o->isStringObject()) { - pd = static_cast<StringObject *>(o.getPointer())->getIndex(index); - if (pd) { + ScopedString str(scope, static_cast<StringObject *>(o.getPointer())->getIndex(index)); + if (str) { attrs = (Attr_NotWritable|Attr_NotConfigurable); - break; + if (hasProperty) + *hasProperty = true; + return str.asReturnedValue(); } } o = o->prototype(); @@ -674,7 +674,7 @@ void Object::internalPut(String *name, const Value &value) goto reject; } else if (!attrs.isWritable()) goto reject; - else if (isArrayObject() && name->equals(engine()->id_length)) { + else if (isArrayObject() && name->equals(engine()->id_length())) { bool ok; uint l = value.asArrayLength(&ok); if (!ok) { @@ -710,7 +710,7 @@ void Object::internalPut(String *name, const Value &value) // Clause 5 if (pd && attrs.isAccessor()) { - assert(pd->setter() != 0); + Q_ASSERT(pd->setter() != 0); Scope scope(engine()); ScopedFunctionObject setter(scope, pd->setter()); @@ -745,8 +745,7 @@ void Object::internalPutIndexed(uint index, const Value &value) attrs = arrayData()->attributes(index); if (!pd && isStringObject()) { - pd = static_cast<StringObject *>(this)->getIndex(index); - if (pd) + if (index < static_cast<StringObject *>(this)->length()) // not writable goto reject; } @@ -784,7 +783,7 @@ void Object::internalPutIndexed(uint index, const Value &value) // Clause 5 if (pd && attrs.isAccessor()) { - assert(pd->setter() != 0); + Q_ASSERT(pd->setter() != 0); Scope scope(engine()); ScopedFunctionObject setter(scope, pd->setter()); @@ -858,8 +857,8 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const PropertyAttributes *cattrs; uint memberIndex; - if (isArrayObject() && name->equals(engine->id_length)) { - Q_ASSERT(Heap::ArrayObject::LengthPropertyIndex == internalClass()->find(engine->id_length)); + if (isArrayObject() && name->equals(engine->id_length())) { + Q_ASSERT(Heap::ArrayObject::LengthPropertyIndex == internalClass()->find(engine->id_length())); Property *lp = propertyAt(Heap::ArrayObject::LengthPropertyIndex); cattrs = internalClass()->propertyData.constData() + Heap::ArrayObject::LengthPropertyIndex; if (attrs.isEmpty() || p->isSubset(attrs, lp, *cattrs)) @@ -926,16 +925,16 @@ reject: bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Property *p, PropertyAttributes attrs) { - Property *current = 0; + bool hasProperty = 0; // Clause 1 if (arrayData()) { - current = arrayData()->getProperty(index); - if (!current && isStringObject()) - current = static_cast<StringObject *>(this)->getIndex(index); + hasProperty = arrayData()->getProperty(index); + if (!hasProperty && isStringObject()) + hasProperty = (index < static_cast<StringObject *>(this)->length()); } - if (!current) { + if (!hasProperty) { // clause 3 if (!isExtensible()) goto reject; @@ -1029,9 +1028,9 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String * } else { // clause 10 Q_ASSERT(cattrs.isAccessor() && attrs.isAccessor()); if (!cattrs.isConfigurable()) { - if (!p->value.isEmpty() && current->value.val != p->value.val) + if (!p->value.isEmpty() && current->value.rawValue() != p->value.rawValue()) goto reject; - if (!p->set.isEmpty() && current->set.val != p->set.val) + if (!p->set.isEmpty() && current->set.rawValue() != p->set.rawValue()) goto reject; } } @@ -1097,7 +1096,7 @@ void Object::copyArrayData(Object *other) uint Object::getLength(const Managed *m) { Scope scope(static_cast<const Object *>(m)->engine()); - ScopedValue v(scope, static_cast<Object *>(const_cast<Managed *>(m))->get(scope.engine->id_length)); + ScopedValue v(scope, static_cast<Object *>(const_cast<Managed *>(m))->get(scope.engine->id_length())); return v->toUInt32(); } @@ -1137,7 +1136,7 @@ void Object::initSparseArray() DEFINE_OBJECT_VTABLE(ArrayObject); Heap::ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list) - : Heap::Object(engine->arrayClass, engine->arrayPrototype.asObject()) + : Heap::Object(engine->arrayClass, engine->arrayPrototype()) { init(); Scope scope(engine); @@ -1155,14 +1154,14 @@ Heap::ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list) a->setArrayLengthUnchecked(len); } -ReturnedValue ArrayObject::getLookup(Managed *m, Lookup *l) +ReturnedValue ArrayObject::getLookup(const Managed *m, Lookup *l) { - Scope scope(static_cast<Object *>(m)->engine()); + Scope scope(static_cast<const Object *>(m)->engine()); ScopedString name(scope, scope.engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); - if (name->equals(scope.engine->id_length)) { + if (name->equals(scope.engine->id_length())) { // special case, as the property is on the object itself l->getter = Lookup::arrayLengthGetter; - ArrayObject *a = static_cast<ArrayObject *>(m); + const ArrayObject *a = static_cast<const ArrayObject *>(m); return a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].asReturnedValue(); } return Object::getLookup(m, l); diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 71a997e133..f129312819 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -36,6 +36,9 @@ #include "qv4managed_p.h" #include "qv4memberdata_p.h" #include "qv4arraydata_p.h" +#include "qv4engine_p.h" +#include "qv4scopedvalue_p.h" +#include "qv4value_p.h" QT_BEGIN_NAMESPACE @@ -44,20 +47,16 @@ namespace QV4 { namespace Heap { struct Object : Base { - Object(ExecutionEngine *engine) - : internalClass(engine->emptyClass), - prototype(static_cast<Object *>(engine->objectPrototype.m)) - { - } + inline Object(ExecutionEngine *engine); Object(InternalClass *internal, QV4::Object *prototype); const Property *propertyAt(uint index) const { return reinterpret_cast<const Property *>(memberData->data + index); } Property *propertyAt(uint index) { return reinterpret_cast<Property *>(memberData->data + index); } InternalClass *internalClass; - Heap::Object *prototype; - MemberData *memberData; - ArrayData *arrayData; + Pointer<Object> prototype; + Pointer<MemberData> memberData; + Pointer<ArrayData> arrayData; }; } @@ -67,9 +66,9 @@ struct Object : Base { Q_MANAGED_CHECK \ typedef superClass SuperClass; \ static const QV4::ObjectVTable static_vtbl; \ - static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl.managedVTable; } \ + static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \ V4_MANAGED_SIZE_TEST \ - Data *d() const { return static_cast<Data *>(m); } + Data *d() const { return static_cast<Data *>(m()); } #define V4_OBJECT2(DataClass, superClass) \ public: \ @@ -77,33 +76,33 @@ struct Object : Base { typedef QV4::Heap::DataClass Data; \ typedef superClass SuperClass; \ static const QV4::ObjectVTable static_vtbl; \ - static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl.managedVTable; } \ + static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \ V4_MANAGED_SIZE_TEST \ - QV4::Heap::DataClass *d() const { return static_cast<QV4::Heap::DataClass *>(m); } + QV4::Heap::DataClass *d() const { return static_cast<QV4::Heap::DataClass *>(m()); } struct ObjectVTable { - ManagedVTable managedVTable; - ReturnedValue (*call)(Managed *, CallData *data); - ReturnedValue (*construct)(Managed *, CallData *data); - ReturnedValue (*get)(Managed *, String *name, bool *hasProperty); - ReturnedValue (*getIndexed)(Managed *, uint index, bool *hasProperty); + VTable vTable; + ReturnedValue (*call)(const Managed *, CallData *data); + ReturnedValue (*construct)(const Managed *, CallData *data); + ReturnedValue (*get)(const Managed *, String *name, bool *hasProperty); + ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty); void (*put)(Managed *, String *name, const Value &value); void (*putIndexed)(Managed *, uint index, const Value &value); PropertyAttributes (*query)(const Managed *, String *name); PropertyAttributes (*queryIndexed)(const Managed *, uint index); bool (*deleteProperty)(Managed *m, String *name); bool (*deleteIndexedProperty)(Managed *m, uint index); - ReturnedValue (*getLookup)(Managed *m, Lookup *l); + ReturnedValue (*getLookup)(const Managed *m, Lookup *l); void (*setLookup)(Managed *m, Lookup *l, const Value &v); uint (*getLength)(const Managed *m); - void (*advanceIterator)(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes); + void (*advanceIterator)(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); }; #define DEFINE_OBJECT_VTABLE(classname) \ const QV4::ObjectVTable classname::static_vtbl = \ { \ - DEFINE_MANAGED_VTABLE_INT(classname, &classname::SuperClass::static_vtbl == &Object::static_vtbl ? 0 : &classname::SuperClass::static_vtbl.managedVTable), \ + DEFINE_MANAGED_VTABLE_INT(classname, &classname::SuperClass::static_vtbl == &Object::static_vtbl ? 0 : &classname::SuperClass::static_vtbl.vTable), \ call, \ construct, \ get, \ @@ -141,15 +140,15 @@ struct Q_QML_EXPORT Object: Managed { const Property *propertyAt(uint index) const { return d()->propertyAt(index); } Property *propertyAt(uint index) { return d()->propertyAt(index); } - const ObjectVTable *vtable() const { return reinterpret_cast<const ObjectVTable *>(d()->vtable); } + const ObjectVTable *vtable() const { return reinterpret_cast<const ObjectVTable *>(d()->vtable()); } Heap::Object *prototype() const { return d()->prototype; } bool setPrototype(Object *proto); - Property *__getOwnProperty__(String *name, PropertyAttributes *attrs = 0); - Property *__getOwnProperty__(uint index, PropertyAttributes *attrs = 0); + void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0); + void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = 0); - Property *__getPropertyDescriptor__(String *name, PropertyAttributes *attrs = 0) const; - Property *__getPropertyDescriptor__(uint index, PropertyAttributes *attrs = 0) const; + Property *__getPropertyDescriptor__(String *name, PropertyAttributes *attrs) const; + Property *__getPropertyDescriptor__(uint index, PropertyAttributes *attrs) const; bool hasProperty(String *name) const; bool hasProperty(uint index) const; @@ -272,9 +271,9 @@ public: } void ensureMemberIndex(uint idx); - inline ReturnedValue get(String *name, bool *hasProperty = 0) + inline ReturnedValue get(String *name, bool *hasProperty = 0) const { return vtable()->get(this, name, hasProperty); } - inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) + inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) const { return vtable()->getIndexed(this, idx, hasProperty); } inline void put(String *name, const Value &v) { vtable()->put(this, name, v); } @@ -288,38 +287,38 @@ public: { return vtable()->deleteProperty(this, name); } bool deleteIndexedProperty(uint index) { return vtable()->deleteIndexedProperty(this, index); } - ReturnedValue getLookup(Lookup *l) + ReturnedValue getLookup(Lookup *l) const { return vtable()->getLookup(this, l); } void setLookup(Lookup *l, const Value &v) { vtable()->setLookup(this, l, v); } - void advanceIterator(ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes) + void advanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes) { vtable()->advanceIterator(this, it, name, index, p, attributes); } uint getLength() const { return vtable()->getLength(this); } - inline ReturnedValue construct(CallData *d) + inline ReturnedValue construct(CallData *d) const { return vtable()->construct(this, d); } - inline ReturnedValue call(CallData *d) + inline ReturnedValue call(CallData *d) const { return vtable()->call(this, d); } protected: static void markObjects(Heap::Base *that, ExecutionEngine *e); - static ReturnedValue construct(Managed *m, CallData *); - static ReturnedValue call(Managed *m, CallData *); - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue construct(const Managed *m, CallData *); + static ReturnedValue call(const Managed *m, CallData *); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); static void putIndexed(Managed *m, uint index, const Value &value); static PropertyAttributes query(const Managed *m, String *name); static PropertyAttributes queryIndexed(const Managed *m, uint index); static bool deleteProperty(Managed *m, String *name); static bool deleteIndexedProperty(Managed *m, uint index); - static ReturnedValue getLookup(Managed *m, Lookup *l); + static ReturnedValue getLookup(const Managed *m, Lookup *l); static void setLookup(Managed *m, Lookup *l, const Value &v); - static void advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes); + static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); static uint getLength(const Managed *m); private: - ReturnedValue internalGet(String *name, bool *hasProperty); - ReturnedValue internalGetIndexed(uint index, bool *hasProperty); + ReturnedValue internalGet(String *name, bool *hasProperty) const; + ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const; void internalPut(String *name, const Value &value); void internalPutIndexed(uint index, const Value &value); bool internalDeleteProperty(String *name); @@ -331,6 +330,12 @@ private: namespace Heap { +inline Object::Object(ExecutionEngine *engine) + : internalClass(engine->emptyClass), + prototype(static_cast<Object *>(engine->objectPrototype()->m())) +{ +} + struct BooleanObject : Object { BooleanObject(InternalClass *ic, QV4::Object *prototype) : Object(ic, prototype), @@ -339,7 +344,7 @@ struct BooleanObject : Object { } BooleanObject(ExecutionEngine *engine, bool b) - : Object(engine->emptyClass, engine->booleanPrototype.asObject()), + : Object(engine->emptyClass, engine->booleanPrototype()), b(b) { } @@ -354,7 +359,7 @@ struct NumberObject : Object { } NumberObject(ExecutionEngine *engine, double val) - : Object(engine->emptyClass, engine->numberPrototype.asObject()), + : Object(engine->emptyClass, engine->numberPrototype()), value(val) { } @@ -367,7 +372,7 @@ struct ArrayObject : Object { }; ArrayObject(ExecutionEngine *engine) - : Heap::Object(engine->arrayClass, engine->arrayPrototype.asObject()) + : Heap::Object(engine->arrayClass, engine->arrayPrototype()) { init(); } ArrayObject(ExecutionEngine *engine, const QStringList &list); ArrayObject(InternalClass *ic, QV4::Object *prototype) @@ -400,7 +405,7 @@ struct ArrayObject: Object { void init(ExecutionEngine *engine); - static ReturnedValue getLookup(Managed *m, Lookup *l); + static ReturnedValue getLookup(const Managed *m, Lookup *l); using Object::getLength; static uint getLength(const Managed *m); @@ -454,14 +459,10 @@ inline void Object::arraySet(uint index, const Value &value) setArrayLengthUnchecked(index + 1); } -template<> -inline Object *value_cast(const Value &v) { - return v.asObject(); -} template<> -inline ArrayObject *value_cast(const Value &v) { - return v.asArrayObject(); +inline const ArrayObject *Value::as() const { + return isManaged() && m() && 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 f36ee554a7..585f9f5c2e 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -35,6 +35,7 @@ #include "qv4stringobject_p.h" #include "qv4identifier_p.h" #include "qv4argumentsobject_p.h" +#include "qv4string_p.h" using namespace QV4; @@ -50,7 +51,7 @@ ObjectIterator::ObjectIterator(ExecutionEngine *e, Value *scratch1, Value *scrat init(o); } -ObjectIterator::ObjectIterator(Scope &scope, Object *o, uint flags) +ObjectIterator::ObjectIterator(Scope &scope, const Object *o, uint flags) : engine(scope.engine) , object(scope.alloc(1)) , current(scope.alloc(1)) @@ -62,14 +63,14 @@ ObjectIterator::ObjectIterator(Scope &scope, Object *o, uint flags) init(o); } -void ObjectIterator::init(Object *o) +void ObjectIterator::init(const Object *o) { - object->m = o ? o->m : 0; - current->m = o ? o->m : 0; + object->setM(o ? o->m() : 0); + current->setM(o ? o->m() : 0); #if QT_POINTER_SIZE == 4 - object->tag = QV4::Value::Managed_Type; - current->tag = QV4::Value::Managed_Type; + object->setTag(QV4::Value::Managed_Type); + current->setTag(QV4::Value::Managed_Type); #endif if (object->as<ArgumentsObject>()) { @@ -78,12 +79,12 @@ void ObjectIterator::init(Object *o) } } -void ObjectIterator::next(Heap::String **name, uint *index, Property *pd, PropertyAttributes *attrs) +void ObjectIterator::next(Value *name, uint *index, Property *pd, PropertyAttributes *attrs) { - *name = 0; + name->setM(0); *index = UINT_MAX; - if (!object->asObject()) { + if (!object->as<Object>()) { *attrs = PropertyAttributes(); return; } @@ -92,19 +93,19 @@ void ObjectIterator::next(Heap::String **name, uint *index, Property *pd, Proper ScopedString n(scope); while (1) { - if (!current->asObject()) + if (!current->as<Object>()) break; while (1) { - current->asObject()->advanceIterator(this, name, index, pd, attrs); + current->as<Object>()->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()) { - o = object->asObject(); + o = object->as<Object>(); n = *name; bool shadowed = false; - while (o->asObject()->d() != current->heapObject()) { + while (o->d() != current->heapObject()) { if ((!!n && o->hasOwnProperty(n)) || (*index != UINT_MAX && o->hasOwnProperty(*index))) { shadowed = true; @@ -119,9 +120,9 @@ void ObjectIterator::next(Heap::String **name, uint *index, Property *pd, Proper } if (flags & WithProtoChain) - current->m = current->objectValue()->prototype(); + current->setM(current->objectValue()->prototype()); else - current->m = (Heap::Base *)0; + current->setM(0); arrayIndex = 0; memberIndex = 0; @@ -131,7 +132,7 @@ void ObjectIterator::next(Heap::String **name, uint *index, Property *pd, Proper ReturnedValue ObjectIterator::nextPropertyName(Value *value) { - if (!object->asObject()) + if (!object->as<Object>()) return Encode::null(); PropertyAttributes attrs; @@ -147,13 +148,13 @@ ReturnedValue ObjectIterator::nextPropertyName(Value *value) if (!!name) return name->asReturnedValue(); - assert(index < UINT_MAX); + Q_ASSERT(index < UINT_MAX); return Encode(index); } ReturnedValue ObjectIterator::nextPropertyNameAsString(Value *value) { - if (!object->asObject()) + if (!object->as<Object>()) return Encode::null(); PropertyAttributes attrs; @@ -169,13 +170,13 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString(Value *value) if (!!name) return name->asReturnedValue(); - assert(index < UINT_MAX); + Q_ASSERT(index < UINT_MAX); return Encode(engine->newString(QString::number(index))); } ReturnedValue ObjectIterator::nextPropertyNameAsString() { - if (!object->asObject()) + if (!object->as<Object>()) return Encode::null(); PropertyAttributes attrs; diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index a7abd2ca10..bfe04b33aa 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -57,9 +57,9 @@ struct Q_QML_EXPORT ObjectIterator uint flags; ObjectIterator(ExecutionEngine *e, Value *scratch1, Value *scratch2, Object *o, uint flags); - ObjectIterator(Scope &scope, Object *o, uint flags); - void init(Object *o); - void next(Heap::String **name, uint *index, Property *pd, PropertyAttributes *attributes = 0); + ObjectIterator(Scope &scope, const Object *o, uint flags); + void init(const Object *o); + void next(Value *name, uint *index, Property *pd, PropertyAttributes *attributes = 0); ReturnedValue nextPropertyName(Value *value); ReturnedValue nextPropertyNameAsString(Value *value); ReturnedValue nextPropertyNameAsString(); diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 9356ea434e..1edf76e2de 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -34,10 +34,11 @@ #include "qv4objectproto_p.h" #include "qv4argumentsobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4scopedvalue_p.h" #include "qv4runtime_p.h" #include "qv4objectiterator_p.h" +#include "qv4string_p.h" #include <QtCore/QDateTime> #include <QtCore/QStringList> @@ -52,14 +53,14 @@ Heap::ObjectCtor::ObjectCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ObjectCtor::construct(Managed *that, CallData *callData) +ReturnedValue ObjectCtor::construct(const Managed *that, CallData *callData) { - ObjectCtor *ctor = static_cast<ObjectCtor *>(that); + const ObjectCtor *ctor = static_cast<const ObjectCtor *>(that); ExecutionEngine *v4 = ctor->engine(); Scope scope(v4); 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 proto(scope, ctor->get(v4->id_prototype())); if (!!proto) obj->setPrototype(proto); return obj.asReturnedValue(); @@ -67,9 +68,9 @@ ReturnedValue ObjectCtor::construct(Managed *that, CallData *callData) return RuntimeHelpers::toObject(scope.engine, callData->args[0]); } -ReturnedValue ObjectCtor::call(Managed *m, CallData *callData) +ReturnedValue ObjectCtor::call(const Managed *m, CallData *callData) { - ObjectCtor *ctor = static_cast<ObjectCtor *>(m); + const ObjectCtor *ctor = static_cast<const ObjectCtor *>(m); ExecutionEngine *v4 = ctor->engine(); if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) return v4->newObject()->asReturnedValue(); @@ -81,8 +82,8 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) Scope scope(v4); ScopedObject o(scope, this); - ctor->defineReadonlyProperty(v4->id_prototype, o); - ctor->defineReadonlyProperty(v4->id_length, Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(v4->id_prototype(), o); + ctor->defineReadonlyProperty(v4->id_length(), Primitive::fromInt32(1)); ctor->defineDefaultProperty(QStringLiteral("getPrototypeOf"), method_getPrototypeOf, 1); ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptor"), method_getOwnPropertyDescriptor, 2); ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyNames"), method_getOwnPropertyNames, 1); @@ -98,9 +99,9 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) ctor->defineDefaultProperty(QStringLiteral("keys"), method_keys, 1); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(v4->id_toString, method_toString, 0); + defineDefaultProperty(v4->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0); - defineDefaultProperty(v4->id_valueOf, method_valueOf, 0); + defineDefaultProperty(v4->id_valueOf(), method_valueOf, 0); defineDefaultProperty(QStringLiteral("hasOwnProperty"), method_hasOwnProperty, 1); defineDefaultProperty(QStringLiteral("isPrototypeOf"), method_isPrototypeOf, 1); defineDefaultProperty(QStringLiteral("propertyIsEnumerable"), method_propertyIsEnumerable, 1); @@ -109,9 +110,9 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) ScopedContext global(scope, scope.engine->rootContext()); ScopedProperty p(scope); - p->value = BuiltinFunction::create(global, v4->id___proto__, method_get_proto); - p->set = BuiltinFunction::create(global, v4->id___proto__, method_set_proto); - insertMember(v4->id___proto__, p, Attr_Accessor|Attr_NotEnumerable); + p->value = BuiltinFunction::create(global, v4->id___proto__(), method_get_proto); + p->set = BuiltinFunction::create(global, v4->id___proto__(), method_set_proto); + insertMember(v4->id___proto__(), p, Attr_Accessor|Attr_NotEnumerable); } ReturnedValue ObjectPrototype::method_getPrototypeOf(CallContext *ctx) @@ -140,8 +141,9 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx) if (scope.hasException()) return Encode::undefined(); PropertyAttributes attrs; - Property *desc = O->__getOwnProperty__(name, &attrs); - return fromPropertyDescriptor(scope.engine, desc, attrs); + Property desc; + O->getOwnProperty(name, &attrs, &desc); + return fromPropertyDescriptor(scope.engine, &desc, attrs); } ReturnedValue ObjectPrototype::method_getOwnPropertyNames(CallContext *context) @@ -163,7 +165,7 @@ ReturnedValue ObjectPrototype::method_create(CallContext *ctx) return ctx->engine()->throwTypeError(); ScopedObject newObject(scope, ctx->d()->engine->newObject()); - newObject->setPrototype(O->asObject()); + newObject->setPrototype(O->as<Object>()); if (ctx->argc() > 1 && !ctx->args()[1].isUndefined()) { ctx->d()->callData->args[0] = newObject.asReturnedValue(); @@ -390,7 +392,7 @@ ReturnedValue ObjectPrototype::method_toString(CallContext *ctx) } else { ScopedObject obj(scope, RuntimeHelpers::toObject(scope.engine, ctx->thisObject())); QString className = obj->className(); - return ctx->d()->engine->newString(QString::fromLatin1("[object %1]").arg(className))->asReturnedValue(); + return ctx->d()->engine->newString(QStringLiteral("[object %1]").arg(className))->asReturnedValue(); } } @@ -400,7 +402,7 @@ ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx) ScopedObject o(scope, ctx->thisObject().toObject(scope.engine)); if (!o) return Encode::undefined(); - ScopedFunctionObject f(scope, o->get(ctx->d()->engine->id_toString)); + ScopedFunctionObject f(scope, o->get(ctx->d()->engine->id_toString())); if (!f) return ctx->engine()->throwTypeError(); ScopedCallData callData(scope); @@ -462,7 +464,7 @@ ReturnedValue ObjectPrototype::method_propertyIsEnumerable(CallContext *ctx) if (scope.engine->hasException) return Encode::undefined(); PropertyAttributes attrs; - o->__getOwnProperty__(p, &attrs); + o->getOwnProperty(p, &attrs); return Encode(attrs.isEnumerable()); } @@ -484,7 +486,7 @@ ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx) if (!o) { if (!ctx->thisObject().isUndefined()) return Encode::undefined(); - o = ctx->d()->engine->globalObject(); + o = ctx->d()->engine->globalObject; } ScopedProperty pd(scope); @@ -512,7 +514,7 @@ ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx) if (!o) { if (!ctx->thisObject().isUndefined()) return Encode::undefined(); - o = ctx->d()->engine->globalObject(); + o = ctx->d()->engine->globalObject; } ScopedProperty pd(scope); @@ -525,7 +527,7 @@ ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx) ReturnedValue ObjectPrototype::method_get_proto(CallContext *ctx) { Scope scope(ctx); - ScopedObject o(scope, ctx->thisObject().asObject()); + ScopedObject o(scope, ctx->thisObject().as<Object>()); if (!o) return ctx->engine()->throwTypeError(); @@ -572,15 +574,15 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value desc->set = Primitive::emptyValue(); ScopedValue tmp(scope); - if (o->hasProperty(engine->id_enumerable)) - attrs->setEnumerable((tmp = o->get(engine->id_enumerable))->toBoolean()); + if (o->hasProperty(engine->id_enumerable())) + attrs->setEnumerable((tmp = o->get(engine->id_enumerable()))->toBoolean()); - if (o->hasProperty(engine->id_configurable)) - attrs->setConfigurable((tmp = o->get(engine->id_configurable))->toBoolean()); + if (o->hasProperty(engine->id_configurable())) + attrs->setConfigurable((tmp = o->get(engine->id_configurable()))->toBoolean()); - if (o->hasProperty(engine->id_get)) { - ScopedValue get(scope, o->get(engine->id_get)); - FunctionObject *f = get->asFunctionObject(); + if (o->hasProperty(engine->id_get())) { + ScopedValue get(scope, o->get(engine->id_get())); + FunctionObject *f = get->as<FunctionObject>(); if (f || get->isUndefined()) { desc->value = get; } else { @@ -590,9 +592,9 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value attrs->setType(PropertyAttributes::Accessor); } - if (o->hasProperty(engine->id_set)) { - ScopedValue set(scope, o->get(engine->id_set)); - FunctionObject *f = set->asFunctionObject(); + if (o->hasProperty(engine->id_set())) { + ScopedValue set(scope, o->get(engine->id_set())); + FunctionObject *f = set->as<FunctionObject>(); if (f || set->isUndefined()) { desc->set = set; } else { @@ -602,22 +604,22 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value attrs->setType(PropertyAttributes::Accessor); } - if (o->hasProperty(engine->id_writable)) { + if (o->hasProperty(engine->id_writable())) { if (attrs->isAccessor()) { engine->throwTypeError(); return; } - attrs->setWritable((tmp = o->get(engine->id_writable))->toBoolean()); + attrs->setWritable((tmp = o->get(engine->id_writable()))->toBoolean()); // writable forces it to be a data descriptor desc->value = Primitive::undefinedValue(); } - if (o->hasProperty(engine->id_value)) { + if (o->hasProperty(engine->id_value())) { if (attrs->isAccessor()) { engine->throwTypeError(); return; } - desc->value = o->get(engine->id_value); + desc->value = o->get(engine->id_value()); attrs->setType(PropertyAttributes::Data); } diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h index 4e96681017..d571e50cd4 100644 --- a/src/qml/jsruntime/qv4objectproto_p.h +++ b/src/qml/jsruntime/qv4objectproto_p.h @@ -53,8 +53,8 @@ struct ObjectCtor: FunctionObject { V4_OBJECT2(ObjectCtor, FunctionObject) - static ReturnedValue construct(Managed *that, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct ObjectPrototype: Object diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index 88dc1946b8..4ec7103644 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include "qv4persistent_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4object_p.h" #include "PageAllocation.h" @@ -78,11 +78,11 @@ Page *allocatePage(PersistentValueStorage *storage) if (p->header.next) p->header.next->header.prev = &p->header.next; for (int i = 0; i < kEntriesPerPage - 1; ++i) { - p->values[i].tag = QV4::Value::Empty_Type; - p->values[i].int_32 = i + 1; + p->values[i].setTag(QV4::Value::Empty_Type); + p->values[i].setInt_32(i + 1); } - p->values[kEntriesPerPage - 1].tag = QV4::Value::Empty_Type; - p->values[kEntriesPerPage - 1].int_32 = -1; + p->values[kEntriesPerPage - 1].setTag(QV4::Value::Empty_Type); + p->values[kEntriesPerPage - 1].setInt_32(-1); storage->firstPage = p; @@ -97,7 +97,7 @@ PersistentValueStorage::Iterator &PersistentValueStorage::Iterator::operator++() while (p) { while (index < kEntriesPerPage - 1) { ++index; - if (static_cast<Page *>(p)->values[index].tag != QV4::Value::Empty_Type) + if (static_cast<Page *>(p)->values[index].tag() != QV4::Value::Empty_Type) return *this; } index = -1; @@ -147,10 +147,10 @@ Value *PersistentValueStorage::allocate() p = allocatePage(this); Value *v = p->values + p->header.freeList; - p->header.freeList = v->int_32; + p->header.freeList = v->int_32(); ++p->header.refCount; - v->val = Encode::undefined(); + v->setRawValue(Encode::undefined()); return v; } @@ -162,8 +162,8 @@ void PersistentValueStorage::free(Value *v) Page *p = getPage(v); - v->tag = QV4::Value::Empty_Type; - v->int_32 = p->header.freeList; + v->setTag(QV4::Value::Empty_Type); + v->setInt_32(p->header.freeList); p->header.freeList = v - p->values; if (!--p->header.refCount) { if (p->header.prev) @@ -178,8 +178,8 @@ static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase) { while (engine->jsStackTop > markBase) { Heap::Base *h = engine->popForGC(); - Q_ASSERT (h->gcGetVtable()->markObjects); - h->gcGetVtable()->markObjects(h, engine); + Q_ASSERT (h->vtable()->markObjects); + h->vtable()->markObjects(h, engine); } } @@ -190,7 +190,7 @@ void PersistentValueStorage::mark(ExecutionEngine *e) Page *p = static_cast<Page *>(firstPage); while (p) { for (int i = 0; i < kEntriesPerPage; ++i) { - if (Managed *m = p->values[i].asManaged()) + if (Managed *m = p->values[i].as<Managed>()) m->mark(e); } drainMarkStack(e, markBase); @@ -312,6 +312,12 @@ WeakValue::WeakValue(const WeakValue &other) } } +WeakValue::WeakValue(ExecutionEngine *engine, const Value &value) +{ + val = engine->memoryManager->m_weakValues->allocate(); + *val = value; +} + WeakValue &WeakValue::operator=(const WeakValue &other) { if (!val) { diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h index 7cac2ed95f..858734e9ed 100644 --- a/src/qml/jsruntime/qv4persistent_p.h +++ b/src/qml/jsruntime/qv4persistent_p.h @@ -33,7 +33,8 @@ #ifndef QV4PERSISTENT_H #define QV4PERSISTENT_H -#include "qv4value_inl_p.h" +#include "qv4value_p.h" +#include "qv4managed_p.h" QT_BEGIN_NAMESPACE @@ -96,7 +97,13 @@ public: Managed *asManaged() const { if (!val) return 0; - return val->asManaged(); + return val->as<Managed>(); + } + template<typename T> + T *as() const { + if (!val) + return 0; + return val->as<T>(); } ExecutionEngine *engine() const { @@ -122,6 +129,7 @@ class Q_QML_EXPORT WeakValue public: WeakValue() : val(0) {} WeakValue(const WeakValue &other); + WeakValue(ExecutionEngine *engine, const Value &value); WeakValue &operator=(const WeakValue &other); ~WeakValue(); @@ -138,7 +146,13 @@ public: Managed *asManaged() const { if (!val) return 0; - return val->asManaged(); + return val->as<Managed>(); + } + template <typename T> + T *as() const { + if (!val) + return 0; + return val->as<T>(); } ExecutionEngine *engine() const { diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp index a7019d0558..9b77599904 100644 --- a/src/qml/jsruntime/qv4profiling.cpp +++ b/src/qml/jsruntime/qv4profiling.cpp @@ -32,7 +32,8 @@ ****************************************************************************/ #include "qv4profiling_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> +#include <private/qv4string_p.h> QT_BEGIN_NAMESPACE @@ -55,10 +56,10 @@ FunctionCallProperties FunctionCall::resolve() const Profiler::Profiler(QV4::ExecutionEngine *engine) : featuresEnabled(0), m_engine(engine) { - static int metatype = qRegisterMetaType<QList<QV4::Profiling::FunctionCallProperties> >(); - static int metatype2 = qRegisterMetaType<QList<QV4::Profiling::MemoryAllocationProperties> >(); - Q_UNUSED(metatype); - Q_UNUSED(metatype2); + static int meta = qRegisterMetaType<QVector<QV4::Profiling::FunctionCallProperties> >(); + static int meta2 = qRegisterMetaType<QVector<QV4::Profiling::MemoryAllocationProperties> >(); + Q_UNUSED(meta); + Q_UNUSED(meta2); m_timer.start(); } @@ -75,7 +76,7 @@ void Profiler::stopProfiling() void Profiler::reportData() { - QList<FunctionCallProperties> resolved; + QVector<FunctionCallProperties> resolved; resolved.reserve(m_data.size()); FunctionCallComparator comp; foreach (const FunctionCall &call, m_data) { @@ -83,14 +84,13 @@ void Profiler::reportData() resolved.insert(std::upper_bound(resolved.begin(), resolved.end(), props, comp), props); } emit dataReady(resolved, m_memory_data); + m_data.clear(); + m_memory_data.clear(); } void Profiler::startProfiling(quint64 features) { if (featuresEnabled == 0) { - m_data.clear(); - m_memory_data.clear(); - if (features & (1 << FeatureMemoryAllocation)) { qint64 timestamp = m_timer.nsecsElapsed(); MemoryAllocationProperties heap = {timestamp, diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index c3441eaacd..cc00af0193 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -155,14 +155,14 @@ public slots: void setTimer(const QElapsedTimer &timer) { m_timer = timer; } signals: - void dataReady(const QList<QV4::Profiling::FunctionCallProperties> &, - const QList<QV4::Profiling::MemoryAllocationProperties> &); + void dataReady(const QVector<QV4::Profiling::FunctionCallProperties> &, + const QVector<QV4::Profiling::MemoryAllocationProperties> &); private: QV4::ExecutionEngine *m_engine; QElapsedTimer m_timer; QVector<FunctionCall> m_data; - QList<MemoryAllocationProperties> m_memory_data; + QVector<MemoryAllocationProperties> m_memory_data; friend class FunctionCallProfiler; }; @@ -202,7 +202,7 @@ Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCallProperties, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCall, Q_MOVABLE_TYPE); QT_END_NAMESPACE -Q_DECLARE_METATYPE(QList<QV4::Profiling::FunctionCallProperties>) -Q_DECLARE_METATYPE(QList<QV4::Profiling::MemoryAllocationProperties>) +Q_DECLARE_METATYPE(QVector<QV4::Profiling::FunctionCallProperties>) +Q_DECLARE_METATYPE(QVector<QV4::Profiling::MemoryAllocationProperties>) #endif // QV4PROFILING_H diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h index 1b55abd1f7..db8c6017e1 100644 --- a/src/qml/jsruntime/qv4property_p.h +++ b/src/qml/jsruntime/qv4property_p.h @@ -35,7 +35,6 @@ #include "qv4global_p.h" #include "qv4value_p.h" -#include "qv4internalclass_p.h" QT_BEGIN_NAMESPACE @@ -73,8 +72,8 @@ struct Property { 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 void setGetter(FunctionObject *g) { value = Primitive::fromManaged(reinterpret_cast<Managed *>(g)); } - inline void setSetter(FunctionObject *s) { set = s ? Primitive::fromManaged(reinterpret_cast<Managed *>(s)) : Value::fromHeapObject(0); } + inline void setGetter(FunctionObject *g) { value = reinterpret_cast<Managed *>(g); } + inline void setSetter(FunctionObject *s) { set = (s ? reinterpret_cast<Managed *>(s) : 0); } void copy(const Property *other, PropertyAttributes attrs) { value = other->value; @@ -85,12 +84,12 @@ struct Property { explicit Property() { value = Encode::undefined(); set = Value::fromHeapObject(0); } explicit Property(Value v) : value(v) { set = Value::fromHeapObject(0); } Property(FunctionObject *getter, FunctionObject *setter) { - value = Primitive::fromManaged(reinterpret_cast<Managed *>(getter)); - set = Primitive::fromManaged(reinterpret_cast<Managed *>(setter)); + value = reinterpret_cast<Managed *>(getter); + set = reinterpret_cast<Managed *>(setter); } Property(Heap::FunctionObject *getter, Heap::FunctionObject *setter) { - value.m = reinterpret_cast<Heap::Base *>(getter); - set.m = reinterpret_cast<Heap::Base *>(setter); + value.setM(reinterpret_cast<Heap::Base *>(getter)); + set.setM(reinterpret_cast<Heap::Base *>(setter)); } Property &operator=(Value v) { value = v; return *this; } private: diff --git a/src/qml/jsruntime/qv4qmlextensions.cpp b/src/qml/jsruntime/qv4qmlextensions.cpp deleted file mode 100644 index c1c4e0ec78..0000000000 --- a/src/qml/jsruntime/qv4qmlextensions.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qv4qmlextensions_p.h" -#include "qv4object_p.h" - -using namespace QV4; - -void QmlExtensions::markObjects(ExecutionEngine *e) -{ - if (valueTypeWrapperPrototype) - valueTypeWrapperPrototype->mark(e); -} diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 0a1aa56aab..e5946d8be6 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -55,6 +55,7 @@ #include <private/qv4objectproto_p.h> #include <private/qv4jsonobject_p.h> #include <private/qv4regexpobject_p.h> +#include <private/qv4dateobject_p.h> #include <private/qv4scopedvalue_p.h> #include <private/qv4mm_p.h> #include <private/qqmlscriptstring_p.h> @@ -92,7 +93,7 @@ static QPair<QObject *, int> extractQtMethod(QV4::FunctionObject *function) static QPair<QObject *, int> extractQtSignal(const Value &value) { if (value.isObject()) { - QV4::ExecutionEngine *v4 = value.asObject()->engine(); + QV4::ExecutionEngine *v4 = value.as<Object>()->engine(); QV4::Scope scope(v4); QV4::ScopedFunctionObject function(scope, value); if (function) @@ -235,8 +236,8 @@ Heap::QObjectWrapper::QObjectWrapper(ExecutionEngine *engine, QObject *object) void QObjectWrapper::initializeBindings(ExecutionEngine *engine) { - engine->functionPrototype.asObject()->defineDefaultProperty(QStringLiteral("connect"), method_connect); - engine->functionPrototype.asObject()->defineDefaultProperty(QStringLiteral("disconnect"), method_disconnect); + engine->functionPrototype()->defineDefaultProperty(QStringLiteral("connect"), method_connect); + engine->functionPrototype()->defineDefaultProperty(QStringLiteral("disconnect"), method_disconnect); } QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const @@ -255,7 +256,7 @@ QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlCont } ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *n, QObjectWrapper::RevisionMode revisionMode, - bool *hasProperty, bool includeImports) + bool *hasProperty, bool includeImports) const { if (QQmlData::wasDeleted(d()->object)) { if (hasProperty) @@ -266,8 +267,8 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String QV4::Scope scope(engine()); QV4::ScopedString name(scope, n); - if (name->equals(scope.engine->id_destroy) || name->equals(scope.engine->id_toString)) { - int index = name->equals(scope.engine->id_destroy) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod; + if (name->equals(scope.engine->id_destroy()) || name->equals(scope.engine->id_toString())) { + int index = name->equals(scope.engine->id_destroy()) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod; ScopedContext global(scope, scope.engine->rootContext()); QV4::ScopedValue method(scope, QV4::QObjectMethod::create(global, d()->object, index)); if (hasProperty) @@ -317,13 +318,12 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String if (hasProperty) *hasProperty = true; - ScopedContext ctx(scope, scope.engine->currentContext()); - return getProperty(d()->object, ctx, result); + return getProperty(scope.engine, d()->object, result); } -ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired) +ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired) { - QV4::Scope scope(ctx); + QV4::Scope scope(engine); QQmlData::flushPendingBinding(object, property->coreIndex); @@ -333,16 +333,16 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx Q_ASSERT(vmemo); return vmemo->vmeMethod(property->coreIndex); } else if (property->isV4Function()) { - QV4::ScopedObject qmlcontextobject(scope, ctx->d()->engine->qmlContextObject()); + QV4::ScopedObject qmlcontextobject(scope, engine->qmlContextObject()); ScopedContext global(scope, scope.engine->rootContext()); return QV4::QObjectMethod::create(global, object, property->coreIndex, qmlcontextobject); } else if (property->isSignalHandler()) { - QV4::Scoped<QV4::QmlSignalHandler> handler(scope, scope.engine->memoryManager->alloc<QV4::QmlSignalHandler>(ctx->d()->engine, object, property->coreIndex)); + QV4::Scoped<QV4::QmlSignalHandler> handler(scope, scope.engine->memoryManager->alloc<QV4::QmlSignalHandler>(engine, object, property->coreIndex)); - QV4::ScopedString connect(scope, ctx->d()->engine->newIdentifier(QStringLiteral("connect"))); - QV4::ScopedString disconnect(scope, ctx->d()->engine->newIdentifier(QStringLiteral("disconnect"))); - handler->put(connect, QV4::ScopedValue(scope, ctx->d()->engine->functionPrototype.asObject()->get(connect))); - handler->put(disconnect, QV4::ScopedValue(scope, ctx->d()->engine->functionPrototype.asObject()->get(disconnect))); + QV4::ScopedString connect(scope, engine->newIdentifier(QStringLiteral("connect"))); + QV4::ScopedString disconnect(scope, engine->newIdentifier(QStringLiteral("disconnect"))); + handler->put(connect, QV4::ScopedValue(scope, engine->functionPrototype()->get(connect))); + handler->put(disconnect, QV4::ScopedValue(scope, engine->functionPrototype()->get(disconnect))); return handler.asReturnedValue(); } else { @@ -360,31 +360,32 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx if (ep && ep->propertyCapture && property->accessors->notifier) nptr = &n; - QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->d()->engine, object, *property, nptr)); + QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(engine, object, *property, nptr)); if (captureRequired) { if (property->accessors->notifier) { - if (n) - ep->captureProperty(n); + if (n && ep->propertyCapture) + ep->propertyCapture->captureProperty(n); } else { - ep->captureProperty(object, property->coreIndex, property->notifyIndex); + if (ep->propertyCapture) + ep->propertyCapture->captureProperty(object, property->coreIndex, property->notifyIndex); } } return rv->asReturnedValue(); } - if (captureRequired && ep && !property->isConstant()) - ep->captureProperty(object, property->coreIndex, property->notifyIndex); + if (captureRequired && ep && ep->propertyCapture && !property->isConstant()) + ep->propertyCapture->captureProperty(object, property->coreIndex, property->notifyIndex); if (property->isVarProperty()) { QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); Q_ASSERT(vmemo); return vmemo->vmeProperty(property->coreIndex); } else if (property->isDirect()) { - return LoadProperty<ReadAccessor::Direct>(ctx->d()->engine, object, *property, 0); + return LoadProperty<ReadAccessor::Direct>(engine, object, *property, 0); } else { - return LoadProperty<ReadAccessor::Indirect>(ctx->d()->engine, object, *property, 0); + return LoadProperty<ReadAccessor::Indirect>(engine, object, *property, 0); } } @@ -435,21 +436,21 @@ bool QObjectWrapper::setQmlProperty(ExecutionEngine *engine, QQmlContextData *qm Scope scope(engine); ScopedContext ctx(scope, engine->currentContext()); - setProperty(object, ctx, result, value); + setProperty(engine, object, result, value); return true; } -void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, const Value &value) +void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, const Value &value) { if (!property->isWritable() && !property->isQList()) { QString error = QLatin1String("Cannot assign to read-only property \"") + property->name(object) + QLatin1Char('\"'); - ctx->engine()->throwTypeError(error); + engine->throwTypeError(error); return; } QQmlBinding *newBinding = 0; - QV4::Scope scope(ctx); + QV4::Scope scope(engine); QV4::ScopedFunctionObject f(scope, value); if (f) { if (!f->isBinding()) { @@ -460,25 +461,25 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro error += QLatin1String("[unknown property type]"); else error += QLatin1String(QMetaType::typeName(property->propType)); - ctx->engine()->throwError(error); + scope.engine->throwError(error); return; } } else { // binding assignment. - QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->d()->engine); + QQmlContextData *callingQmlContext = scope.engine->callingQmlContext(); QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); bindingFunction->initBindingLocation(); newBinding = new QQmlBinding(value, object, callingQmlContext); - newBinding->setTarget(object, *property, callingQmlContext); + newBinding->setTarget(object, *property); } } - QQmlAbstractBinding *oldBinding = - QQmlPropertyPrivate::setBinding(object, property->coreIndex, -1, newBinding); - if (oldBinding) - oldBinding->destroy(); + if (newBinding) + QQmlPropertyPrivate::setBinding(newBinding); + else + QQmlPropertyPrivate::removeBinding(object, property->encodedIndex()); if (!newBinding && property->isVarProperty()) { // allow assignment of "special" values (null, undefined, function) to var properties @@ -505,16 +506,16 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro } else if (value.isUndefined() && property->propType == QMetaType::QJsonValue) { PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined)); } else if (!newBinding && property->propType == qMetaTypeId<QJSValue>()) { - PROPERTY_STORE(QJSValue, QJSValue(ctx->d()->engine, value.asReturnedValue())); + PROPERTY_STORE(QJSValue, QJSValue(scope.engine, value.asReturnedValue())); } else if (value.isUndefined() && property->propType != qMetaTypeId<QQmlScriptString>()) { QString error = QLatin1String("Cannot assign [undefined] to "); if (!QMetaType::typeName(property->propType)) error += QLatin1String("[unknown property type]"); else error += QLatin1String(QMetaType::typeName(property->propType)); - ctx->engine()->throwError(error); + scope.engine->throwError(error); return; - } else if (value.asFunctionObject()) { + } else if (value.as<FunctionObject>()) { // this is handled by the binding creation above } else if (property->propType == QMetaType::Int && value.isNumber()) { PROPERTY_STORE(int, value.asDouble()); @@ -543,11 +544,11 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro } else { QVariant v; if (property->isQList()) - v = ctx->d()->engine->toVariant(value, qMetaTypeId<QList<QObject *> >()); + v = scope.engine->toVariant(value, qMetaTypeId<QList<QObject *> >()); else - v = ctx->d()->engine->toVariant(value, property->propType); + v = scope.engine->toVariant(value, property->propType); - QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->d()->engine); + QQmlContextData *callingQmlContext = scope.engine->callingQmlContext(); if (!QQmlPropertyPrivate::write(object, *property, v, callingQmlContext)) { const char *valueType = 0; if (v.userType() == QVariant::Invalid) valueType = "null"; @@ -561,7 +562,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro QLatin1String(valueType) + QLatin1String(" to ") + QLatin1String(targetTypeName); - ctx->engine()->throwError(error); + scope.engine->throwError(error); return; } } @@ -634,7 +635,7 @@ void QObjectWrapper::markWrapper(QObject *object, ExecutionEngine *engine) engine->m_multiplyWrappedQObjects->mark(object, engine); } -ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx, int propertyIndex, bool captureRequired) +ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired) { if (QQmlData::wasDeleted(object)) return QV4::Encode::null(); @@ -646,14 +647,19 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx Q_ASSERT(cache); QQmlPropertyData *property = cache->property(propertyIndex); Q_ASSERT(property); // We resolved this property earlier, so it better exist! - return getProperty(object, ctx, property, captureRequired); + return getProperty(engine, object, property, captureRequired); +} + +void QObjectWrapper::setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value) +{ + setProperty(engine, d()->object, propertyIndex, value); } -void QObjectWrapper::setProperty(ExecutionContext *ctx, int propertyIndex, const Value &value) +void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, const Value &value) { - if (QQmlData::wasDeleted(d()->object)) + if (QQmlData::wasDeleted(object)) return; - QQmlData *ddata = QQmlData::get(d()->object, /*create*/false); + QQmlData *ddata = QQmlData::get(object, /*create*/false); if (!ddata) return; @@ -661,14 +667,14 @@ void QObjectWrapper::setProperty(ExecutionContext *ctx, int propertyIndex, const Q_ASSERT(cache); QQmlPropertyData *property = cache->property(propertyIndex); Q_ASSERT(property); // We resolved this property earlier, so it better exist! - return setProperty(d()->object, ctx, property, value); + return setProperty(engine, object, property, value); } bool QObjectWrapper::isEqualTo(Managed *a, Managed *b) { Q_ASSERT(a->as<QV4::QObjectWrapper>()); QV4::QObjectWrapper *qobjectWrapper = static_cast<QV4::QObjectWrapper *>(a); - QV4::Object *o = b->asObject(); + QV4::Object *o = b->as<Object>(); if (o) { if (QV4::QmlTypeWrapper *qmlTypeWrapper = o->as<QV4::QmlTypeWrapper>()) return qmlTypeWrapper->toVariant().value<QObject*>() == qobjectWrapper->object(); @@ -684,10 +690,10 @@ ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QObject *object) return (engine->memoryManager->alloc<QV4::QObjectWrapper>(engine, object))->asReturnedValue(); } -QV4::ReturnedValue QObjectWrapper::get(Managed *m, String *name, bool *hasProperty) +QV4::ReturnedValue QObjectWrapper::get(const Managed *m, String *name, bool *hasProperty) { - QObjectWrapper *that = static_cast<QObjectWrapper*>(m); - QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(that->engine()); + const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m); + QQmlContextData *qmlContext = that->engine()->callingQmlContext(); return that->getQmlProperty(qmlContext, name, IgnoreRevision, hasProperty, /*includeImports*/ true); } @@ -699,7 +705,7 @@ void QObjectWrapper::put(Managed *m, String *name, const Value &value) if (v4->hasException || QQmlData::wasDeleted(that->d()->object)) return; - QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4); + QQmlContextData *qmlContext = v4->callingQmlContext(); if (!setQmlProperty(v4, qmlContext, that->d()->object, name, QV4::QObjectWrapper::IgnoreRevision, value)) { QQmlData *ddata = QQmlData::get(that->d()->object); // Types created by QML are not extensible at run-time, but for other QObjects we can store them @@ -718,23 +724,23 @@ PropertyAttributes QObjectWrapper::query(const Managed *m, String *name) { const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m); ExecutionEngine *engine = that->engine(); - QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(engine); + QQmlContextData *qmlContext = engine->callingQmlContext(); QQmlPropertyData local; if (that->findProperty(engine, qmlContext, name, IgnoreRevision, &local) - || name->equals(engine->id_destroy) || name->equals(engine->id_toString)) + || name->equals(engine->id_destroy()) || name->equals(engine->id_toString())) return QV4::Attr_Data; else return QV4::Object::query(m, name); } -void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes) +void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes) { // Used to block access to QObject::destroyed() and QObject::deleteLater() from QML static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)"); static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()"); static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()"); - *name = (Heap::String *)0; + name->setM(0); *index = UINT_MAX; QObjectWrapper *that = static_cast<QObjectWrapper*>(m); @@ -745,10 +751,9 @@ void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Heap::Strin const bool preventDestruction = mo->superClass() || mo == &QObject::staticMetaObject; const int propertyCount = mo->propertyCount(); if (it->arrayIndex < static_cast<uint>(propertyCount)) { - // #### GC Scope scope(that->engine()); ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name()))); - *name = propName->d(); + name->setM(propName->d()); ++it->arrayIndex; *attributes = QV4::Attr_Data; p->value = that->get(propName); @@ -761,10 +766,9 @@ void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Heap::Strin ++it->arrayIndex; if (method.access() == QMetaMethod::Private || (preventDestruction && (index == deleteLaterIdx || index == destroyedIdx1 || index == destroyedIdx2))) continue; - // #### GC Scope scope(that->engine()); ScopedString methodName(scope, that->engine()->newString(QString::fromUtf8(method.name()))); - *name = methodName->d(); + name->setM(methodName->d()); *attributes = QV4::Attr_Data; p->value = that->get(methodName); return; @@ -811,7 +815,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase QV4::ScopedFunctionObject f(scope, This->function.value()); QV4::ScopedCallData callData(scope, argCount); - callData->thisObject = This->thisObject.isUndefined() ? v4->globalObject()->asReturnedValue() : This->thisObject.value(); + callData->thisObject = This->thisObject.isUndefined() ? v4->globalObject->asReturnedValue() : This->thisObject.value(); for (int ii = 0; ii < argCount; ++ii) { int type = argsTypes[ii + 1]; if (type == qMetaTypeId<QVariant>()) { @@ -826,7 +830,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase QQmlError error = v4->catchExceptionAsQmlError(); if (error.description().isEmpty()) { QV4::ScopedString name(scope, f->name()); - error.setDescription(QString::fromLatin1("Unknown exception occurred during evaluation of connected function: %1").arg(name->toQString())); + error.setDescription(QStringLiteral("Unknown exception occurred during evaluation of connected function: %1").arg(name->toQString())); } if (QQmlEngine *qmlEngine = v4->qmlEngine()) { QQmlEnginePrivate::get(qmlEngine)->warning(error); @@ -1028,48 +1032,31 @@ void QObjectWrapper::markObjects(Heap::Base *that, QV4::ExecutionEngine *e) QV4::Object::markObjects(that, e); } -namespace { - struct QObjectDeleter : public QV4::GCDeletable - { - QObjectDeleter(QObject *o) - : m_objectToDelete(o) - {} - ~QObjectDeleter() - { - QQmlData *ddata = QQmlData::get(m_objectToDelete, false); - if (ddata && ddata->ownContext && ddata->context) - ddata->context->emitDestruction(); - // This object is notionally destroyed now - ddata->isQueuedForDeletion = true; - if (lastCall) - delete m_objectToDelete; - else - m_objectToDelete->deleteLater(); - } - - QObject *m_objectToDelete; - }; -} - -void QObjectWrapper::destroy(Heap::Base *that) +void QObjectWrapper::destroyObject(bool lastCall) { - Heap::QObjectWrapper *This = static_cast<Heap::QObjectWrapper*>(that); - QPointer<QObject> object = This->object; - ExecutionEngine *engine = This->internalClass->engine; - This->~Data(); - This = 0; - if (!object) - return; - - QQmlData *ddata = QQmlData::get(object, false); - if (!ddata) - return; - - if (object->parent() || ddata->indestructible) - return; + Heap::QObjectWrapper *h = d(); + if (!h->internalClass) + return; // destroyObject already got called + + QPointer<QObject> object = h->object; + if (object) { + QQmlData *ddata = QQmlData::get(object, false); + if (ddata) { + if (!object->parent() && !ddata->indestructible) { + if (ddata && ddata->ownContext && ddata->context) + ddata->context->emitDestruction(); + // This object is notionally destroyed now + ddata->isQueuedForDeletion = true; + if (lastCall) + delete object; + else + object->deleteLater(); + } + } + } - QObjectDeleter *deleter = new QObjectDeleter(object); - engine->memoryManager->registerDeletable(deleter); + h->internalClass = 0; + h->~Data(); } @@ -1229,7 +1216,7 @@ static int MatchScore(const QV4::Value &actual, int conversionType) default: return 10; } - } else if (actual.asDateObject()) { + } else if (actual.as<DateObject>()) { switch (conversionType) { case QMetaType::QDateTime: return 0; @@ -1247,7 +1234,7 @@ static int MatchScore(const QV4::Value &actual, int conversionType) default: return 10; } - } else if (actual.asArrayObject()) { + } else if (actual.as<ArrayObject>()) { switch (conversionType) { case QMetaType::QJsonArray: return 3; @@ -1276,7 +1263,7 @@ static int MatchScore(const QV4::Value &actual, int conversionType) return 10; } } - } else if (QV4::Object *obj = actual.asObject()) { + } else if (const Object *obj = actual.as<Object>()) { if (obj->as<QV4::VariantObject>()) { if (conversionType == qMetaTypeId<QVariant>()) return 0; @@ -1379,7 +1366,7 @@ static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQ if (returnType == QMetaType::UnknownType) { QString typeName = QString::fromLatin1(unknownTypeError); - QString error = QString::fromLatin1("Unknown method return type: %1").arg(typeName); + QString error = QStringLiteral("Unknown method return type: %1").arg(typeName); return engine->throwError(error); } @@ -1392,7 +1379,7 @@ static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQ if (!args) { QString typeName = QString::fromLatin1(unknownTypeError); - QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(typeName); + QString error = QStringLiteral("Unknown method parameter type: %1").arg(typeName); return engine->throwError(error); } @@ -1606,9 +1593,9 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q type = callType; } else if (callType == QMetaType::QObjectStar) { qobjectPtr = 0; - if (QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) + if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) qobjectPtr = qobjectWrapper->object(); - else if (QV4::QmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QmlTypeWrapper>()) + else if (const QV4::QmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QmlTypeWrapper>()) queryEngine = qmlTypeWrapper->isSingleton(); type = callType; } else if (callType == qMetaTypeId<QVariant>()) { @@ -1630,7 +1617,7 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q } } else { QObject *o = 0; - if (QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) + if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) o = qobjectWrapper->object(); qlistPtr->append(o); } @@ -1754,14 +1741,14 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, in return method.asReturnedValue(); } -ReturnedValue QObjectMethod::create(ExecutionContext *scope, QQmlValueTypeWrapper *valueType, int index, const Value &qmlGlobal) +ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index, const Value &qmlGlobal) { Scope valueScope(scope); Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->alloc<QObjectMethod>(scope)); method->d()->propertyCache = valueType->d()->propertyCache; method->d()->index = index; method->d()->qmlGlobal = qmlGlobal; - method->d()->valueTypeWrapper = valueType; + method->d()->valueTypeWrapper = *valueType; return method.asReturnedValue(); } @@ -1777,7 +1764,7 @@ const QMetaObject *Heap::QObjectMethod::metaObject() return object->metaObject(); } -QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) +QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) const { QString result; if (const QMetaObject *metaObject = d()->metaObject()) { @@ -1803,7 +1790,7 @@ QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) return ctx->d()->engine->newString(result)->asReturnedValue(); } -QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) +QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const { if (!d()->object) return Encode::undefined(); @@ -1822,13 +1809,13 @@ QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, con return Encode::undefined(); } -ReturnedValue QObjectMethod::call(Managed *m, CallData *callData) +ReturnedValue QObjectMethod::call(const Managed *m, CallData *callData) { - QObjectMethod *This = static_cast<QObjectMethod*>(m); + const QObjectMethod *This = static_cast<const QObjectMethod*>(m); return This->callInternal(callData); } -ReturnedValue QObjectMethod::callInternal(CallData *callData) +ReturnedValue QObjectMethod::callInternal(CallData *callData) const { Scope scope(engine()); ScopedContext context(scope, scope.engine->currentContext()); diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 24e8b29e08..2d10006d97 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -54,7 +54,7 @@ #include <private/qqmlpropertycache_p.h> #include <private/qintrusivelist_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> QT_BEGIN_NAMESPACE @@ -104,7 +104,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object QObject *object() const { return d()->object.data(); } - ReturnedValue getQmlProperty(QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = 0, bool includeImports = false); + ReturnedValue getQmlProperty(QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = 0, bool includeImports = false) const; static ReturnedValue getQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = 0); static bool setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const Value &value); @@ -114,26 +114,28 @@ struct Q_QML_EXPORT QObjectWrapper : public Object using Object::get; - static ReturnedValue getProperty(QObject *object, ExecutionContext *ctx, int propertyIndex, bool captureRequired); - void setProperty(ExecutionContext *ctx, int propertyIndex, const Value &value); + static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired); + static void setProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, const Value &value); + void setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value); + + void destroyObject(bool lastCall); protected: static bool isEqualTo(Managed *that, Managed *o); private: - static ReturnedValue getProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired = true); - static void setProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, const Value &value); + static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired = true); + static void setProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, const Value &value); static ReturnedValue create(ExecutionEngine *engine, QObject *object); QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const; - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); static PropertyAttributes query(const Managed *, String *name); - static void advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes); + static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e); - static void destroy(Heap::Base *that); static ReturnedValue method_connect(CallContext *ctx); static ReturnedValue method_disconnect(CallContext *ctx); @@ -149,17 +151,17 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject enum { DestroyMethod = -1, ToStringMethod = -2 }; static ReturnedValue create(QV4::ExecutionContext *scope, QObject *object, int index, const Value &qmlGlobal = Primitive::undefinedValue()); - static ReturnedValue create(QV4::ExecutionContext *scope, QQmlValueTypeWrapper *valueType, int index, const Value &qmlGlobal = Primitive::undefinedValue()); + static ReturnedValue create(QV4::ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index, const Value &qmlGlobal = Primitive::undefinedValue()); int methodIndex() const { return d()->index; } QObject *object() const { return d()->object.data(); } - QV4::ReturnedValue method_toString(QV4::ExecutionContext *ctx); - QV4::ReturnedValue method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc); + QV4::ReturnedValue method_toString(QV4::ExecutionContext *ctx) const; + QV4::ReturnedValue method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const; - static ReturnedValue call(Managed *, CallData *callData); + static ReturnedValue call(const Managed *, CallData *callData); - ReturnedValue callInternal(CallData *callData); + ReturnedValue callInternal(CallData *callData) const; static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index 8e18a5fbdd..31fee534ad 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -34,16 +34,16 @@ #include "qv4regexp_p.h" #include "qv4engine_p.h" #include "qv4scopedvalue_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> using namespace QV4; RegExpCache::~RegExpCache() { - for (RegExpCache::Iterator it = begin(), e = end(); - it != e; ++it) - it.value()->cache = 0; - clear(); + for (RegExpCache::Iterator it = begin(), e = end(); it != e; ++it) { + if (RegExp *re = it.value().as<RegExp>()) + re->d()->cache = 0; + } } DEFINE_MANAGED_VTABLE(RegExp); @@ -68,19 +68,18 @@ Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bo RegExpCacheKey key(pattern, ignoreCase, multiline); RegExpCache *cache = engine->regExpCache; - if (cache) { - if (Heap::RegExp *result = cache->value(key)) - return result; - } + if (!cache) + cache = engine->regExpCache = new RegExpCache; + + QV4::WeakValue &cachedValue = (*cache)[key]; + if (QV4::RegExp *result = cachedValue.as<RegExp>()) + return result->d(); Scope scope(engine); Scoped<RegExp> result(scope, engine->memoryManager->alloc<RegExp>(engine, pattern, ignoreCase, multiline)); - if (!cache) - cache = engine->regExpCache = new RegExpCache; - result->d()->cache = cache; - cache->insert(key, result->d()); + cachedValue.set(engine, result); return result->d(); } diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h index 819e31e5f1..af6e346ea8 100644 --- a/src/qml/jsruntime/qv4regexp_p.h +++ b/src/qml/jsruntime/qv4regexp_p.h @@ -133,8 +133,7 @@ inline RegExpCacheKey::RegExpCacheKey(const RegExp::Data *re) inline uint qHash(const RegExpCacheKey& key, uint seed = 0) Q_DECL_NOTHROW { return qHash(key.pattern, seed); } -// ### GC -class RegExpCache : public QHash<RegExpCacheKey, Heap::RegExp*> +class RegExpCache : public QHash<RegExpCacheKey, WeakValue> { public: ~RegExpCache(); diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index f6e88e62b7..329e5d2c56 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -37,7 +37,7 @@ #include "qv4objectproto_p.h" #include "qv4regexp_p.h" #include "qv4stringobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4scopedvalue_p.h" #include <private/qqmljsengine_p.h> @@ -75,7 +75,7 @@ Heap::RegExpObject::RegExpObject(InternalClass *ic, QV4::Object *prototype) } Heap::RegExpObject::RegExpObject(QV4::ExecutionEngine *engine, QV4::RegExp *value, bool global) - : Heap::Object(engine->emptyClass, engine->regExpPrototype.asObject()) + : Heap::Object(engine->emptyClass, engine->regExpPrototype()) , value(value->d()) , global(global) { @@ -88,7 +88,7 @@ Heap::RegExpObject::RegExpObject(QV4::ExecutionEngine *engine, QV4::RegExp *valu // The conversion is not 100% exact since ECMA regexp and QRegExp // have different semantics/flags, but we try to do our best. Heap::RegExpObject::RegExpObject(QV4::ExecutionEngine *engine, const QRegExp &re) - : Heap::Object(engine->emptyClass, engine->regExpPrototype.asObject()) + : Heap::Object(engine->emptyClass, engine->regExpPrototype()) { value = 0; global = false; @@ -174,7 +174,7 @@ void RegExpObject::markObjects(Heap::Base *that, ExecutionEngine *e) Property *RegExpObject::lastIndexProperty() { - Q_ASSERT(0 == internalClass()->find(engine()->id_lastIndex)); + Q_ASSERT(0 == internalClass()->find(engine()->id_lastIndex())); return propertyAt(0); } @@ -231,14 +231,14 @@ Heap::RegExpCtor::RegExpCtor(QV4::ExecutionContext *scope) void Heap::RegExpCtor::clearLastMatch() { lastMatch = Primitive::nullValue(); - lastInput = internalClass->engine->id_empty; + lastInput = internalClass->engine->id_empty()->d(); lastMatchStart = 0; lastMatchEnd = 0; } -ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) +ReturnedValue RegExpCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<Object *>(m)->engine()); + Scope scope(static_cast<const Object *>(m)->engine()); ScopedContext ctx(scope, scope.engine->currentContext()); ScopedValue r(scope, callData->argument(0)); @@ -286,7 +286,7 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) return Encode(ctx->d()->engine->newRegExpObject(regexp, global)); } -ReturnedValue RegExpCtor::call(Managed *that, CallData *callData) +ReturnedValue RegExpCtor::call(const Managed *that, CallData *callData) { if (callData->argc > 0 && callData->args[0].as<RegExpObject>()) { if (callData->argc == 1 || callData->args[1].isUndefined()) @@ -300,7 +300,7 @@ void RegExpCtor::markObjects(Heap::Base *that, ExecutionEngine *e) { RegExpCtor::Data *This = static_cast<RegExpCtor::Data *>(that); This->lastMatch.mark(e); - This->lastInput.mark(e); + This->lastInput->mark(e); FunctionObject::markObjects(that, e); } @@ -310,8 +310,8 @@ void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor) ScopedObject o(scope); ScopedObject ctor(scope, constructor); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(2)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(2)); // Properties deprecated in the spec but required by "the web" :( ctor->defineAccessorProperty(QStringLiteral("lastMatch"), method_get_lastMatch_n<0>, 0); @@ -337,7 +337,7 @@ void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor) defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); defineDefaultProperty(QStringLiteral("exec"), method_exec, 1); defineDefaultProperty(QStringLiteral("test"), method_test, 1); - defineDefaultProperty(engine->id_toString, method_toString, 0); + defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("compile"), method_compile, 2); } @@ -363,7 +363,7 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) uint* matchOffsets = (uint*)alloca(r->value()->captureCount() * 2 * sizeof(uint)); const int result = Scoped<RegExp>(scope, r->value())->match(s, offset, matchOffsets); - Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor); + Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor()); regExpCtor->d()->clearLastMatch(); if (result == -1) { @@ -372,7 +372,7 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) } // fill in result data - ScopedArrayObject array(scope, scope.engine->newArrayObject(scope.engine->regExpExecArrayClass, scope.engine->arrayPrototype.asObject())); + ScopedArrayObject array(scope, scope.engine->newArrayObject(scope.engine->regExpExecArrayClass, scope.engine->arrayPrototype())); int len = r->value()->captureCount(); array->arrayReserve(len); ScopedValue v(scope); @@ -388,7 +388,7 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) RegExpCtor::Data *dd = regExpCtor->d(); dd->lastMatch = array; - dd->lastInput = arg->stringValue(); + dd->lastInput = arg->stringValue()->d(); dd->lastMatchStart = matchOffsets[0]; dd->lastMatchEnd = matchOffsets[1]; @@ -425,7 +425,7 @@ ReturnedValue RegExpPrototype::method_compile(CallContext *ctx) ScopedCallData callData(scope, ctx->argc()); memcpy(callData->args, ctx->args(), ctx->argc()*sizeof(Value)); - Scoped<RegExpObject> re(scope, ctx->d()->engine->regExpCtor.asFunctionObject()->construct(callData)); + Scoped<RegExpObject> re(scope, ctx->d()->engine->regExpCtor()->as<FunctionObject>()->construct(callData)); r->d()->value = re->value(); r->d()->global = re->global(); @@ -436,7 +436,7 @@ template <int index> ReturnedValue RegExpPrototype::method_get_lastMatch_n(CallContext *ctx) { Scope scope(ctx); - ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor.objectValue())->lastMatch()); + ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastMatch()); ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(index) : Encode::undefined()); if (result->isUndefined()) return ctx->d()->engine->newString()->asReturnedValue(); @@ -446,7 +446,7 @@ ReturnedValue RegExpPrototype::method_get_lastMatch_n(CallContext *ctx) ReturnedValue RegExpPrototype::method_get_lastParen(CallContext *ctx) { Scope scope(ctx); - ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor.objectValue())->lastMatch()); + ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastMatch()); ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(lastMatch->getLength() - 1) : Encode::undefined()); if (result->isUndefined()) return ctx->d()->engine->newString()->asReturnedValue(); @@ -455,13 +455,13 @@ ReturnedValue RegExpPrototype::method_get_lastParen(CallContext *ctx) ReturnedValue RegExpPrototype::method_get_input(CallContext *ctx) { - return static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor.objectValue())->lastInput().asReturnedValue(); + return static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastInput()->asReturnedValue(); } ReturnedValue RegExpPrototype::method_get_leftContext(CallContext *ctx) { Scope scope(ctx); - Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor); + Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor()); QString lastInput = regExpCtor->lastInput()->toQString(); return ctx->d()->engine->newString(lastInput.left(regExpCtor->lastMatchStart()))->asReturnedValue(); } @@ -469,7 +469,7 @@ ReturnedValue RegExpPrototype::method_get_leftContext(CallContext *ctx) ReturnedValue RegExpPrototype::method_get_rightContext(CallContext *ctx) { Scope scope(ctx); - Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor); + Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor()); QString lastInput = regExpCtor->lastInput()->toQString(); return ctx->d()->engine->newString(lastInput.mid(regExpCtor->lastMatchEnd()))->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index f5f255faf5..29d20614de 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -61,14 +61,14 @@ struct RegExpObject : Object { RegExpObject(QV4::ExecutionEngine *engine, QV4::RegExp *value, bool global); RegExpObject(QV4::ExecutionEngine *engine, const QRegExp &re); - RegExp *value; + Pointer<RegExp> value; bool global; }; struct RegExpCtor : FunctionObject { RegExpCtor(QV4::ExecutionContext *scope); Value lastMatch; - StringValue lastInput; + Pointer<String> lastInput; int lastMatchStart; int lastMatchEnd; void clearLastMatch(); @@ -117,12 +117,12 @@ struct RegExpCtor: FunctionObject V4_OBJECT2(RegExpCtor, FunctionObject) Value lastMatch() { return d()->lastMatch; } - StringValue lastInput() { return d()->lastInput; } + Heap::String *lastInput() { return d()->lastInput; } int lastMatchStart() { return d()->lastMatchStart; } int lastMatchEnd() { return d()->lastMatchEnd; } - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; @@ -146,7 +146,7 @@ struct RegExpPrototype: RegExpObject }; inline Heap::RegExpPrototype::RegExpPrototype(ExecutionEngine *e) - : RegExpObject(e->emptyClass, e->objectPrototype.asObject()) + : RegExpObject(e->emptyClass, e->objectPrototype()) { } diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index b66e917b87..b8ea6d7a87 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -40,12 +40,15 @@ #include "qv4stringobject_p.h" #include "qv4argumentsobject_p.h" #include "qv4objectiterator_p.h" +#include "qv4dateobject_p.h" #include "qv4lookup_p.h" #include "qv4function_p.h" #include "private/qlocale_tools_p.h" #include "qv4scopedvalue_p.h" #include <private/qqmlcontextwrapper_p.h> #include <private/qqmltypewrapper_p.h> +#include <private/qqmlengine_p.h> +#include <private/qqmljavascriptexpression_p.h> #include "qv4qobjectwrapper_p.h" #include <private/qv8engine_p.h> #endif @@ -313,14 +316,14 @@ ReturnedValue Runtime::deleteName(ExecutionEngine *engine, int nameIndex) QV4::ReturnedValue Runtime::instanceof(ExecutionEngine *engine, const Value &left, const Value &right) { Scope scope(engine); - ScopedFunctionObject f(scope, right.asFunctionObject()); + ScopedFunctionObject f(scope, right.as<FunctionObject>()); if (!f) return engine->throwTypeError(); if (f->isBoundFunction()) f = static_cast<BoundFunction *>(f.getPointer())->target(); - ScopedObject v(scope, left.asObject()); + ScopedObject v(scope, left.as<Object>()); if (!v) return Encode(false); @@ -380,10 +383,10 @@ Heap::String *RuntimeHelpers::stringFromNumber(ExecutionEngine *engine, double n return engine->newString(qstr); } -ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint) +ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeHint) { if (typeHint == PREFERREDTYPE_HINT) { - if (object->asDateObject()) + if (object->as<DateObject>()) typeHint = STRING_HINT; else typeHint = NUMBER_HINT; @@ -393,18 +396,18 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint) if (engine->hasException) return Encode::undefined(); - StringValue *meth1 = &engine->id_toString; - StringValue *meth2 = &engine->id_valueOf; + String *meth1 = engine->id_toString(); + String *meth2 = engine->id_valueOf(); if (typeHint == NUMBER_HINT) qSwap(meth1, meth2); Scope scope(engine); ScopedCallData callData(scope, 0); - callData->thisObject = object; + callData->thisObject = *object; - ScopedValue conv(scope, object->get(*meth1)); - if (FunctionObject *o = conv->asFunctionObject()) { + ScopedValue conv(scope, object->get(meth1)); + if (FunctionObject *o = conv->as<FunctionObject>()) { ScopedValue r(scope, o->call(callData)); if (r->isPrimitive()) return r->asReturnedValue(); @@ -413,8 +416,8 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint) if (engine->hasException) return Encode::undefined(); - conv = object->get(*meth2); - if (FunctionObject *o = conv->asFunctionObject()) { + conv = object->get(meth2); + if (FunctionObject *o = conv->as<FunctionObject>()) { ScopedValue r(scope, o->call(callData)); if (r->isPrimitive()) return r->asReturnedValue(); @@ -437,7 +440,7 @@ Heap::Object *RuntimeHelpers::convertToObject(ExecutionEngine *engine, const Val return engine->newBooleanObject(value.booleanValue()); case Value::Managed_Type: Q_ASSERT(value.isString()); - return engine->newStringObject(value); + return engine->newStringObject(value.stringValue()); case Value::Integer_Type: default: // double return engine->newNumberObject(value.asDouble()); @@ -450,14 +453,14 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, const Val case Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); case Value::Undefined_Type: - return engine->id_undefined->d(); + return engine->id_undefined()->d(); case Value::Null_Type: - return engine->id_null->d(); + return engine->id_null()->d(); case Value::Boolean_Type: if (value.booleanValue()) - return engine->id_true->d(); + return engine->id_true()->d(); else - return engine->id_false->d(); + return engine->id_false()->d(); case Value::Managed_Type: if (value.isString()) return value.stringValue()->d(); @@ -467,7 +470,7 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, const Val return RuntimeHelpers::convertToString(engine, prim); } case Value::Integer_Type: - return RuntimeHelpers::stringFromNumber(engine, value.int_32); + return RuntimeHelpers::stringFromNumber(engine, value.int_32()); default: // double return RuntimeHelpers::stringFromNumber(engine, value.doubleValue()); } // switch @@ -481,14 +484,14 @@ static Heap::String *convert_to_string_add(ExecutionEngine *engine, const Value case Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); case Value::Undefined_Type: - return engine->id_undefined->d(); + return engine->id_undefined()->d(); case Value::Null_Type: - return engine->id_null->d(); + return engine->id_null()->d(); case Value::Boolean_Type: if (value.booleanValue()) - return engine->id_true->d(); + return engine->id_true()->d(); else - return engine->id_false->d(); + return engine->id_false()->d(); case Value::Managed_Type: if (value.isString()) return value.stringValue()->d(); @@ -498,7 +501,7 @@ static Heap::String *convert_to_string_add(ExecutionEngine *engine, const Value return RuntimeHelpers::convertToString(engine, prim); } case Value::Integer_Type: - return RuntimeHelpers::stringFromNumber(engine, value.int_32); + return RuntimeHelpers::stringFromNumber(engine, value.int_32()); default: // double return RuntimeHelpers::stringFromNumber(engine, value.doubleValue()); } // switch @@ -578,7 +581,7 @@ ReturnedValue Runtime::getElement(ExecutionEngine *engine, const Value &object, ScopedObject o(scope, object); if (!o) { if (idx < UINT_MAX) { - if (String *str = object.asString()) { + if (const String *str = object.as<String>()) { if (idx >= (uint)str->toQString().length()) { return Encode::undefined(); } @@ -912,7 +915,7 @@ ReturnedValue Runtime::callGlobalLookup(ExecutionEngine *engine, uint index, Cal return engine->throwTypeError(); ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); - if (o->d() == scope.engine->evalFunction && name->equals(scope.engine->id_eval)) + if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) return static_cast<EvalFunction *>(o.getPointer())->evalCall(callData, true); return o->call(callData); @@ -934,7 +937,7 @@ ReturnedValue Runtime::callActivationProperty(ExecutionEngine *engine, int nameI if (base) callData->thisObject = base; - FunctionObject *o = func->asFunctionObject(); + FunctionObject *o = func->as<FunctionObject>(); if (!o) { QString objectAsString = QStringLiteral("[null]"); if (base) @@ -943,13 +946,37 @@ ReturnedValue Runtime::callActivationProperty(ExecutionEngine *engine, int nameI return engine->throwTypeError(msg); } - if (o->d() == scope.engine->evalFunction && name->equals(scope.engine->id_eval)) { + if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) { return static_cast<EvalFunction *>(o)->evalCall(callData, true); } return o->call(callData); } +ReturnedValue Runtime::callQmlScopeObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData) +{ + Scope scope(engine); + ScopedFunctionObject o(scope, getQmlScopeObjectProperty(engine, callData->thisObject, propertyIndex)); + if (!o) { + QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(propertyIndex).arg(callData->thisObject.toQStringNoThrow()); + return engine->throwTypeError(error); + } + + return o->call(callData); +} + +ReturnedValue Runtime::callQmlContextObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData) +{ + Scope scope(engine); + ScopedFunctionObject o(scope, getQmlContextObjectProperty(engine, callData->thisObject, propertyIndex)); + if (!o) { + QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(propertyIndex).arg(callData->thisObject.toQStringNoThrow()); + return engine->throwTypeError(error); + } + + return o->call(callData); +} + ReturnedValue Runtime::callProperty(ExecutionEngine *engine, int nameIndex, CallData *callData) { Scope scope(engine); @@ -1037,7 +1064,7 @@ ReturnedValue Runtime::constructActivationProperty(ExecutionEngine *engine, int if (scope.engine->hasException) return Encode::undefined(); - Object *f = func->asObject(); + Object *f = func->as<Object>(); if (!f) return engine->throwTypeError(); @@ -1046,7 +1073,7 @@ ReturnedValue Runtime::constructActivationProperty(ExecutionEngine *engine, int ReturnedValue Runtime::constructValue(ExecutionEngine *engine, const Value &func, CallData *callData) { - Object *f = func.asObject(); + const Object *f = func.as<Object>(); if (!f) return engine->throwTypeError(); @@ -1092,24 +1119,24 @@ ReturnedValue Runtime::typeofValue(ExecutionEngine *engine, const Value &value) ScopedString res(scope); switch (value.type()) { case Value::Undefined_Type: - res = engine->id_undefined; + res = engine->id_undefined(); break; case Value::Null_Type: - res = engine->id_object; + res = engine->id_object(); break; case Value::Boolean_Type: - res = engine->id_boolean; + res = engine->id_boolean(); break; case Value::Managed_Type: if (value.isString()) - res = engine->id_string; - else if (value.objectValue()->asFunctionObject()) - res = engine->id_function; + res = engine->id_string(); + else if (value.objectValue()->as<FunctionObject>()) + res = engine->id_function(); else - res = engine->id_object; // ### implementation-defined + res = engine->id_object(); // ### implementation-defined break; default: - res = engine->id_number; + res = engine->id_number(); break; } return res.asReturnedValue(); @@ -1202,7 +1229,7 @@ ReturnedValue Runtime::objectLiteral(ExecutionEngine *engine, const QV4::Value * { Scope scope(engine); QV4::InternalClass *klass = engine->currentContext()->compilationUnit->runtimeClasses[classId]; - ScopedObject o(scope, engine->newObject(klass, engine->objectPrototype.asObject())); + ScopedObject o(scope, engine->newObject(klass, engine->objectPrototype())); { bool needSparseArray = arrayGetterSetterCountAndFlags >> 30; @@ -1242,7 +1269,7 @@ ReturnedValue Runtime::objectLiteral(ExecutionEngine *engine, const QV4::Value * QV4::ReturnedValue Runtime::setupArgumentsObject(ExecutionEngine *engine) { - Q_ASSERT(engine->currentContext()->type >= Heap::ExecutionContext::Type_CallContext); + Q_ASSERT(engine->currentContext()->type == Heap::ExecutionContext::Type_CallContext); Scope scope(engine); Scoped<CallContext> c(scope, static_cast<Heap::CallContext *>(engine->currentContext())); return (engine->memoryManager->alloc<ArgumentsObject>(c))->asReturnedValue(); @@ -1327,34 +1354,16 @@ unsigned Runtime::doubleToUInt(const double &d) return Primitive::toUInt32(d); } -#ifndef V4_BOOTSTRAP - -ReturnedValue Runtime::regexpLiteral(ExecutionEngine *engine, int id) +ReturnedValue Runtime::getQmlContext(NoThrowEngine *engine) { - return engine->currentContext()->compilationUnit->runtimeRegularExpressions[id].asReturnedValue(); + return engine->qmlContext()->asReturnedValue(); } -ReturnedValue Runtime::getQmlIdArray(NoThrowEngine *engine) -{ - Q_ASSERT(engine->qmlContextObject()); - Scope scope(engine); - Scoped<QmlContextWrapper> wrapper(scope, engine->qmlContextObject()); - return wrapper->idObjectsArray(); -} - -ReturnedValue Runtime::getQmlContextObject(NoThrowEngine *engine) -{ - QQmlContextData *context = QmlContextWrapper::callingContext(engine); - if (!context) - return Encode::undefined(); - return QObjectWrapper::wrap(engine, context->contextObject); -} +#ifndef V4_BOOTSTRAP -ReturnedValue Runtime::getQmlScopeObject(NoThrowEngine *engine) +ReturnedValue Runtime::regexpLiteral(ExecutionEngine *engine, int id) { - Scope scope(engine); - QV4::Scoped<QmlContextWrapper> c(scope, engine->qmlContextObject()); - return QObjectWrapper::wrap(engine, c->getScopeObject()); + return engine->currentContext()->compilationUnit->runtimeRegularExpressions[id].asReturnedValue(); } ReturnedValue Runtime::getQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired) @@ -1365,21 +1374,29 @@ ReturnedValue Runtime::getQmlQObjectProperty(ExecutionEngine *engine, const Valu engine->throwTypeError(QStringLiteral("Cannot read property of null")); return Encode::undefined(); } - ScopedContext ctx(scope, engine->currentContext()); - return QV4::QObjectWrapper::getProperty(wrapper->object(), ctx, propertyIndex, captureRequired); + return QV4::QObjectWrapper::getProperty(scope.engine, wrapper->object(), propertyIndex, captureRequired); } QV4::ReturnedValue Runtime::getQmlAttachedProperty(ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex) { - Scope scope(engine); - QV4::Scoped<QmlContextWrapper> c(scope, engine->qmlContextObject()); - QObject *scopeObject = c->getScopeObject(); + QObject *scopeObject = engine->qmlScopeObject(); QObject *attachedObject = qmlAttachedPropertiesObjectById(attachedPropertiesId, scopeObject); QJSEngine *jsEngine = engine->jsEngine(); QQmlData::ensurePropertyCache(jsEngine, attachedObject); - ScopedContext ctx(scope, engine->currentContext()); - return QV4::QObjectWrapper::getProperty(attachedObject, ctx, propertyIndex, /*captureRequired*/true); + return QV4::QObjectWrapper::getProperty(engine, attachedObject, propertyIndex, /*captureRequired*/true); +} + +ReturnedValue Runtime::getQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex) +{ + const QmlContext &c = static_cast<const QmlContext &>(context); + return QV4::QObjectWrapper::getProperty(engine, c.d()->qml->scopeObject, propertyIndex, false); +} + +ReturnedValue Runtime::getQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex) +{ + const QmlContext &c = static_cast<const QmlContext &>(context); + return QV4::QObjectWrapper::getProperty(engine, c.d()->qml->context->contextObject, propertyIndex, false); } ReturnedValue Runtime::getQmlSingletonQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired) @@ -1390,8 +1407,34 @@ ReturnedValue Runtime::getQmlSingletonQObjectProperty(ExecutionEngine *engine, c scope.engine->throwTypeError(QStringLiteral("Cannot read property of null")); return Encode::undefined(); } - ScopedContext ctx(scope, engine->currentContext()); - return QV4::QObjectWrapper::getProperty(wrapper->singletonObject(), ctx, propertyIndex, captureRequired); + return QV4::QObjectWrapper::getProperty(scope.engine, wrapper->singletonObject(), propertyIndex, captureRequired); +} + +ReturnedValue Runtime::getQmlIdObject(ExecutionEngine *engine, const Value &c, uint index) +{ + Scope scope(engine); + const QmlContext &qmlContext = static_cast<const QmlContext &>(c); + QQmlContextData *context = qmlContext.d()->qml->context; + if (!context || index >= (uint)context->idValueCount) + return Encode::undefined(); + + QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; + if (ep && ep->propertyCapture) + ep->propertyCapture->captureProperty(&context->idValues[index].bindings); + + return QObjectWrapper::wrap(engine, context->idValues[index].data()); +} + +void Runtime::setQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value) +{ + const QmlContext &c = static_cast<const QmlContext &>(context); + return QV4::QObjectWrapper::setProperty(engine, c.d()->qml->scopeObject, propertyIndex, value); +} + +void Runtime::setQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value) +{ + const QmlContext &c = static_cast<const QmlContext &>(context); + return QV4::QObjectWrapper::setProperty(engine, c.d()->qml->context->contextObject, propertyIndex, value); } void Runtime::setQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value) @@ -1402,13 +1445,12 @@ void Runtime::setQmlQObjectProperty(ExecutionEngine *engine, const Value &object engine->throwTypeError(QStringLiteral("Cannot write property of null")); return; } - ScopedContext ctx(scope, engine->currentContext()); - wrapper->setProperty(ctx, propertyIndex, value); + wrapper->setProperty(engine, propertyIndex, value); } ReturnedValue Runtime::getQmlImportedScripts(NoThrowEngine *engine) { - QQmlContextData *context = QmlContextWrapper::callingContext(engine); + QQmlContextData *context = engine->callingQmlContext(); if (!context) return Encode::undefined(); return context->importedScripts.value(); @@ -1428,7 +1470,7 @@ void Runtime::convertThisToObject(ExecutionEngine *engine) if (t->isObject()) return; if (t->isNullOrUndefined()) { - *t = engine->globalObject()->asReturnedValue(); + *t = engine->globalObject->asReturnedValue(); } else { *t = t->toObject(engine)->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index f2f90bbc15..f597e4b2e3 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -34,8 +34,9 @@ #define QMLJS_RUNTIME_H #include "qv4global_p.h" -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #include "qv4context_p.h" +#include "qv4engine_p.h" #include "qv4math_p.h" #include <QtCore/qnumeric.h> @@ -90,6 +91,8 @@ struct Q_QML_PRIVATE_EXPORT Runtime { // call static ReturnedValue callGlobalLookup(ExecutionEngine *engine, uint index, CallData *callData); static ReturnedValue callActivationProperty(ExecutionEngine *engine, int nameIndex, CallData *callData); + static ReturnedValue callQmlScopeObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData); + static ReturnedValue callQmlContextObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData); static ReturnedValue callProperty(ExecutionEngine *engine, int nameIndex, CallData *callData); static ReturnedValue callPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData); static ReturnedValue callElement(ExecutionEngine *engine, const Value &index, CallData *callData); @@ -206,19 +209,23 @@ struct Q_QML_PRIVATE_EXPORT Runtime { static unsigned doubleToUInt(const double &d); // qml - static ReturnedValue getQmlIdArray(NoThrowEngine *ctx); - static ReturnedValue getQmlImportedScripts(NoThrowEngine *ctx); - static ReturnedValue getQmlContextObject(NoThrowEngine *ctx); - static ReturnedValue getQmlScopeObject(NoThrowEngine *ctx); - static ReturnedValue getQmlSingleton(NoThrowEngine *ctx, int nameIndex); + static ReturnedValue getQmlContext(NoThrowEngine *engine); + static ReturnedValue getQmlImportedScripts(NoThrowEngine *engine); + static ReturnedValue getQmlSingleton(NoThrowEngine *engine, int nameIndex); static ReturnedValue getQmlAttachedProperty(ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex); + static ReturnedValue getQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex); + static ReturnedValue getQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex); static ReturnedValue getQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired); static ReturnedValue getQmlSingletonQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired); + static ReturnedValue getQmlIdObject(ExecutionEngine *engine, const Value &context, uint index); + + static void setQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value); + static void setQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value); static void setQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value); }; struct Q_QML_PRIVATE_EXPORT RuntimeHelpers { - static ReturnedValue objectDefaultValue(Object *object, int typeHint); + static ReturnedValue objectDefaultValue(const Object *object, int typeHint); static ReturnedValue toPrimitive(const Value &value, int typeHint); static double stringToNumber(const QString &s); @@ -243,7 +250,7 @@ struct Q_QML_PRIVATE_EXPORT RuntimeHelpers { #ifndef V4_BOOTSTRAP inline ReturnedValue RuntimeHelpers::toPrimitive(const Value &value, int typeHint) { - Object *o = value.asObject(); + const Object *o = value.as<Object>(); if (!o) return value.asReturnedValue(); return RuntimeHelpers::objectDefaultValue(o, typeHint); @@ -262,7 +269,7 @@ inline ReturnedValue Runtime::uPlus(const Value &value) if (value.isNumber()) return value.asReturnedValue(); if (value.integerCompatible()) - return Encode(value.int_32); + return Encode(value.int_32()); double n = value.toNumberImpl(); return Encode(n); @@ -369,6 +376,15 @@ inline ReturnedValue Runtime::div(const Value &left, const Value &right) { TRACE2(left, right); + if (Value::integerCompatible(left, right)) { + int lval = left.integerValue(); + int rval = right.integerValue(); + if (rval != 0 && (lval % rval == 0)) + return Encode(int(lval / rval)); + else + return Encode(double(lval) / rval); + } + double lval = left.toNumber(); double rval = right.toNumber(); return Primitive::fromDouble(lval / rval).asReturnedValue(); diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 908248f0f0..e19aeaf882 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -85,10 +85,7 @@ struct Scope { #ifndef QT_NO_DEBUG size += nValues; #endif - Value *ptr = engine->jsStackTop; - engine->jsStackTop = ptr + nValues; - memset(ptr, 0, nValues*sizeof(Value)); - return ptr; + return engine->jsAlloca(nValues); } bool hasException() const { @@ -110,7 +107,7 @@ struct ScopedValue ScopedValue(const Scope &scope) { ptr = scope.engine->jsStackTop++; - ptr->val = 0; + ptr->setRawValue(0); #ifndef QT_NO_DEBUG ++scope.size; #endif @@ -128,9 +125,9 @@ struct ScopedValue ScopedValue(const Scope &scope, Heap::Base *o) { ptr = scope.engine->jsStackTop++; - ptr->m = o; + ptr->setM(o); #if QT_POINTER_SIZE == 4 - ptr->tag = QV4::Value::Managed_Type; + ptr->setTag(QV4::Value::Managed_Type); #endif #ifndef QT_NO_DEBUG ++scope.size; @@ -140,7 +137,7 @@ struct ScopedValue ScopedValue(const Scope &scope, Managed *m) { ptr = scope.engine->jsStackTop++; - ptr->val = m->asReturnedValue(); + ptr->setRawValue(m->asReturnedValue()); #ifndef QT_NO_DEBUG ++scope.size; #endif @@ -149,7 +146,7 @@ struct ScopedValue ScopedValue(const Scope &scope, const ReturnedValue &v) { ptr = scope.engine->jsStackTop++; - ptr->val = v; + ptr->setRawValue(v); #ifndef QT_NO_DEBUG ++scope.size; #endif @@ -161,9 +158,9 @@ struct ScopedValue } ScopedValue &operator=(Heap::Base *o) { - ptr->m = o; + ptr->setM(o); #if QT_POINTER_SIZE == 4 - ptr->tag = QV4::Value::Managed_Type; + ptr->setTag(QV4::Value::Managed_Type); #endif return *this; } @@ -174,7 +171,7 @@ struct ScopedValue } ScopedValue &operator=(const ReturnedValue &v) { - ptr->val = v; + ptr->setRawValue(v); return *this; } @@ -202,30 +199,29 @@ struct Scoped { enum _Convert { Convert }; - inline void setPointer(Managed *p) { - ptr->m = p ? p->m : 0; + inline void setPointer(const Managed *p) { + ptr->setM(p ? p->m() : 0); #if QT_POINTER_SIZE == 4 - ptr->tag = QV4::Value::Managed_Type; + ptr->setTag(QV4::Value::Managed_Type); #endif } Scoped(const Scope &scope) { ptr = scope.engine->jsStackTop++; - ptr->m = 0; + ptr->setM(0); #if QT_POINTER_SIZE == 4 - ptr->tag = QV4::Value::Managed_Type; + ptr->setTag(QV4::Value::Managed_Type); #endif #ifndef QT_NO_DEBUG ++scope.size; #endif } - // ### GC FIX casting below to be safe Scoped(const Scope &scope, const Value &v) { ptr = scope.engine->jsStackTop++; - setPointer(value_cast<T>(v)); + setPointer(v.as<T>()); #ifndef QT_NO_DEBUG ++scope.size; #endif @@ -235,7 +231,7 @@ struct Scoped Value v; v = o; ptr = scope.engine->jsStackTop++; - setPointer(value_cast<T>(v)); + setPointer(v.as<T>()); #ifndef QT_NO_DEBUG ++scope.size; #endif @@ -243,7 +239,7 @@ struct Scoped Scoped(const Scope &scope, const ScopedValue &v) { ptr = scope.engine->jsStackTop++; - setPointer(value_cast<T>(*v.ptr)); + setPointer(v.ptr->as<T>()); #ifndef QT_NO_DEBUG ++scope.size; #endif @@ -252,7 +248,7 @@ struct Scoped Scoped(const Scope &scope, const Value &v, _Convert) { ptr = scope.engine->jsStackTop++; - ptr->val = value_convert<T>(scope.engine, v); + ptr->setRawValue(value_convert<T>(scope.engine, v)); #ifndef QT_NO_DEBUG ++scope.size; #endif @@ -261,7 +257,7 @@ struct Scoped Scoped(const Scope &scope, const Value *v) { ptr = scope.engine->jsStackTop++; - setPointer(v ? value_cast<T>(*v) : 0); + setPointer(v ? v->as<T>() : 0); #ifndef QT_NO_DEBUG ++scope.size; #endif @@ -287,7 +283,7 @@ struct Scoped Scoped(const Scope &scope, const ReturnedValue &v) { ptr = scope.engine->jsStackTop++; - setPointer(value_cast<T>(QV4::Value::fromReturnedValue(v))); + setPointer(QV4::Value::fromReturnedValue(v).as<T>()); #ifndef QT_NO_DEBUG ++scope.size; #endif @@ -295,16 +291,14 @@ struct Scoped Scoped(const Scope &scope, const ReturnedValue &v, _Convert) { ptr = scope.engine->jsStackTop++; - ptr->val = value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v)); + ptr->setRawValue(value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v))); #ifndef QT_NO_DEBUG ++scope.size; #endif } Scoped<T> &operator=(Heap::Base *o) { - Value v; - v = o; - setPointer(value_cast<T>(v)); + setPointer(Value::fromHeapObject(o).as<T>()); return *this; } Scoped<T> &operator=(typename T::Data *t) { @@ -312,16 +306,16 @@ struct Scoped return *this; } Scoped<T> &operator=(const Value &v) { - setPointer(value_cast<T>(v)); + setPointer(v.as<T>()); return *this; } Scoped<T> &operator=(Value *v) { - setPointer(v ? value_cast<T>(*v) : 0); + setPointer(v ? v->as<T>() : 0); return *this; } Scoped<T> &operator=(const ReturnedValue &v) { - setPointer(value_cast<T>(QV4::Value::fromReturnedValue(v))); + setPointer(QV4::Value::fromReturnedValue(v).as<T>()); return *this; } @@ -347,21 +341,21 @@ struct Scoped } bool operator!() const { - return !ptr->m; + return !ptr->m(); } operator void *() const { - return ptr->m; + return ptr->m(); } T *getPointer() { return ptr->cast<T>(); } - typename T::Data **getRef() { - return reinterpret_cast<typename T::Data **>(&ptr->m); + Value *getRef() { + return ptr; } ReturnedValue asReturnedValue() const { - return ptr->m ? ptr->val : Encode::undefined(); + return ptr->m() ? ptr->rawValue() : Encode::undefined(); } Value *ptr; @@ -390,41 +384,14 @@ struct ScopedCallData { inline Value &Value::operator =(const ScopedValue &v) { - val = v.ptr->val; + _val = v.ptr->val(); return *this; } template<typename T> inline Value &Value::operator=(const Scoped<T> &t) { - val = t.ptr->val; - return *this; -} - -template<typename T> -inline TypedValue<T> &TypedValue<T>::operator =(T *t) -{ - m = t ? t->m : 0; -#if QT_POINTER_SIZE == 4 - tag = Managed_Type; -#endif - return *this; -} - -template<typename T> -inline TypedValue<T> &TypedValue<T>::operator =(const Scoped<T> &v) -{ - m = v.ptr->m; -#if QT_POINTER_SIZE == 4 - tag = Managed_Type; -#endif - return *this; -} - -template<typename T> -inline TypedValue<T> &TypedValue<T>::operator=(const TypedValue<T> &t) -{ - val = t.val; + _val = t.ptr->val(); return *this; } @@ -453,18 +420,18 @@ struct ExecutionContextSaver : engine(context->d()->engine) , savedContext(scope.alloc(1)) { - savedContext->m = context->d(); + savedContext->setM(context->d()); #if QT_POINTER_SIZE == 4 - savedContext->tag = QV4::Value::Managed_Type; + savedContext->setTag(QV4::Value::Managed_Type); #endif } ExecutionContextSaver(Scope &scope, Heap::ExecutionContext *context) : engine(context->engine) , savedContext(scope.alloc(1)) { - savedContext->m = context; + savedContext->setM(context); #if QT_POINTER_SIZE == 4 - savedContext->tag = QV4::Value::Managed_Type; + savedContext->setTag(QV4::Value::Managed_Type); #endif } ~ExecutionContextSaver() diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 4fde0e2445..0bf4f21acb 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -32,11 +32,12 @@ ****************************************************************************/ #include "qv4script_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4functionobject_p.h" #include "qv4function_p.h" #include "qv4context_p.h" #include "qv4debugging_p.h" +#include "qv4profiling_p.h" #include "qv4scopedvalue_p.h" #include <private/qqmljsengine_p.h> @@ -44,6 +45,7 @@ #include <private/qqmljsparser_p.h> #include <private/qqmljsast_p.h> #include <private/qqmlengine_p.h> +#include <private/qv4profiling_p.h> #include <qv4jsir_p.h> #include <qv4codegen_p.h> #include <private/qqmlcontextwrapper_p.h> @@ -86,8 +88,8 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlBindingWrapper); DEFINE_OBJECT_VTABLE(CompilationUnitHolder); -Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::Object *qml) - : Heap::FunctionObject(scope, scope->d()->engine->id_eval, /*createProto = */ false) +Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::QmlContextWrapper *qml) + : Heap::FunctionObject(scope, scope->d()->engine->id_eval(), /*createProto = */ false) , qml(qml->d()) { Q_ASSERT(scope->inUse()); @@ -97,46 +99,43 @@ Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, Functio function->compilationUnit->addref(); Scope s(scope); - Scoped<QV4::QmlBindingWrapper> o(s, this); + Scoped<QV4::QmlBindingWrapper> protectThis(s, this); - o->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(1)); - - ScopedContext ctx(s, s.engine->currentContext()); - o->d()->qmlContext = ctx->newQmlContext(o, qml); - s.engine->popContext(); + this->scope = scope->newQmlContext(qml); + internalClass->engine->popContext(); } -Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, QV4::Object *qml) - : Heap::FunctionObject(scope, scope->d()->engine->id_eval, /*createProto = */ false) +Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, QV4::QmlContextWrapper *qml) + : Heap::FunctionObject(scope, scope->d()->engine->id_eval(), /*createProto = */ false) , qml(qml->d()) { Q_ASSERT(scope->inUse()); Scope s(scope); - Scoped<QV4::QmlBindingWrapper> o(s, this); - - o->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(1)); + Scoped<QV4::QmlBindingWrapper> protectThis(s, this); - ScopedContext ctx(s, s.engine->currentContext()); - o->d()->qmlContext = ctx->newQmlContext(o, qml); - s.engine->popContext(); + this->scope = scope->newQmlContext(qml); + internalClass->engine->popContext(); } -ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *) +ReturnedValue QmlBindingWrapper::call(const Managed *that, CallData *callData) { - ExecutionEngine *engine = static_cast<Object *>(that)->engine(); - CHECK_STACK_LIMITS(engine); + const QmlBindingWrapper *This = static_cast<const QmlBindingWrapper *>(that); + ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); + if (v4->hasException) + return Encode::undefined(); + CHECK_STACK_LIMITS(v4); - Scope scope(engine); - QmlBindingWrapper *This = static_cast<QmlBindingWrapper *>(that); - if (!This->function()) + Scope scope(v4); + QV4::Function *f = This->function(); + if (!f) return QV4::Encode::undefined(); - Scoped<CallContext> ctx(scope, This->d()->qmlContext); - std::fill(ctx->d()->locals, ctx->d()->locals + ctx->d()->function->varCount(), Primitive::undefinedValue()); - engine->pushContext(ctx); - ScopedValue result(scope, This->function()->code(engine, This->function()->codeData)); - engine->popContext(); + ScopedContext context(scope, v4->currentContext()); + Scoped<CallContext> ctx(scope, context->newCallContext(This, callData)); + + ExecutionContextSaver ctxSaver(scope, context); + ScopedValue result(scope, Q_V4_PROFILE(v4, f)); return result->asReturnedValue(); } @@ -147,14 +146,12 @@ void QmlBindingWrapper::markObjects(Heap::Base *m, ExecutionEngine *e) if (wrapper->qml) wrapper->qml->mark(e); FunctionObject::markObjects(m, e); - if (wrapper->qmlContext) - wrapper->qmlContext->mark(e); } static ReturnedValue signalParameterGetter(QV4::CallContext *ctx, uint parameterIndex) { QV4::Scope scope(ctx); - QV4::Scoped<CallContext> signalEmittingContext(scope, static_cast<Heap::CallContext *>(ctx->d()->parent)); + QV4::Scoped<CallContext> signalEmittingContext(scope, ctx->d()->parent.cast<Heap::CallContext>()); Q_ASSERT(signalEmittingContext && signalEmittingContext->d()->type >= QV4::Heap::ExecutionContext::Type_SimpleCallContext); return signalEmittingContext->argument(parameterIndex); } @@ -163,10 +160,10 @@ Heap::FunctionObject *QmlBindingWrapper::createQmlCallableForFunction(QQmlContex { ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(qmlContext->engine); QV4::Scope valueScope(engine); - QV4::ScopedObject qmlScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(engine, qmlContext, scopeObject)); + QV4::Scoped<QmlContextWrapper> qmlScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(engine, qmlContext, scopeObject)); ScopedContext global(valueScope, valueScope.engine->rootContext()); QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, engine->memoryManager->alloc<QV4::QmlBindingWrapper>(global, qmlScopeObject)); - QV4::Scoped<CallContext> wrapperContext(valueScope, wrapper->context()); + QV4::Scoped<QmlContext> wrapperContext(valueScope, wrapper->context()); if (!signalParameters.isEmpty()) { if (error) @@ -214,7 +211,7 @@ void Script::parse() parsed = true; - ExecutionEngine *v4 = scope->engine; + ExecutionEngine *v4 = scope->engine(); Scope valueScope(v4); MemoryManager::GCBlocker gcBlocker(v4->memoryManager); @@ -285,7 +282,7 @@ ReturnedValue Script::run() if (!vmFunction) return Encode::undefined(); - QV4::ExecutionEngine *engine = scope->engine; + QV4::ExecutionEngine *engine = scope->engine(); QV4::Scope valueScope(engine); if (qml.isUndefined()) { @@ -293,15 +290,14 @@ ReturnedValue Script::run() ExecutionContextSaver ctxSaver(valueScope, scope); ContextStateSaver stateSaver(valueScope, scope); - scope->strictMode = vmFunction->isStrict(); - scope->lookups = vmFunction->compilationUnit->runtimeLookups; - scope->compilationUnit = vmFunction->compilationUnit; + scope->d()->strictMode = vmFunction->isStrict(); + scope->d()->lookups = vmFunction->compilationUnit->runtimeLookups; + scope->d()->compilationUnit = vmFunction->compilationUnit; - return vmFunction->code(engine, vmFunction->codeData); + return Q_V4_PROFILE(engine, vmFunction); } else { - ScopedObject qmlObj(valueScope, qml.value()); - ScopedContext ctx(valueScope, scope); - ScopedFunctionObject f(valueScope, engine->memoryManager->alloc<QmlBindingWrapper>(ctx, vmFunction, qmlObj)); + Scoped<QmlContextWrapper> qmlObj(valueScope, qml.value()); + ScopedFunctionObject f(valueScope, engine->memoryManager->alloc<QmlBindingWrapper>(scope, vmFunction, qmlObj)); ScopedCallData callData(valueScope); callData->thisObject = Primitive::undefinedValue(); return f->call(callData); @@ -376,11 +372,10 @@ ReturnedValue Script::qmlBinding() { if (!parsed) parse(); - ExecutionEngine *v4 = scope->engine; + ExecutionEngine *v4 = scope->engine(); Scope valueScope(v4); - ScopedObject qmlObj(valueScope, qml.value()); - ScopedContext ctx(valueScope, scope); - ScopedObject v(valueScope, v4->memoryManager->alloc<QmlBindingWrapper>(ctx, vmFunction, qmlObj)); + Scoped<QmlContextWrapper> qmlObj(valueScope, qml.value()); + ScopedObject v(valueScope, v4->memoryManager->alloc<QmlBindingWrapper>(scope, vmFunction, qmlObj)); return v.asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index 05a9e45f45..77784dfc4f 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -63,7 +63,7 @@ struct ContextStateSaver { , compilationUnit(context->d()->compilationUnit) , lineNumber(context->d()->lineNumber) { - savedContext->m = context->d(); + savedContext->setM(context->d()); } ContextStateSaver(Scope &scope, Heap::ExecutionContext *context) : savedContext(scope.alloc(1)) @@ -72,12 +72,12 @@ struct ContextStateSaver { , compilationUnit(context->compilationUnit) , lineNumber(context->lineNumber) { - savedContext->m = context; + savedContext->setM(context); } ~ContextStateSaver() { - Heap::ExecutionContext *ctx = static_cast<Heap::ExecutionContext *>(savedContext->m); + Heap::ExecutionContext *ctx = static_cast<Heap::ExecutionContext *>(savedContext->m()); ctx->strictMode = strictMode; ctx->lookups = lookups; ctx->compilationUnit = compilationUnit; @@ -87,11 +87,10 @@ struct ContextStateSaver { namespace Heap { struct QmlBindingWrapper : Heap::FunctionObject { - QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::Object *qml); + QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::QmlContextWrapper *qml); // Constructor for QML functions and signal handlers, resulting binding wrapper is not callable! - QmlBindingWrapper(QV4::ExecutionContext *scope, QV4::Object *qml); - Object *qml; - CallContext *qmlContext; + QmlBindingWrapper(QV4::ExecutionContext *scope, QV4::QmlContextWrapper *qml); + Pointer<Object> qml; }; } @@ -99,21 +98,19 @@ struct QmlBindingWrapper : Heap::FunctionObject { struct Q_QML_EXPORT QmlBindingWrapper : FunctionObject { V4_OBJECT2(QmlBindingWrapper, FunctionObject) - static ReturnedValue call(Managed *that, CallData *); + static ReturnedValue call(const Managed *that, CallData *callData); static void markObjects(Heap::Base *m, ExecutionEngine *e); - Heap::CallContext *context() const { return d()->qmlContext; } + Heap::QmlContext *context() const { return static_cast<Heap::QmlContext *>(d()->scope.ptr); } static Heap::FunctionObject *createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction, const QList<QByteArray> &signalParameters = QList<QByteArray>(), QString *error = 0); - -private: }; struct Q_QML_EXPORT Script { Script(ExecutionContext *scope, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0) : sourceFile(source), line(line), column(column), sourceCode(sourceCode) - , scope(scope->d()), strictMode(false), inheritContext(false), parsed(false) + , scope(scope), strictMode(false), inheritContext(false), parsed(false) , vmFunction(0), parseAsBinding(false) {} Script(ExecutionEngine *engine, Object *qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0) : sourceFile(source), line(line), column(column), sourceCode(sourceCode) @@ -125,8 +122,7 @@ struct Q_QML_EXPORT Script { int line; int column; QString sourceCode; - // ### GC - Heap::ExecutionContext *scope; + ExecutionContext *scope; bool strictMode; bool inheritContext; bool parsed; diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index f1f546bece..23bbcc60e1 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -175,7 +175,7 @@ template <> QUrl convertValueToElement(const Value &value) template <> QModelIndex convertValueToElement(const Value &value) { - const QQmlValueTypeWrapper *v = value_cast<QQmlValueTypeWrapper>(value); + const QQmlValueTypeWrapper *v = value.as<QQmlValueTypeWrapper>(); if (v) return v->toVariant().toModelIndex(); return QModelIndex(); @@ -183,7 +183,7 @@ template <> QModelIndex convertValueToElement(const Value &value) template <> QItemSelectionRange convertValueToElement(const Value &value) { - const QQmlValueTypeWrapper *v = value_cast<QQmlValueTypeWrapper>(value); + const QQmlValueTypeWrapper *v = value.as<QQmlValueTypeWrapper>(); if (v) return v->toVariant().value<QItemSelectionRange>(); return QItemSelectionRange(); @@ -231,7 +231,7 @@ public: defineAccessorProperty(QStringLiteral("length"), method_get_length, method_set_length); } - QV4::ReturnedValue containerGetIndexed(uint index, bool *hasProperty) + QV4::ReturnedValue containerGetIndexed(uint index, bool *hasProperty) const { /* Qt containers have int (rather than uint) allowable indexes. */ if (index > INT_MAX) { @@ -316,9 +316,9 @@ public: return (signedIdx < d()->container.count()) ? QV4::Attr_Data : QV4::Attr_Invalid; } - void containerAdvanceIterator(ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attrs) + void containerAdvanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs) { - *name = (Heap::String *)0; + name->setM(0); *index = UINT_MAX; if (d()->isReference) { @@ -400,7 +400,7 @@ public: ScopedCallData callData(scope, 2); callData->args[0] = convertElementToValue(this->m_ctx->d()->engine, lhs); callData->args[1] = convertElementToValue(this->m_ctx->d()->engine, rhs); - callData->thisObject = this->m_ctx->d()->engine->globalObject(); + callData->thisObject = this->m_ctx->d()->engine->globalObject; QV4::ScopedValue result(scope, compare->call(callData)); return result->toNumber() < 0; } @@ -419,7 +419,7 @@ public: } QV4::Scope scope(ctx); - if (ctx->argc() == 1 && ctx->args()[0].asFunctionObject()) { + if (ctx->argc() == 1 && ctx->args()[0].as<FunctionObject>()) { CompareFunctor cf(ctx, ctx->args()[0]); std::sort(d()->container.begin(), d()->container.end(), cf); } else { @@ -526,8 +526,8 @@ public: QMetaObject::metacall(d()->object, QMetaObject::WriteProperty, d()->propertyIndex, a); } - static QV4::ReturnedValue getIndexed(QV4::Managed *that, uint index, bool *hasProperty) - { return static_cast<QQmlSequence<Container> *>(that)->containerGetIndexed(index, hasProperty); } + static QV4::ReturnedValue getIndexed(const QV4::Managed *that, uint index, bool *hasProperty) + { return static_cast<const QQmlSequence<Container> *>(that)->containerGetIndexed(index, hasProperty); } static void putIndexed(Managed *that, uint index, const QV4::Value &value) { static_cast<QQmlSequence<Container> *>(that)->containerPutIndexed(index, value); } static QV4::PropertyAttributes queryIndexed(const QV4::Managed *that, uint index) @@ -536,7 +536,7 @@ public: { return static_cast<QQmlSequence<Container> *>(that)->containerDeleteIndexedProperty(index); } static bool isEqualTo(Managed *that, Managed *other) { return static_cast<QQmlSequence<Container> *>(that)->containerIsEqualTo(other); } - static void advanceIterator(Managed *that, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attrs) + static void advanceIterator(Managed *that, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs) { return static_cast<QQmlSequence<Container> *>(that)->containerAdvanceIterator(it, name, index, p, attrs); } }; @@ -544,7 +544,7 @@ public: template <typename Container> Heap::QQmlSequence<Container>::QQmlSequence(QV4::ExecutionEngine *engine, const Container &container) - : Heap::Object(engine->emptyClass, engine->sequencePrototype.asObject()) + : Heap::Object(engine->emptyClass, engine->sequencePrototype()) , container(container) , propertyIndex(-1) , isReference(false) @@ -557,7 +557,7 @@ Heap::QQmlSequence<Container>::QQmlSequence(QV4::ExecutionEngine *engine, const template <typename Container> Heap::QQmlSequence<Container>::QQmlSequence(QV4::ExecutionEngine *engine, QObject *object, int propertyIndex) - : Heap::Object(engine->emptyClass, engine->sequencePrototype.asObject()) + : Heap::Object(engine->emptyClass, engine->sequencePrototype()) , object(object) , propertyIndex(propertyIndex) , isReference(true) @@ -605,7 +605,7 @@ void SequencePrototype::init() { FOREACH_QML_SEQUENCE_TYPE(REGISTER_QML_SEQUENCE_METATYPE) defineDefaultProperty(QStringLiteral("sort"), method_sort, 1); - defineDefaultProperty(engine()->id_valueOf, method_valueOf, 0); + defineDefaultProperty(engine()->id_valueOf(), method_valueOf, 0); } #undef REGISTER_QML_SEQUENCE_METATYPE @@ -700,11 +700,11 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, int typeHint, boo { *succeeded = true; - if (!array.asArrayObject()) { + if (!array.as<ArrayObject>()) { *succeeded = false; return QVariant(); } - QV4::Scope scope(array.asObject()->engine()); + QV4::Scope scope(array.as<Object>()->engine()); QV4::ScopedArrayObject a(scope, array); FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_TO_VARIANT) { /* else */ *succeeded = false; return QVariant(); } @@ -717,7 +717,7 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, int typeHint, boo return qMetaTypeId<SequenceType>(); \ } else -int SequencePrototype::metaTypeForSequence(QV4::Object *object) +int SequencePrototype::metaTypeForSequence(const QV4::Object *object) { FOREACH_QML_SEQUENCE_TYPE(MAP_META_TYPE) /*else*/ { diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h index 9949278a89..560c3c27ca 100644 --- a/src/qml/jsruntime/qv4sequenceobject_p.h +++ b/src/qml/jsruntime/qv4sequenceobject_p.h @@ -48,9 +48,10 @@ #include <QtCore/qglobal.h> #include <QtCore/qvariant.h> -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #include "qv4object_p.h" #include "qv4context_p.h" +#include "qv4string_p.h" QT_BEGIN_NAMESPACE @@ -70,7 +71,7 @@ struct SequencePrototype : public QV4::Object static bool isSequenceType(int sequenceTypeId); static ReturnedValue newSequence(QV4::ExecutionEngine *engine, int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded); static ReturnedValue fromVariant(QV4::ExecutionEngine *engine, const QVariant& v, bool *succeeded); - static int metaTypeForSequence(Object *object); + static int metaTypeForSequence(const Object *object); static QVariant toVariant(Object *object); static QVariant toVariant(const Value &array, int typeHint, bool *succeeded); }; diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp index 31d85df13e..33b40796a4 100644 --- a/src/qml/jsruntime/qv4serialize.cpp +++ b/src/qml/jsruntime/qv4serialize.cpp @@ -37,7 +37,7 @@ #include <private/qqmllistmodel_p.h> #include <private/qqmllistmodelworkeragent_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4dateobject_p.h> #include <private/qv4regexpobject_p.h> #include <private/qv4sequenceobject_p.h> @@ -168,11 +168,11 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine char *buffer = data.data() + offset; memcpy(buffer, qstr.constData(), length*sizeof(QChar)); - } else if (v.asFunctionObject()) { + } else if (v.as<FunctionObject>()) { // XXX TODO: Implement passing function objects between the main and // worker scripts push(data, valueheader(WorkerUndefined)); - } else if (QV4::ArrayObject *array = v.asArrayObject()) { + } else if (const QV4::ArrayObject *array = v.as<ArrayObject>()) { uint length = array->getLength(); if (length > 0xFFFFFF) { push(data, valueheader(WorkerUndefined)); @@ -195,11 +195,11 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine reserve(data, sizeof(quint32) + sizeof(double)); push(data, valueheader(WorkerNumber)); push(data, v.asDouble()); - } else if (QV4::DateObject *d = v.asDateObject()) { + } else if (const QV4::DateObject *d = v.as<DateObject>()) { reserve(data, sizeof(quint32) + sizeof(double)); push(data, valueheader(WorkerDate)); - push(data, d->date().asDouble()); - } else if (RegExpObject *re = v.as<RegExpObject>()) { + push(data, d->date()); + } else if (const RegExpObject *re = v.as<RegExpObject>()) { quint32 flags = re->flags(); QString pattern = re->source(); int length = pattern.length() + 1; @@ -218,7 +218,7 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine char *buffer = data.data() + offset; memcpy(buffer, pattern.constData(), length*sizeof(QChar)); - } else if (QObjectWrapper *qobjectWrapper = v.as<QV4::QObjectWrapper>()) { + } else if (const QObjectWrapper *qobjectWrapper = v.as<QV4::QObjectWrapper>()) { // XXX TODO: Generalize passing objects between the main thread and worker scripts so // that others can trivially plug in their elements. QQmlListModel *lm = qobject_cast<QQmlListModel *>(qobjectWrapper->object()); @@ -231,10 +231,10 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine } // No other QObject's are allowed to be sent push(data, valueheader(WorkerUndefined)); - } else if (Object *o = v.asObject()) { + } else if (const Object *o = v.as<Object>()) { if (o->isListType()) { // valid sequence. we generate a length (sequence length + 1 for the sequence type) - uint seqLength = ScopedValue(scope, o->get(engine->id_length))->toUInt32(); + uint seqLength = ScopedValue(scope, o->get(engine->id_length()))->toUInt32(); uint length = seqLength + 1; if (length > 0xFFFFFF) { push(data, valueheader(WorkerUndefined)); @@ -265,7 +265,7 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine s = properties->getIndexed(ii); serialize(data, s, engine); - QV4::String *str = s->asString(); + QV4::String *str = s->as<String>(); val = o->get(str); if (scope.hasException()) scope.engine->catchException(); @@ -356,7 +356,7 @@ ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine) QVariant var = qVariantFromValue(ref); QV4::ScopedValue v(scope, scope.engine->fromVariant(var)); QV4::ScopedString s(scope, engine->newString(QStringLiteral("__qml:hidden:ref"))); - rv->asObject()->defineReadonlyProperty(s, v); + rv->as<Object>()->defineReadonlyProperty(s, v); agent->release(); agent->setEngine(engine); diff --git a/src/qml/jsruntime/qv4serialize_p.h b/src/qml/jsruntime/qv4serialize_p.h index 06eaffe4c4..d5d48edee7 100644 --- a/src/qml/jsruntime/qv4serialize_p.h +++ b/src/qml/jsruntime/qv4serialize_p.h @@ -46,7 +46,7 @@ // #include <QtCore/qbytearray.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4sparsearray_p.h b/src/qml/jsruntime/qv4sparsearray_p.h index 861c7dd28d..8496fc32e7 100644 --- a/src/qml/jsruntime/qv4sparsearray_p.h +++ b/src/qml/jsruntime/qv4sparsearray_p.h @@ -35,11 +35,7 @@ #define QV4SPARSEARRAY_H #include "qv4global_p.h" -#include <QtCore/qmap.h> -#include "qv4value_inl_p.h" -#include "qv4scopedvalue_p.h" -#include "qv4property_p.h" -#include <assert.h> +#include <QtCore/qlist.h> //#define Q_MAP_DEBUG #ifdef Q_MAP_DEBUG @@ -188,7 +184,7 @@ public: typedef qptrdiff difference_type; typedef int size_type; -#ifndef QT_NO_DEBUG +#ifdef Q_MAP_DEBUG void dump() const; #endif }; @@ -261,7 +257,7 @@ inline void SparseArray::push_back(uint index, uint len) n->value = index; } -#ifndef QT_NO_DEBUG +#ifdef Q_MAP_DEBUG inline void SparseArray::dump() const { const SparseArrayNode *it = begin(); @@ -344,4 +340,4 @@ inline SparseArrayNode *SparseArray::upperBound(uint akey) QT_END_NAMESPACE -#endif // QMAP_H +#endif diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index 6d55eb2c18..24a13ddd10 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include "qv4string_p.h" -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #ifndef V4_BOOTSTRAP #include "qv4identifiertable_p.h" #include "qv4runtime_p.h" @@ -110,7 +110,7 @@ bool String::isEqualTo(Managed *t, Managed *o) if (t == o) return true; - if (!o->d()->vtable->isString) + if (!o->d()->vtable()->isString) return false; return static_cast<String *>(t)->isEqualTo(static_cast<String *>(o)); diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index 1cf8f51a29..93a25d7ed5 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -188,6 +188,20 @@ public: static uint toArrayIndex(const QString &str); }; +template<> +inline const String *Value::as() const { + return isManaged() && m() && m()->vtable()->isString ? static_cast<const String *>(this) : 0; +} + +#ifndef V4_BOOTSTRAP +template<> +inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v) +{ + return v.toString(e)->asReturnedValue(); +} +#endif + + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index e0b84f6da3..9fbafa7ded 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -36,7 +36,7 @@ #include "qv4regexp_p.h" #include "qv4regexpobject_p.h" #include "qv4objectproto_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4scopedvalue_p.h" #include "qv4alloca_p.h" #include <QtCore/QDateTime> @@ -70,44 +70,45 @@ DEFINE_OBJECT_VTABLE(StringObject); Heap::StringObject::StringObject(InternalClass *ic, QV4::Object *prototype) : Heap::Object(ic, prototype) { - Q_ASSERT(vtable == QV4::StringObject::staticVTable()); - value = ic->engine->newString()->asReturnedValue(); - tmpProperty.value = Primitive::undefinedValue(); + Q_ASSERT(vtable() == QV4::StringObject::staticVTable()); + string = ic->engine->newString(); Scope scope(ic->engine); ScopedObject s(scope, this); - s->defineReadonlyProperty(ic->engine->id_length, Primitive::fromInt32(0)); + s->defineReadonlyProperty(ic->engine->id_length(), Primitive::fromInt32(0)); } -Heap::StringObject::StringObject(ExecutionEngine *engine, const Value &val) - : Heap::Object(engine->emptyClass, engine->stringPrototype.asObject()) +Heap::StringObject::StringObject(ExecutionEngine *engine, const QV4::String *str) + : Heap::Object(engine->emptyClass, engine->stringPrototype()) { - value = val; - Q_ASSERT(value.isString()); - tmpProperty.value = Primitive::undefinedValue(); + string = str->d(); Scope scope(engine); ScopedObject s(scope, this); - s->defineReadonlyProperty(engine->id_length, Primitive::fromUInt32(value.stringValue()->toQString().length())); + s->defineReadonlyProperty(engine->id_length(), Primitive::fromUInt32(length())); } -Property *Heap::StringObject::getIndex(uint index) const +Heap::String *Heap::StringObject::getIndex(uint index) const { - QString str = value.stringValue()->toQString(); + QString str = string->toQString(); if (index >= (uint)str.length()) return 0; - tmpProperty.value = Encode(internalClass->engine->newString(str.mid(index, 1))); - return &tmpProperty; + return internalClass->engine->newString(str.mid(index, 1)); +} + +uint Heap::StringObject::length() const +{ + return string->toQString().length(); } bool StringObject::deleteIndexedProperty(Managed *m, uint index) { ExecutionEngine *v4 = static_cast<StringObject *>(m)->engine(); Scope scope(v4); - Scoped<StringObject> o(scope, m->asStringObject()); + Scoped<StringObject> o(scope, m->as<StringObject>()); Q_ASSERT(!!o); - if (index < static_cast<uint>(o->d()->value.stringValue()->toQString().length())) { + if (index < static_cast<uint>(o->d()->string->toQString().length())) { if (v4->currentContext()->strictMode) v4->throwTypeError(); return false; @@ -115,20 +116,21 @@ bool StringObject::deleteIndexedProperty(Managed *m, uint index) return true; } -void StringObject::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attrs) +void StringObject::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs) { - *name = (Heap::String *)0; + name->setM(0); StringObject *s = static_cast<StringObject *>(m); - uint slen = s->d()->value.stringValue()->toQString().length(); + uint slen = s->d()->string->toQString().length(); if (it->arrayIndex <= slen) { while (it->arrayIndex < slen) { *index = it->arrayIndex; ++it->arrayIndex; PropertyAttributes a; - Property *pd = s->__getOwnProperty__(*index, &a); + Property pd; + s->getOwnProperty(*index, &a, &pd); if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { *attrs = a; - p->copy(pd, a); + p->copy(&pd, a); return; } } @@ -146,8 +148,7 @@ void StringObject::advanceIterator(Managed *m, ObjectIterator *it, Heap::String void StringObject::markObjects(Heap::Base *that, ExecutionEngine *e) { StringObject::Data *o = static_cast<StringObject::Data *>(that); - o->value.stringValue()->mark(e); - o->tmpProperty.value.mark(e); + o->string->mark(e); Object::markObjects(that, e); } @@ -158,11 +159,11 @@ Heap::StringCtor::StringCtor(QV4::ExecutionContext *scope) { } -ReturnedValue StringCtor::construct(Managed *m, CallData *callData) +ReturnedValue StringCtor::construct(const Managed *m, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(m)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(m)->engine(); Scope scope(v4); - ScopedValue value(scope); + ScopedString value(scope); if (callData->argc) value = callData->args[0].toString(v4); else @@ -170,9 +171,9 @@ ReturnedValue StringCtor::construct(Managed *m, CallData *callData) return Encode(v4->newStringObject(value)); } -ReturnedValue StringCtor::call(Managed *m, CallData *callData) +ReturnedValue StringCtor::call(const Managed *m, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(m)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(m)->engine(); Scope scope(v4); ScopedValue value(scope); if (callData->argc) @@ -187,13 +188,13 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor) Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); ctor->defineDefaultProperty(QStringLiteral("fromCharCode"), method_fromCharCode, 1); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString); - defineDefaultProperty(engine->id_valueOf, method_toString); // valueOf and toString are identical + defineDefaultProperty(engine->id_toString(), method_toString); + defineDefaultProperty(engine->id_valueOf(), method_toString); // valueOf and toString are identical defineDefaultProperty(QStringLiteral("charAt"), method_charAt, 1); defineDefaultProperty(QStringLiteral("charCodeAt"), method_charCodeAt, 1); defineDefaultProperty(QStringLiteral("concat"), method_concat, 1); @@ -220,8 +221,8 @@ static QString getThisString(ExecutionContext *ctx) ScopedValue t(scope, ctx->thisObject()); if (t->isString()) return t->stringValue()->toQString(); - if (StringObject *thisString = t->asStringObject()) - return thisString->d()->value.stringValue()->toQString(); + if (StringObject *thisString = t->as<StringObject>()) + return thisString->d()->string->toQString(); if (t->isUndefined() || t->isNull()) { scope.engine->throwTypeError(); return QString(); @@ -234,10 +235,10 @@ ReturnedValue StringPrototype::method_toString(CallContext *context) if (context->thisObject().isString()) return context->thisObject().asReturnedValue(); - StringObject *o = context->thisObject().asStringObject(); + StringObject *o = context->thisObject().as<StringObject>(); if (!o) return context->engine()->throwTypeError(); - return o->d()->value.asReturnedValue(); + return Encode(o->d()->string); } ReturnedValue StringPrototype::method_charAt(CallContext *context) @@ -368,7 +369,7 @@ ReturnedValue StringPrototype::method_match(CallContext *context) if (!rx) { ScopedCallData callData(scope, 1); callData->args[0] = regexp; - rx = context->d()->engine->regExpCtor.asFunctionObject()->construct(callData); + rx = context->d()->engine->regExpCtor()->construct(callData); } if (!rx) @@ -379,7 +380,7 @@ ReturnedValue StringPrototype::method_match(CallContext *context) // ### use the standard builtin function, not the one that might be redefined in the proto ScopedString execString(scope, scope.engine->newString(QStringLiteral("exec"))); - ScopedFunctionObject exec(scope, scope.engine->regExpPrototype.asObject()->get(execString)); + ScopedFunctionObject exec(scope, scope.engine->regExpPrototype()->get(execString)); ScopedCallData callData(scope, 1); callData->thisObject = rx; @@ -470,8 +471,8 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) { Scope scope(ctx); QString string; - if (StringObject *thisString = ctx->thisObject().asStringObject()) - string = thisString->d()->value.stringValue()->toQString(); + if (StringObject *thisString = ctx->thisObject().as<StringObject>()) + string = thisString->d()->string->toQString(); else string = ctx->thisObject().toQString(); @@ -481,12 +482,12 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) uint allocatedMatchOffsets = 64; uint _matchOffsets[64]; uint *matchOffsets = _matchOffsets; - uint nMatchOffsets = 0; ScopedValue searchValue(scope, ctx->argument(0)); Scoped<RegExpObject> regExp(scope, searchValue); if (regExp) { uint offset = 0; + uint nMatchOffsets = 0; // We extract the pointer here to work around a compiler bug on Android. Scoped<RegExp> re(scope, regExp->value()); @@ -519,7 +520,6 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) int idx = string.indexOf(searchString); if (idx != -1) { numStringMatches = 1; - nMatchOffsets = 2; matchOffsets[0] = idx; matchOffsets[1] = idx + searchString.length(); } @@ -593,7 +593,7 @@ ReturnedValue StringPrototype::method_search(CallContext *ctx) if (!regExp) { ScopedCallData callData(scope, 1); callData->args[0] = regExpValue; - regExpValue = ctx->d()->engine->regExpCtor.asFunctionObject()->construct(callData); + regExpValue = ctx->d()->engine->regExpCtor()->construct(callData); if (scope.engine->hasException) return Encode::undefined(); regExp = regExpValue->as<RegExpObject>(); diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index 459dc1322e..aa56a79bc3 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -45,12 +45,11 @@ namespace Heap { struct StringObject : Object { StringObject(InternalClass *ic, QV4::Object *prototype); - StringObject(ExecutionEngine *engine, const Value &value); - Value value; + StringObject(ExecutionEngine *engine, const QV4::String *string); + String *string; - Property *getIndex(uint index) const; - // ### get rid of tmpProperty - mutable Property tmpProperty; + Heap::String *getIndex(uint index) const; + uint length() const; }; struct StringCtor : FunctionObject { @@ -63,14 +62,17 @@ struct StringObject: Object { V4_OBJECT2(StringObject, Object) Q_MANAGED_TYPE(StringObject) - Property *getIndex(uint index) const { + Heap::String *getIndex(uint index) const { return d()->getIndex(index); } + uint length() const { + return d()->length(); + } static bool deleteIndexedProperty(Managed *m, uint index); protected: - static void advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attrs); + static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; @@ -78,8 +80,8 @@ struct StringCtor: FunctionObject { V4_OBJECT2(StringCtor, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct StringPrototype: StringObject diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 19e541dba8..f06eeb08b9 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -32,6 +32,7 @@ ****************************************************************************/ #include "qv4typedarray_p.h" #include "qv4arraybuffer_p.h" +#include "qv4string_p.h" #include <cmath> @@ -201,10 +202,10 @@ Heap::TypedArrayCtor::TypedArrayCtor(QV4::ExecutionContext *scope, TypedArray::T { } -ReturnedValue TypedArrayCtor::construct(Managed *m, CallData *callData) +ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<Object *>(m)->engine()); - Scoped<TypedArrayCtor> that(scope, static_cast<TypedArrayCtor *>(m)); + Scope scope(static_cast<const Object *>(m)->engine()); + Scoped<TypedArrayCtor> that(scope, static_cast<const TypedArrayCtor *>(m)); if (!callData->argc || !callData->args[0].isObject()) { // ECMA 6 22.2.1.1 @@ -257,7 +258,7 @@ ReturnedValue TypedArrayCtor::construct(Managed *m, CallData *callData) TypedArrayWrite write =array->d()->type->write; for (uint i = 0; i < l; ++i) { Primitive val; - val.val = read(src, i*srcElementSize); + val.setRawValue(read(src, i*srcElementSize)); write(scope.engine, dest, i*destElementSize, val); } } @@ -299,7 +300,7 @@ ReturnedValue TypedArrayCtor::construct(Managed *m, CallData *callData) // ECMA 6 22.2.1.3 ScopedObject o(scope, callData->argument(0)); - uint l = (uint) qBound(0., ScopedValue(scope, o->get(scope.engine->id_length))->toInteger(), (double)UINT_MAX); + uint l = (uint) qBound(0., ScopedValue(scope, o->get(scope.engine->id_length()))->toInteger(), (double)UINT_MAX); if (scope.engine->hasException) return scope.engine->throwTypeError(); @@ -329,13 +330,13 @@ ReturnedValue TypedArrayCtor::construct(Managed *m, CallData *callData) return array.asReturnedValue(); } -ReturnedValue TypedArrayCtor::call(Managed *that, CallData *callData) +ReturnedValue TypedArrayCtor::call(const Managed *that, CallData *callData) { return construct(that, callData); } Heap::TypedArray::TypedArray(ExecutionEngine *e, Type t) - : Heap::Object(e->emptyClass, e->typedArrayPrototype[t].asObject()), + : Heap::Object(e->emptyClass, e->typedArrayPrototype + t), type(operations + t), arrayType(t) { @@ -347,10 +348,10 @@ void TypedArray::markObjects(Heap::Base *that, ExecutionEngine *e) Object::markObjects(that, e); } -ReturnedValue TypedArray::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProperty) { - Scope scope(static_cast<Object *>(m)->engine()); - Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m)); + Scope scope(static_cast<const Object *>(m)->engine()); + Scoped<TypedArray> a(scope, static_cast<const TypedArray *>(m)); uint bytesPerElement = a->d()->type->bytesPerElement; uint byteOffset = a->d()->byteOffset + index * bytesPerElement; @@ -390,10 +391,10 @@ void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(3)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(3)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); ctor->defineReadonlyProperty(QStringLiteral("BYTES_PER_ELEMENT"), Primitive::fromInt32(operations[ctor->d()->type].bytesPerElement)); - defineDefaultProperty(engine->id_constructor, (o = ctor)); + defineDefaultProperty(engine->id_constructor(), (o = ctor)); defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, 0); defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, 0); @@ -470,7 +471,7 @@ ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx) if (scope.engine->hasException || !o) return scope.engine->throwTypeError(); - double len = ScopedValue(scope, o->get(scope.engine->id_length))->toNumber(); + double len = ScopedValue(scope, o->get(scope.engine->id_length()))->toNumber(); uint l = (uint)len; if (scope.engine->hasException || l != len) return scope.engine->throwTypeError(); @@ -523,7 +524,7 @@ ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx) TypedArrayWrite write = a->d()->type->write; for (uint i = 0; i < l; ++i) { Primitive val; - val.val = read(src, i*srcElementSize); + val.setRawValue(read(src, i*srcElementSize)); write(scope.engine, dest, i*elementSize, val); } @@ -563,7 +564,7 @@ ReturnedValue TypedArrayPrototype::method_subarray(CallContext *ctx) int newLen = end - begin; - ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor)); + ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor())); if (!constructor) return scope.engine->throwTypeError(); diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index afd1bb97e7..8e1090dcd2 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -72,7 +72,7 @@ struct TypedArray : Object { TypedArray(ExecutionEngine *e, Type t); const TypedArrayOperations *type; - ArrayBuffer *buffer; + Pointer<ArrayBuffer> buffer; uint byteLength; uint byteOffset; Type arrayType; @@ -113,7 +113,7 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object } static void markObjects(Heap::Base *that, ExecutionEngine *e); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); static void putIndexed(Managed *m, uint index, const Value &value); }; @@ -121,8 +121,8 @@ struct TypedArrayCtor: FunctionObject { V4_OBJECT2(TypedArrayCtor, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index 68228f06bb..4c81199a07 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -32,10 +32,11 @@ ****************************************************************************/ #include <qv4engine_p.h> #include <qv4runtime_p.h> +#include <qv4string_p.h> #ifndef V4_BOOTSTRAP #include <qv4object_p.h> #include <qv4objectproto_p.h> -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #endif #include <wtf/MathExtras.h> @@ -68,10 +69,32 @@ int Value::toUInt16() const return (unsigned short)number; } +bool Value::toBoolean() const +{ + switch (type()) { + case Value::Undefined_Type: + case Value::Null_Type: + return false; + case Value::Boolean_Type: + case Value::Integer_Type: + return (bool)int_32(); + case Value::Managed_Type: +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); +#else + if (isString()) + return stringValue()->toQString().length() > 0; +#endif + return true; + default: // double + return doubleValue() && !std::isnan(doubleValue()); + } +} + double Value::toInteger() const { if (integerCompatible()) - return int_32; + return int_32(); return Primitive::toInteger(toNumber()); } @@ -87,10 +110,10 @@ double Value::toNumberImpl() const #else if (isString()) return RuntimeHelpers::stringToNumber(stringValue()->toQString()); - { - Q_ASSERT(isObject()); - Scope scope(objectValue()->engine()); - ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, NUMBER_HINT)); + { + Q_ASSERT(isObject()); + Scope scope(objectValue()->engine()); + ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, NUMBER_HINT)); if (scope.engine->hasException) return 0; return prim->toNumber(); @@ -99,7 +122,7 @@ double Value::toNumberImpl() const case QV4::Value::Null_Type: case QV4::Value::Boolean_Type: case QV4::Value::Integer_Type: - return int_32; + return int_32(); default: // double Q_UNREACHABLE(); } @@ -148,7 +171,7 @@ QString Value::toQStringNoThrow() const } case Value::Integer_Type: { QString str; - RuntimeHelpers::numberToString(&str, (double)int_32, 10); + RuntimeHelpers::numberToString(&str, (double)int_32(), 10); return str; } default: { // double @@ -184,7 +207,7 @@ QString Value::toQString() const } case Value::Integer_Type: { QString str; - RuntimeHelpers::numberToString(&str, (double)int_32, 10); + RuntimeHelpers::numberToString(&str, (double)int_32(), 10); return str; } default: { // double @@ -197,14 +220,14 @@ QString Value::toQString() const #endif // V4_BOOTSTRAP bool Value::sameValue(Value other) const { - if (val == other.val) + if (_val == other._val) return true; if (isString() && other.isString()) return stringValue()->isEqualTo(other.stringValue()); if (isInteger() && other.isDouble()) - return int_32 ? (double(int_32) == other.doubleValue()) : (other.val == 0); + return int_32() ? (double(int_32()) == other.doubleValue()) : (other._val == 0); if (isDouble() && other.isInteger()) - return other.int_32 ? (doubleValue() == double(other.int_32)) : (val == 0); + return other.int_32() ? (doubleValue() == double(other.int_32())) : (_val == 0); return false; } @@ -281,4 +304,35 @@ Heap::Object *Value::toObject(ExecutionEngine *e) const return RuntimeHelpers::convertToObject(e, *this); } +uint Value::asArrayLength(bool *ok) const +{ + *ok = true; + if (isInteger()) { + if (int_32() >= 0) { + return (uint)int_32(); + } else { + *ok = false; + return UINT_MAX; + } + } + if (isNumber()) { + double d = doubleValue(); + uint idx = (uint)d; + if (idx != d) { + *ok = false; + return UINT_MAX; + } + return idx; + } + if (isString()) + return stringValue()->toUInt(ok); + + uint idx = toUInt32(); + double d = toNumber(); + if (d != idx) { + *ok = false; + return UINT_MAX; + } + return idx; +} #endif // V4_BOOTSTRAP diff --git a/src/qml/jsruntime/qv4value_inl_p.h b/src/qml/jsruntime/qv4value_inl_p.h deleted file mode 100644 index f3026900d6..0000000000 --- a/src/qml/jsruntime/qv4value_inl_p.h +++ /dev/null @@ -1,293 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#ifndef QV4VALUE_INL_H -#define QV4VALUE_INL_H - -#include <cmath> // this HAS to come - -#include "qv4value_p.h" - -#include "qv4string_p.h" -#include "qv4managed_p.h" -#include "qv4engine_p.h" - -QT_BEGIN_NAMESPACE - -namespace QV4 { - -inline bool Value::isString() const -{ - if (!isManaged()) - return false; - return m && m->vtable->isString; -} -inline bool Value::isObject() const -{ - if (!isManaged()) - return false; - return m && m->vtable->isObject; -} - -inline bool Value::isPrimitive() const -{ - return !isObject(); -} - -inline String *Value::asString() const -{ - if (isString()) - return stringValue(); - return 0; -} - -inline void Value::mark(ExecutionEngine *e) const -{ - if (!val) - return; - Managed *m = asManaged(); - if (m) - m->mark(e); -} - -inline Primitive Primitive::nullValue() -{ - Primitive v; -#ifdef QV4_USE_64_BIT_VALUE_ENCODING - v.val = quint64(_Null_Type) << Tag_Shift; -#else - v.tag = _Null_Type; - v.int_32 = 0; -#endif - return v; -} - -inline Primitive Primitive::fromBoolean(bool b) -{ - Primitive v; - v.tag = _Boolean_Type; - v.int_32 = (bool)b; - return v; -} - -inline Primitive Primitive::fromDouble(double d) -{ - Primitive v; - v.setDouble(d); - return v; -} - -inline Primitive Primitive::fromInt32(int i) -{ - Primitive v; - v.tag = _Integer_Type; - v.int_32 = i; - return v; -} - -inline Primitive Primitive::fromUInt32(uint i) -{ - Primitive v; - if (i < INT_MAX) { - v.tag = _Integer_Type; - v.int_32 = (int)i; - } else { - v.setDouble(i); - } - return v; -} - -inline double Value::toNumber() const -{ - if (isInteger()) - return int_32; - if (isDouble()) - return doubleValue(); - return toNumberImpl(); -} - -inline int Value::toInt32() const -{ - if (isInteger()) - return int_32; - double d = isNumber() ? doubleValue() : toNumberImpl(); - - const double D32 = 4294967296.0; - const double D31 = D32 / 2.0; - - if ((d >= -D31 && d < D31)) - return static_cast<int>(d); - - return Primitive::toInt32(d); -} - -inline unsigned int Value::toUInt32() const -{ - return (unsigned int)toInt32(); -} - - -inline bool Value::toBoolean() const -{ - switch (type()) { - case Value::Undefined_Type: - case Value::Null_Type: - return false; - case Value::Boolean_Type: - case Value::Integer_Type: - return (bool)int_32; - case Value::Managed_Type: -#ifdef V4_BOOTSTRAP - Q_UNIMPLEMENTED(); -#else - if (isString()) - return stringValue()->toQString().length() > 0; -#endif - return true; - default: // double - return doubleValue() && !std::isnan(doubleValue()); - } -} - -#ifndef V4_BOOTSTRAP -inline uint Value::asArrayIndex() const -{ -#ifdef QV4_USE_64_BIT_VALUE_ENCODING - if (!isNumber()) - return UINT_MAX; - if (isInteger()) - return int_32 >= 0 ? (uint)int_32 : UINT_MAX; -#else - if (isInteger() && int_32 >= 0) - return (uint)int_32; - if (!isDouble()) - return UINT_MAX; -#endif - double d = doubleValue(); - uint idx = (uint)d; - if (idx != d) - return UINT_MAX; - return idx; -} - -inline uint Value::asArrayLength(bool *ok) const -{ - *ok = true; - if (isInteger()) { - if (int_32 >= 0) { - return (uint)int_32; - } else { - *ok = false; - return UINT_MAX; - } - } - if (isNumber()) { - double d = doubleValue(); - uint idx = (uint)d; - if (idx != d) { - *ok = false; - return UINT_MAX; - } - return idx; - } - if (isString()) - return stringValue()->toUInt(ok); - - uint idx = toUInt32(); - double d = toNumber(); - if (d != idx) { - *ok = false; - return UINT_MAX; - } - return idx; -} - -inline Object *Value::asObject() const -{ - return isObject() ? objectValue() : 0; -} - -inline FunctionObject *Value::asFunctionObject() const -{ - return isObject() ? managed()->asFunctionObject() : 0; -} - -inline NumberObject *Value::asNumberObject() const -{ - return isObject() ? managed()->asNumberObject() : 0; -} - -inline StringObject *Value::asStringObject() const -{ - return isObject() ? managed()->asStringObject() : 0; -} - -inline DateObject *Value::asDateObject() const -{ - return isObject() ? managed()->asDateObject() : 0; -} - -inline ArrayObject *Value::asArrayObject() const -{ - return isObject() ? managed()->asArrayObject() : 0; -} - -inline ErrorObject *Value::asErrorObject() const -{ - return isObject() ? managed()->asErrorObject() : 0; -} - -template<typename T> -inline T *Value::as() const { Managed *m = isObject() ? managed() : 0; return m ? m->as<T>() : 0; } - -#ifndef V4_BOOTSTRAP - -template<> -inline String *value_cast(const Value &v) { - return v.asString(); -} - -template<> -inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v) -{ - return v.toString(e)->asReturnedValue(); -} - -#endif - -#endif - -} // namespace QV4 - -QT_END_NAMESPACE - -#endif diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 628950784a..6305e6dfbb 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -37,6 +37,7 @@ #include <QtCore/QString> #include "qv4global_p.h" +#include <private/qv4heap_p.h> /* We cannot rely on QT_POINTER_SIZE to be set correctly on host builds. In qmldevtools the Value objects are only used to store primitives, never object pointers. So we can use the 64-bit encoding. */ @@ -50,56 +51,12 @@ QT_BEGIN_NAMESPACE namespace QV4 { -typedef uint Bool; - namespace Heap { - -struct Q_QML_EXPORT Base { - union { - const ManagedVTable *vtable; - quintptr mm_data; - }; - - inline ReturnedValue asReturnedValue() const; - inline void mark(QV4::ExecutionEngine *engine); - - enum { - MarkBit = 0x1, - NotInUse = 0x2, - PointerMask = ~0x3 - }; - - ManagedVTable *gcGetVtable() const { - return reinterpret_cast<ManagedVTable *>(mm_data & PointerMask); - } - inline bool isMarked() const { - return mm_data & MarkBit; - } - inline void setMarkBit() { - mm_data |= MarkBit; - } - inline void clearMarkBit() { - mm_data &= ~MarkBit; - } - - inline bool inUse() const { - return !(mm_data & NotInUse); - } - - Base *nextFree() { - return reinterpret_cast<Base *>(mm_data & PointerMask); - } - void setNextFree(Base *m) { - mm_data = (reinterpret_cast<quintptr>(m) | NotInUse); - } - - void *operator new(size_t, Managed *m) { return m; } - void *operator new(size_t, Heap::Base *m) { return m; } - void operator delete(void *, Heap::Base *) {} -}; - + struct Base; } +typedef uint Bool; + struct Q_QML_PRIVATE_EXPORT Value { /* @@ -124,30 +81,38 @@ struct Q_QML_PRIVATE_EXPORT Value Bit 15-17 is then used to encode other immediates. */ + quint64 _val; + + Q_ALWAYS_INLINE quint64 val() const { return _val; } + Q_ALWAYS_INLINE void setVal(quint64 v) { _val = v; } + Q_ALWAYS_INLINE void setValue(quint32 v) { setTagValue(tag(), v); } + Q_ALWAYS_INLINE void setTag(quint32 t) { setTagValue(t, value()); } - union { - quint64 val; -#ifdef QV4_USE_64_BIT_VALUE_ENCODING - Heap::Base *m; -#else - double dbl; -#endif - struct { -#if Q_BYTE_ORDER != Q_LITTLE_ENDIAN - uint tag; -#endif - union { - uint uint_32; - int int_32; -#ifndef QV4_USE_64_BIT_VALUE_ENCODING - Heap::Base *m; -#endif - }; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - uint tag; + static inline int valueOffset() { return 0; } + static inline int tagOffset() { return 4; } + 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; } +#else // !Q_LITTLE_ENDIAN + static inline int valueOffset() { return 4; } + static inline int tagOffset() { return 0; } + Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(value) << 32 | tag; } + Q_ALWAYS_INLINE quint32 tag() const { return _val & quint64(~quint32(0)); } + Q_ALWAYS_INLINE quint32 value() const { return _val >> 32; } #endif - }; - }; + +#ifdef QV4_USE_64_BIT_VALUE_ENCODING + Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; memcpy(&b, &_val, 8); return b; } + Q_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 { Heap::Base *b; quint32 v = value(); memcpy(&b, &v, 4); return b; } + Q_ALWAYS_INLINE void setM(Heap::Base *b) { quint32 v; memcpy(&v, &b, 4); setValue(v); } +#endif + + Q_ALWAYS_INLINE int int_32() const { int i; quint32 v = value(); memcpy(&i, &v, 4); return i; } + Q_ALWAYS_INLINE void setInt_32(int i) { quint32 u; memcpy(&u, &i, 4); setValue(u); } + Q_ALWAYS_INLINE uint uint_32() const { return value(); } #ifndef QV4_USE_64_BIT_VALUE_ENCODING enum Masks { @@ -220,127 +185,127 @@ struct Q_QML_PRIVATE_EXPORT Value #endif inline unsigned type() const { - return tag & Type_Mask; + return tag() & Type_Mask; } // used internally in property - inline bool isEmpty() const { return tag == Empty_Type; } + inline bool isEmpty() const { return tag() == Empty_Type; } - inline bool isUndefined() const { return tag == Undefined_Type; } - inline bool isNull() const { return tag == _Null_Type; } - inline bool isBoolean() const { return tag == _Boolean_Type; } + inline bool isUndefined() const { return tag() == Undefined_Type; } + inline bool isNull() const { return tag() == _Null_Type; } + inline bool isBoolean() const { return tag ()== _Boolean_Type; } #ifdef QV4_USE_64_BIT_VALUE_ENCODING - inline bool isInteger() const { return (val >> IsNumber_Shift) == 1; } - inline bool isDouble() const { return (val >> IsDouble_Shift); } - inline bool isNumber() const { return (val >> IsNumber_Shift); } - inline bool isManaged() const { return !(val >> IsManaged_Shift); } - inline bool isNullOrUndefined() const { return ((val >> IsManaged_Shift) & ~2) == 1; } - inline bool integerCompatible() const { return ((val >> IsConvertibleToInt_Shift) & ~2) == 1; } + inline bool isInteger() const { return (_val >> IsNumber_Shift) == 1; } + inline bool isDouble() const { return (_val >> IsDouble_Shift); } + inline bool isNumber() const { return (_val >> IsNumber_Shift); } + inline bool isManaged() const { return !(_val >> IsManaged_Shift); } + inline bool isNullOrUndefined() const { return ((_val >> IsManaged_Shift) & ~2) == 1; } + inline bool integerCompatible() const { return ((_val >> IsConvertibleToInt_Shift) & ~2) == 1; } static inline bool integerCompatible(Value a, Value b) { return a.integerCompatible() && b.integerCompatible(); } static inline bool bothDouble(Value a, Value b) { return a.isDouble() && b.isDouble(); } - double doubleValue() const { - Q_ASSERT(isDouble()); - union { - quint64 i; - double d; - } v; - v.i = val ^ NaNEncodeMask; - return v.d; - } - void setDouble(double d) { - union { - quint64 i; - double d; - } v; - v.d = d; - val = v.i ^ NaNEncodeMask; - Q_ASSERT(isDouble()); - } - inline bool isNaN() const { return (tag & 0x7fff8000) == 0x00078000; } + inline bool isNaN() const { return (tag() & 0x7fff8000) == 0x00078000; } #else - inline bool isInteger() const { return tag == _Integer_Type; } - inline bool isDouble() const { return (tag & NotDouble_Mask) != NotDouble_Mask; } - inline bool isNumber() const { return tag == _Integer_Type || (tag & NotDouble_Mask) != NotDouble_Mask; } - inline bool isManaged() const { return tag == Managed_Type; } - inline bool isNullOrUndefined() const { return (tag & IsNullOrUndefined_Mask) == Undefined_Type; } - inline bool integerCompatible() const { return (tag & ConvertibleToInt) == ConvertibleToInt; } + inline bool isInteger() const { return tag() == _Integer_Type; } + inline bool isDouble() const { return (tag() & NotDouble_Mask) != NotDouble_Mask; } + inline bool isNumber() const { return tag() == _Integer_Type || (tag() & NotDouble_Mask) != NotDouble_Mask; } + inline bool isManaged() const { return tag() == Managed_Type; } + inline bool isNullOrUndefined() const { return (tag() & IsNullOrUndefined_Mask) == Undefined_Type; } + inline bool integerCompatible() const { return (tag() & ConvertibleToInt) == ConvertibleToInt; } static inline bool integerCompatible(Value a, Value b) { - return ((a.tag & b.tag) & ConvertibleToInt) == ConvertibleToInt; + return ((a.tag() & b.tag()) & ConvertibleToInt) == ConvertibleToInt; } static inline bool bothDouble(Value a, Value b) { - return ((a.tag | b.tag) & NotDouble_Mask) != NotDouble_Mask; + return ((a.tag() | b.tag()) & NotDouble_Mask) != NotDouble_Mask; } - double doubleValue() const { Q_ASSERT(isDouble()); return dbl; } - void setDouble(double d) { dbl = d; Q_ASSERT(isDouble()); } - inline bool isNaN() const { return (tag & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; } + inline bool isNaN() const { return (tag() & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; } #endif + Q_ALWAYS_INLINE double doubleValue() const { + Q_ASSERT(isDouble()); + double d; + quint64 v = _val; +#ifdef QV4_USE_64_BIT_VALUE_ENCODING + v ^= NaNEncodeMask; +#endif + memcpy(&d, &v, 8); + return d; + } + Q_ALWAYS_INLINE void setDouble(double d) { + memcpy(&_val, &d, 8); +#ifdef QV4_USE_64_BIT_VALUE_ENCODING + _val ^= NaNEncodeMask; +#endif + Q_ASSERT(isDouble()); + } inline bool isString() const; inline bool isObject() const; inline bool isInt32() { - if (tag == _Integer_Type) + if (tag() == _Integer_Type) return true; if (isDouble()) { double d = doubleValue(); int i = (int)d; if (i == d) { - int_32 = i; - tag = _Integer_Type; + setInt_32(i); + setTag(_Integer_Type); return true; } } return false; } double asDouble() const { - if (tag == _Integer_Type) - return int_32; + if (tag() == _Integer_Type) + return int_32(); return doubleValue(); } bool booleanValue() const { - return int_32; + return int_32(); } int integerValue() const { - return int_32; + return int_32(); } - String *stringValue() const { - return m ? reinterpret_cast<String*>(const_cast<Value *>(this)) : 0; + Q_ALWAYS_INLINE String *stringValue() const { + return m() ? reinterpret_cast<String*>(const_cast<Value *>(this)) : 0; } - Object *objectValue() const { - return m ? reinterpret_cast<Object*>(const_cast<Value *>(this)) : 0; + Q_ALWAYS_INLINE Object *objectValue() const { + return m() ? reinterpret_cast<Object*>(const_cast<Value *>(this)) : 0; } - Managed *managed() const { - return m ? reinterpret_cast<Managed*>(const_cast<Value *>(this)) : 0; + Q_ALWAYS_INLINE Managed *managed() const { + return m() ? reinterpret_cast<Managed*>(const_cast<Value *>(this)) : 0; } - Heap::Base *heapObject() const { - return m; + Q_ALWAYS_INLINE Heap::Base *heapObject() const { + return m(); } - quint64 rawValue() const { - return val; + Q_ALWAYS_INLINE quint64 &rawValueRef() { + return _val; + } + Q_ALWAYS_INLINE quint64 rawValue() const { + return _val; } + Q_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; } static inline Value fromHeapObject(Heap::Base *m) { Value v; - v.m = m; + v.setRawValue(0); + v.setM(m); #ifndef QV4_USE_64_BIT_VALUE_ENCODING - v.tag = Managed_Type; + v.setTag(Managed_Type); #endif return v; } - static inline Value fromManaged(Managed *m); - int toUInt16() const; inline int toInt32() const; inline unsigned int toUInt32() const; - inline bool toBoolean() const; + bool toBoolean() const; double toInteger() const; inline double toNumber() const; double toNumberImpl() const; @@ -353,21 +318,32 @@ struct Q_QML_PRIVATE_EXPORT Value inline bool tryIntegerConversion() { bool b = integerCompatible(); if (b) - tag = _Integer_Type; + setTag(_Integer_Type); return b; } - inline String *asString() const; - inline Managed *asManaged() const; - inline Object *asObject() const; - inline FunctionObject *asFunctionObject() const; - inline NumberObject *asNumberObject() const; - inline StringObject *asStringObject() const; - inline DateObject *asDateObject() const; - inline ArrayObject *asArrayObject() const; - inline ErrorObject *asErrorObject() const; + template <typename T> + const T *as() const { + if (!m() || !isManaged()) + return 0; + + Q_ASSERT(m()->vtable()); +#if !defined(QT_NO_QOBJECT_CHECK) + static_cast<const T *>(this)->qt_check_for_QMANAGED_macro(static_cast<const T *>(this)); +#endif + const VTable *vt = m()->vtable(); + while (vt) { + if (vt == T::staticVTable()) + return static_cast<const T *>(this); + vt = vt->parent; + } + return 0; + } + template <typename T> + T *as() { + return const_cast<T *>(const_cast<const Value *>(this)->as<T>()); + } - template<typename T> inline T *as() const; template<typename T> inline T *cast() { return static_cast<T *>(managed()); } @@ -376,26 +352,32 @@ struct Q_QML_PRIVATE_EXPORT Value } inline uint asArrayIndex() const; - inline uint asArrayLength(bool *ok) const; +#ifndef V4_BOOTSTRAP + uint asArrayLength(bool *ok) const; +#endif - ReturnedValue asReturnedValue() const { return val; } - static Value fromReturnedValue(ReturnedValue val) { Value v; v.val = val; return v; } + ReturnedValue asReturnedValue() const { return _val; } + static Value fromReturnedValue(ReturnedValue val) { Value v; v._val = val; return v; } // Section 9.12 bool sameValue(Value other) const; - inline void mark(ExecutionEngine *e) const; + inline void mark(ExecutionEngine *e); Value &operator =(const ScopedValue &v); - Value &operator=(ReturnedValue v) { val = v; return *this; } + Value &operator=(ReturnedValue v) { _val = v; return *this; } Value &operator=(Managed *m) { - val = Value::fromManaged(m).val; + if (!m) { + setTagValue(Undefined_Type, 0); + } else { + _val = reinterpret_cast<Value *>(m)->_val; + } return *this; } Value &operator=(Heap::Base *o) { - m = o; + setM(o); #ifndef QV4_USE_64_BIT_VALUE_ENCODING - tag = Managed_Type; + setTag(Managed_Type); #endif return *this; } @@ -403,17 +385,68 @@ struct Q_QML_PRIVATE_EXPORT Value template<typename T> Value &operator=(const Scoped<T> &t); Value &operator=(const Value &v) { - val = v.val; + _val = v._val; return *this; } }; -inline Managed *Value::asManaged() const +inline bool Value::isString() const +{ + if (!isManaged()) + return false; + return m() && m()->vtable()->isString; +} +inline bool Value::isObject() const +{ + if (!isManaged()) + return false; + return m() && m()->vtable()->isObject; +} + +inline bool Value::isPrimitive() const +{ + return !isObject(); +} + +inline double Value::toNumber() const +{ + if (isInteger()) + return int_32(); + if (isDouble()) + return doubleValue(); + return toNumberImpl(); +} + + +#ifndef V4_BOOTSTRAP +inline uint Value::asArrayIndex() const { - if (isManaged()) - return managed(); - return 0; +#ifdef QV4_USE_64_BIT_VALUE_ENCODING + if (!isNumber()) + return UINT_MAX; + if (isInteger()) + return int_32() >= 0 ? (uint)int_32() : UINT_MAX; +#else + if (isInteger() && int_32() >= 0) + return (uint)int_32(); + if (!isDouble()) + return UINT_MAX; +#endif + double d = doubleValue(); + uint idx = (uint)d; + if (idx != d) + return UINT_MAX; + return idx; } +#endif + +inline +ReturnedValue Heap::Base::asReturnedValue() const +{ + return Value::fromHeapObject(const_cast<Heap::Base *>(this)).asReturnedValue(); +} + + struct Q_QML_PRIVATE_EXPORT Primitive : public Value { @@ -437,10 +470,11 @@ inline Primitive Primitive::undefinedValue() { Primitive v; #ifdef QV4_USE_64_BIT_VALUE_ENCODING - v.val = quint64(Undefined_Type) << Tag_Shift; + v.setRawValue(quint64(Undefined_Type) << Tag_Shift); #else - v.tag = Undefined_Type; - v.int_32 = 0; + v.setRawValue(0); + v.setTag(Undefined_Type); + v.setValue(0); #endif return v; } @@ -448,39 +482,54 @@ inline Primitive Primitive::undefinedValue() inline Primitive Primitive::emptyValue() { Primitive v; - v.tag = Value::Empty_Type; - v.uint_32 = 0; + v.setTagValue(Value::Empty_Type, 0); return v; } -template <typename T> -struct TypedValue : public Value +inline Primitive Primitive::nullValue() { - template<typename X> - TypedValue &operator =(X *x) { - m = x; + Primitive v; #ifndef QV4_USE_64_BIT_VALUE_ENCODING - tag = Managed_Type; + v.setRawValue(quint64(_Null_Type) << Tag_Shift); +#else + v.setTagValue(_Null_Type, 0); #endif - return *this; - } - TypedValue &operator =(T *t); - TypedValue &operator =(const Scoped<T> &v); -// TypedValue &operator =(const ManagedRef<T> &v); - - TypedValue &operator =(const TypedValue<T> &t); + return v; +} - bool operator!() const { return !managed(); } +inline Primitive Primitive::fromBoolean(bool b) +{ + Primitive v; + v.setTagValue(_Boolean_Type, b); + return v; +} - operator T *() { return static_cast<T *>(managed()); } - T *operator->() { return static_cast<T *>(managed()); } - const T *operator->() const { return static_cast<T *>(managed()); } - T *getPointer() const { return static_cast<T *>(managed()); } +inline Primitive Primitive::fromDouble(double d) +{ + Primitive v; + v.setDouble(d); + return v; +} - void mark(ExecutionEngine *e) { if (managed()) managed()->mark(e); } -}; -typedef TypedValue<String> StringValue; +inline Primitive Primitive::fromInt32(int i) +{ + Primitive v; + v.setTagValue(_Integer_Type, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors. + v.setInt_32(i); + return v; +} +inline Primitive Primitive::fromUInt32(uint i) +{ + Primitive v; + if (i < INT_MAX) { + v.setTagValue(_Integer_Type, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors. + v.setInt_32((int)i); + } else { + v.setDouble(i); + } + return v; +} struct Encode { static ReturnedValue undefined() { @@ -496,7 +545,7 @@ struct Encode { Encode(double d) { Value v; v.setDouble(d); - val = v.val; + val = v.rawValue(); } Encode(int i) { val = (quint64(Value::_Integer_Type) << Value::Tag_Shift) | (uint)i; @@ -507,7 +556,7 @@ struct Encode { } else { Value v; v.setDouble(i); - val = v.val; + val = v.rawValue(); } } Encode(ReturnedValue v) { @@ -527,21 +576,29 @@ private: Encode(void *); }; -inline -ReturnedValue Heap::Base::asReturnedValue() const +template<typename T> +ReturnedValue value_convert(ExecutionEngine *e, const Value &v); + +inline int Value::toInt32() const { - return Value::fromHeapObject(const_cast<Heap::Base *>(this)).asReturnedValue(); -} + if (isInteger()) + return int_32(); + double d = isNumber() ? doubleValue() : toNumberImpl(); + const double D32 = 4294967296.0; + const double D31 = D32 / 2.0; -template<typename T> -T *value_cast(const Value &v) + if ((d >= -D31 && d < D31)) + return static_cast<int>(d); + + return Primitive::toInt32(d); +} + +inline unsigned int Value::toUInt32() const { - return v.as<T>(); + return (unsigned int)toInt32(); } -template<typename T> -ReturnedValue value_convert(ExecutionEngine *e, const Value &v); } diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp index 966f83acef..f9e26efe71 100644 --- a/src/qml/jsruntime/qv4variantobject.cpp +++ b/src/qml/jsruntime/qv4variantobject.cpp @@ -44,7 +44,7 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(VariantObject); Heap::VariantObject::VariantObject(QV4::ExecutionEngine *engine, const QVariant &value) - : Heap::Object(engine->emptyClass, engine->variantPrototype.asObject()) + : Heap::Object(engine->emptyClass, engine->variantPrototype()) { data = value; if (isScarce()) @@ -96,8 +96,8 @@ void VariantPrototype::init() { defineDefaultProperty(QStringLiteral("preserve"), method_preserve, 0); defineDefaultProperty(QStringLiteral("destroy"), method_destroy, 0); - defineDefaultProperty(engine()->id_valueOf, method_valueOf, 0); - defineDefaultProperty(engine()->id_toString, method_toString, 0); + defineDefaultProperty(engine()->id_valueOf(), method_valueOf, 0); + defineDefaultProperty(engine()->id_toString(), method_toString, 0); } QV4::ReturnedValue VariantPrototype::method_preserve(CallContext *ctx) @@ -129,7 +129,7 @@ QV4::ReturnedValue VariantPrototype::method_toString(CallContext *ctx) return Encode::undefined(); QString result = o->d()->data.toString(); if (result.isEmpty() && !o->d()->data.canConvert(QVariant::String)) - result = QString::fromLatin1("QVariant(%0)").arg(QString::fromLatin1(o->d()->data.typeName())); + result = QStringLiteral("QVariant(%0)").arg(QString::fromLatin1(o->d()->data.typeName())); return Encode(ctx->d()->engine->newString(result)); } diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h index 2b48412c4d..b19f12bb98 100644 --- a/src/qml/jsruntime/qv4variantobject_p.h +++ b/src/qml/jsruntime/qv4variantobject_p.h @@ -49,7 +49,7 @@ #include <QtQml/qqmllist.h> #include <QtCore/qvariant.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 390bbf5ee3..0edd7378a7 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -37,13 +37,14 @@ #include <QtCore/qjsondocument.h> #include <QtCore/qjsonobject.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4debugging_p.h> #include <private/qv4function_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4math_p.h> #include <private/qv4scopedvalue_p.h> #include <private/qv4lookup_p.h> +#include <private/qv4string_p.h> #include <iostream> #include "qv4alloca_p.h" @@ -512,6 +513,28 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code STOREVALUE(instr.result, Runtime::getQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired)); MOTH_END_INSTR(LoadQObjectProperty) + MOTH_BEGIN_INSTR(StoreScopeObjectProperty) + Runtime::setQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source)); + CHECK_EXCEPTION; + MOTH_END_INSTR(StoreScopeObjectProperty) + + MOTH_BEGIN_INSTR(LoadScopeObjectProperty) + STOREVALUE(instr.result, Runtime::getQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex)); + MOTH_END_INSTR(LoadScopeObjectProperty) + + MOTH_BEGIN_INSTR(StoreContextObjectProperty) + Runtime::setQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source)); + CHECK_EXCEPTION; + MOTH_END_INSTR(StoreContextObjectProperty) + + MOTH_BEGIN_INSTR(LoadContextObjectProperty) + STOREVALUE(instr.result, Runtime::getQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex)); + MOTH_END_INSTR(LoadContextObjectProperty) + + MOTH_BEGIN_INSTR(LoadIdObject) + STOREVALUE(instr.result, Runtime::getQmlIdObject(engine, VALUE(instr.base), instr.index)); + MOTH_END_INSTR(LoadIdObject) + MOTH_BEGIN_INSTR(LoadAttachedQObjectProperty) STOREVALUE(instr.result, Runtime::getQmlAttachedProperty(engine, instr.attachedPropertiesId, instr.propertyIndex)); MOTH_END_INSTR(LoadAttachedQObjectProperty) @@ -565,6 +588,26 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code STOREVALUE(instr.result, Runtime::callPropertyLookup(engine, instr.lookupIndex, callData)); MOTH_END_INSTR(CallPropertyLookup) + MOTH_BEGIN_INSTR(CallScopeObjectProperty) + TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); + callData->tag = QV4::Value::Integer_Type; + callData->argc = instr.argc; + callData->thisObject = VALUE(instr.base); + STOREVALUE(instr.result, Runtime::callQmlScopeObjectProperty(engine, instr.index, callData)); + MOTH_END_INSTR(CallScopeObjectProperty) + + MOTH_BEGIN_INSTR(CallContextObjectProperty) + TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); + callData->tag = QV4::Value::Integer_Type; + callData->argc = instr.argc; + callData->thisObject = VALUE(instr.base); + STOREVALUE(instr.result, Runtime::callQmlContextObjectProperty(engine, instr.index, callData)); + MOTH_END_INSTR(CallContextObjectProperty) + MOTH_BEGIN_INSTR(CallElement) Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); @@ -858,28 +901,20 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code engine->currentContext()->lineNumber = instr.lineNumber; if (qt_v4IsDebugging) qt_v4CheckForBreak(context, scopes, scopeDepth); - MOTH_END_INSTR(Debug) + MOTH_END_INSTR(Line) MOTH_BEGIN_INSTR(LoadThis) VALUE(instr.result) = context->thisObject(); MOTH_END_INSTR(LoadThis) - MOTH_BEGIN_INSTR(LoadQmlIdArray) - VALUE(instr.result) = Runtime::getQmlIdArray(static_cast<QV4::NoThrowEngine*>(engine)); - MOTH_END_INSTR(LoadQmlIdArray) + MOTH_BEGIN_INSTR(LoadQmlContext) + VALUE(instr.result) = Runtime::getQmlContext(static_cast<QV4::NoThrowEngine*>(engine)); + MOTH_END_INSTR(LoadQmlContext) MOTH_BEGIN_INSTR(LoadQmlImportedScripts) VALUE(instr.result) = Runtime::getQmlImportedScripts(static_cast<QV4::NoThrowEngine*>(engine)); MOTH_END_INSTR(LoadQmlImportedScripts) - MOTH_BEGIN_INSTR(LoadQmlContextObject) - VALUE(instr.result) = Runtime::getQmlContextObject(static_cast<QV4::NoThrowEngine*>(engine)); - MOTH_END_INSTR(LoadContextObject) - - MOTH_BEGIN_INSTR(LoadQmlScopeObject) - VALUE(instr.result) = Runtime::getQmlScopeObject(static_cast<QV4::NoThrowEngine*>(engine)); - MOTH_END_INSTR(LoadScopeObject) - MOTH_BEGIN_INSTR(LoadQmlSingleton) VALUE(instr.result) = Runtime::getQmlSingleton(static_cast<QV4::NoThrowEngine*>(engine), instr.name); MOTH_END_INSTR(LoadQmlSingleton) diff --git a/src/qml/memory/memory.pri b/src/qml/memory/memory.pri new file mode 100644 index 0000000000..04b7566ccc --- /dev/null +++ b/src/qml/memory/memory.pri @@ -0,0 +1,14 @@ +INCLUDEPATH += $$PWD +INCLUDEPATH += $$OUT_PWD + +!qmldevtools_build { +SOURCES += \ + $$PWD/qv4mm.cpp \ + +HEADERS += \ + $$PWD/qv4mm_p.h + +} + +HEADERS += \ + $$PWD/qv4heap_p.h diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h new file mode 100644 index 0000000000..a93e4191b0 --- /dev/null +++ b/src/qml/memory/qv4heap_p.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QV4HEAP_P_H +#define QV4HEAP_P_H + +#include <QtCore/QString> +#include <private/qv4global_p.h> + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +struct VTable +{ + const VTable * const parent; + uint isExecutionContext : 1; + uint isString : 1; + uint isObject : 1; + uint isFunctionObject : 1; + uint isErrorObject : 1; + uint isArrayData : 1; + uint unused : 18; + uint type : 8; + const char *className; + void (*destroy)(Heap::Base *); + void (*markObjects)(Heap::Base *, ExecutionEngine *e); + bool (*isEqualTo)(Managed *m, Managed *other); +}; + +namespace Heap { + +struct Q_QML_EXPORT Base { + quintptr mm_data; // vtable and markbit + + inline ReturnedValue asReturnedValue() const; + inline void mark(QV4::ExecutionEngine *engine); + + enum { + MarkBit = 0x1, + NotInUse = 0x2, + PointerMask = ~0x3 + }; + + void setVtable(const VTable *v) { + Q_ASSERT(!(mm_data & MarkBit)); + mm_data = reinterpret_cast<quintptr>(v); + } + VTable *vtable() const { + return reinterpret_cast<VTable *>(mm_data & PointerMask); + } + inline bool isMarked() const { + return mm_data & MarkBit; + } + inline void setMarkBit() { + mm_data |= MarkBit; + } + inline void clearMarkBit() { + mm_data &= ~MarkBit; + } + + inline bool inUse() const { + return !(mm_data & NotInUse); + } + + Base *nextFree() { + return reinterpret_cast<Base *>(mm_data & PointerMask); + } + void setNextFree(Base *m) { + mm_data = (reinterpret_cast<quintptr>(m) | NotInUse); + } + + void *operator new(size_t, Managed *m) { return m; } + void *operator new(size_t, Heap::Base *m) { return m; } + void operator delete(void *, Heap::Base *) {} +}; + +template <typename T> +struct Pointer { + Pointer() {} + Pointer(T *t) : ptr(t) {} + + T *operator->() const { return ptr; } + operator T *() const { return ptr; } + + Pointer &operator =(T *t) { ptr = t; return *this; } + + template <typename Type> + Type *cast() { return static_cast<Type *>(ptr); } + + T *ptr; +}; + +} + +} + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 64491e1376..38b4e1eaf1 100644 --- a/src/qml/jsruntime/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -111,8 +111,6 @@ struct MemoryManager::Data LargeItem *largeItems; std::size_t totalLargeItemsAllocated; - GCDeletable *deletable; - // statistics: #ifdef DETAILED_MM_STATS QVector<unsigned> allocSizeCounters; @@ -129,7 +127,6 @@ struct MemoryManager::Data , unmanagedHeapSizeGCLimit(64 * 1024) , largeItems(0) , totalLargeItemsAllocated(0) - , deletable(0) { memset(nonFullChunks, 0, sizeof(nonFullChunks)); memset(nChunks, 0, sizeof(nChunks)); @@ -189,15 +186,15 @@ bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, Exec #ifdef V4_USE_VALGRIND VALGRIND_ENABLE_ERROR_REPORTING; #endif - if (std::size_t(header->itemSize) == MemoryManager::align(sizeof(Heap::String)) && m->gcGetVtable()->isString) { + if (std::size_t(header->itemSize) == MemoryManager::align(sizeof(Heap::String)) && m->vtable()->isString) { std::size_t heapBytes = static_cast<Heap::String *>(m)->retainedTextSize(); Q_ASSERT(*unmanagedHeapSize >= heapBytes); // qDebug() << "-- it's a string holding on to" << heapBytes << "bytes"; *unmanagedHeapSize -= heapBytes; } - if (m->gcGetVtable()->destroy) - m->gcGetVtable()->destroy(m); + if (m->vtable()->destroy) + m->vtable()->destroy(m); memset(m, 0, header->itemSize); #ifdef V4_USE_VALGRIND @@ -307,7 +304,6 @@ Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize Q_V4_PROFILE_ALLOC(m_d->engine, allocSize, Profiling::HeapPage), OSAllocator::JSGCHeapPages); m_d->heapChunks.append(allocation); - std::sort(m_d->heapChunks.begin(), m_d->heapChunks.end()); header = reinterpret_cast<Data::ChunkHeader *>(allocation.base()); header->itemSize = int(size); @@ -353,8 +349,8 @@ static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase) { while (engine->jsStackTop > markBase) { Heap::Base *h = engine->popForGC(); - Q_ASSERT (h->gcGetVtable()->markObjects); - h->gcGetVtable()->markObjects(h, engine); + Q_ASSERT (h->vtable()->markObjects); + h->vtable()->markObjects(h, engine); } } @@ -377,11 +373,9 @@ void MemoryManager::mark() for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) { if (!(*it).isManaged()) continue; - if ((*it).managed()->d()->gcGetVtable() != QObjectWrapper::staticVTable()) + if ((*it).managed()->d()->vtable() != QObjectWrapper::staticVTable()) continue; QObjectWrapper *qobjectWrapper = static_cast<QObjectWrapper*>((*it).managed()); - if (!qobjectWrapper) - continue; QObject *qobject = qobjectWrapper->object(); if (!qobject) continue; @@ -408,13 +402,20 @@ void MemoryManager::mark() void MemoryManager::sweep(bool lastSweep) { - if (m_weakValues) { - for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) { - if (Managed *m = (*it).asManaged()) { - if (!m->markBit()) - (*it) = Primitive::undefinedValue(); - } + for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) { + if (!(*it).isManaged()) + continue; + Managed *m = (*it).as<Managed>(); + if (m->markBit()) + continue; + // we need to call detroyObject on qobjectwrappers now, so that they can emit the destroyed + // signal before we start sweeping the heap + if ((*it).managed()->d()->vtable() == QObjectWrapper::staticVTable()) { + QObjectWrapper *qobjectWrapper = static_cast<QObjectWrapper*>((*it).managed()); + qobjectWrapper->destroyObject(lastSweep); } + + (*it) = Primitive::undefinedValue(); } if (MultiplyWrappedQObjectMap *multiplyWrappedQObjects = m_d->engine->m_multiplyWrappedQObjects) { @@ -473,8 +474,8 @@ void MemoryManager::sweep(bool lastSweep) i = i->next; continue; } - if (m->gcGetVtable()->destroy) - m->gcGetVtable()->destroy(m); + if (m->vtable()->destroy) + m->vtable()->destroy(m); *last = i->next; free(Q_V4_PROFILE_DEALLOC(m_d->engine, i, i->size + sizeof(Data::LargeItem), @@ -482,15 +483,6 @@ void MemoryManager::sweep(bool lastSweep) i = *last; } - GCDeletable *deletable = m_d->deletable; - m_d->deletable = 0; - while (deletable) { - GCDeletable *next = deletable->next; - deletable->lastCall = lastSweep; - delete deletable; - deletable = next; - } - // some execution contexts are allocated on the stack, make sure we clear their markBit as well if (!lastSweep) { Heap::ExecutionContext *ctx = engine()->current; @@ -554,7 +546,7 @@ void MemoryManager::runGC() size_t MemoryManager::getUsedMem() const { size_t usedMem = 0; - for (QVector<PageAllocation>::const_iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i) { + for (QVector<PageAllocation>::const_iterator i = m_d->heapChunks.cbegin(), ei = m_d->heapChunks.cend(); i != ei; ++i) { Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(i->base()); for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) { Heap::Base *m = reinterpret_cast<Heap::Base *>(item); @@ -590,10 +582,10 @@ void MemoryManager::growUnmanagedHeapSizeUsage(size_t delta) MemoryManager::~MemoryManager() { delete m_persistentValues; - delete m_weakValues; - m_weakValues = 0; sweep(/*lastSweep*/true); + + delete m_weakValues; #ifdef V4_USE_VALGRIND VALGRIND_DESTROY_MEMPOOL(this); #endif @@ -618,12 +610,6 @@ void MemoryManager::dumpStats() const #endif // DETAILED_MM_STATS } -void MemoryManager::registerDeletable(GCDeletable *d) -{ - d->next = m_d->deletable; - m_d->deletable = d; -} - #ifdef DETAILED_MM_STATS void MemoryManager::willAllocate(std::size_t size) { @@ -641,7 +627,7 @@ void MemoryManager::collectFromJSStack() const Value *v = m_d->engine->jsStackBase; Value *top = m_d->engine->jsStackTop; while (v < top) { - Managed *m = v->asManaged(); + Managed *m = v->as<Managed>(); if (m && m->inUse()) // Skip pointers to already freed objects, they are bogus as well m->mark(m_d->engine); diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 7f6d2edba3..c01866ff11 100644 --- a/src/qml/jsruntime/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -34,9 +34,9 @@ #ifndef QV4GC_H #define QV4GC_H -#include "qv4global_p.h" -#include "qv4value_inl_p.h" -#include "qv4scopedvalue_p.h" +#include <private/qv4global_p.h> +#include <private/qv4value_p.h> +#include <private/qv4scopedvalue_p.h> //#define DETAILED_MM_STATS @@ -87,7 +87,7 @@ public: { size = align(size); Heap::Base *o = allocData(size, unmanagedSize); - o->vtable = ManagedType::staticVTable(); + o->setVtable(ManagedType::staticVTable()); return static_cast<typename ManagedType::Data *>(o); } @@ -162,8 +162,6 @@ public: void dumpStats() const; - void registerDeletable(GCDeletable *d); - size_t getUsedMem() const; size_t getAllocatedMem() const; size_t getLargeItemsMem() const; diff --git a/src/qml/parser/qqmljsmemorypool_p.h b/src/qml/parser/qqmljsmemorypool_p.h index 16927251c7..c7ac5919bd 100644 --- a/src/qml/parser/qqmljsmemorypool_p.h +++ b/src/qml/parser/qqmljsmemorypool_p.h @@ -104,28 +104,6 @@ public: template <typename _Tp> _Tp *New() { return new (this->allocate(sizeof(_Tp))) _Tp(); } - template <typename PoolContentType, typename Visitor> - void visitManagedPool(Visitor &visitor) - { - for (int i = 0; i <= _blockCount; ++i) { - char *p = _blocks[i]; - char *end = p + BLOCK_SIZE; - if (i == _blockCount) { - Q_ASSERT(_ptr <= end); - end = _ptr; - } - - Q_ASSERT(p <= end); - - const qptrdiff increment = (sizeof(PoolContentType) + 7) & ~7; - - while (p + increment <= end) { - visitor(reinterpret_cast<PoolContentType*>(p)); - p += increment; - } - } - } - private: void *allocate_helper(size_t size) { diff --git a/src/qml/qml.pro b/src/qml/qml.pro index 6e06fb42ef..d75262bf0b 100644 --- a/src/qml/qml.pro +++ b/src/qml/qml.pro @@ -8,6 +8,9 @@ win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS win32:!wince*:!winrt:LIBS += -lshell32 solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2 +# Ensure this gcc optimization is switched off for mips platforms to avoid trouble with JIT. +gcc:isEqual(QT_ARCH, "mips"): QMAKE_CXXFLAGS += -fno-reorder-blocks + MODULE_PLUGIN_TYPES = \ qmltooling @@ -33,6 +36,7 @@ HEADERS += qtqmlglobal.h \ #modules include(util/util.pri) +include(memory/memory.pri) include(parser/parser.pri) include(compiler/compiler.pri) include(jsapi/jsapi.pri) diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri index 4b109107f9..51697b0aff 100644 --- a/src/qml/qml/ftw/ftw.pri +++ b/src/qml/qml/ftw/ftw.pri @@ -4,7 +4,6 @@ HEADERS += \ $$PWD/qpodvector_p.h \ $$PWD/qhashedstring_p.h \ $$PWD/qqmlrefcount_p.h \ - $$PWD/qqmlpool_p.h \ $$PWD/qfieldlist_p.h \ $$PWD/qhashfield_p.h \ $$PWD/qqmlthread_p.h \ @@ -20,7 +19,6 @@ HEADERS += \ SOURCES += \ $$PWD/qintrusivelist.cpp \ $$PWD/qhashedstring.cpp \ - $$PWD/qqmlpool.cpp \ $$PWD/qqmlthread.cpp \ # mirrors logic in $$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri diff --git a/src/qml/qml/ftw/qqmlpool.cpp b/src/qml/qml/ftw/qqmlpool.cpp deleted file mode 100644 index b86dcba107..0000000000 --- a/src/qml/qml/ftw/qqmlpool.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlpool_p.h" -#include <stdlib.h> - -#ifdef Q_OS_QNX -#include <malloc.h> -#endif - -// #define POOL_DEBUG - -QT_BEGIN_NAMESPACE - -void QQmlPool::newpage() -{ -#ifdef POOL_DEBUG - qWarning("QQmlPool: Allocating page"); -#endif - - Page *page = (Page *)malloc(sizeof(Page)); - page->header.next = _page; - page->header.free = page->memory; - _page = page; -} - -void QQmlPool::clear() -{ -#ifdef POOL_DEBUG - int count = 0; -#endif - - Class *c = _classList; - while (c) { - Class *n = c->_next; - c->_destroy(c); -#ifdef POOL_DEBUG - ++count; -#endif - c = n; - } - -#ifdef POOL_DEBUG - qWarning("QQmlPool: Destroyed %d objects", count); -#endif - - Page *p = _page; - while (p) { - Page *n = p->header.next; - free(p); - p = n; - } - - _classList = 0; - _page = 0; -} - - -QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qqmlpool_p.h b/src/qml/qml/ftw/qqmlpool_p.h deleted file mode 100644 index 4956cd81d8..0000000000 --- a/src/qml/qml/ftw/qqmlpool_p.h +++ /dev/null @@ -1,270 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLPOOL_P_H -#define QQMLPOOL_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. -// - -#include <private/qv4global_p.h> -#include <QtCore/qstring.h> -#include <QtCore/qurl.h> - -QT_BEGIN_NAMESPACE - -class Q_QML_PRIVATE_EXPORT QQmlPool -{ -public: - // The class has a destructor that needs to be called - class Class { - public: - inline QQmlPool *pool() const; - - private: - void *operator new(size_t); - void *operator new(size_t, void *m) { return m; } - friend class QQmlPool; - - QQmlPool *_pool; - Class *_next; - void (*_destroy)(Class *); - }; - - // The class is plain old data and no destructor needs to - // be called - class POD { - public: - inline QQmlPool *pool() const; - - private: - void *operator new(size_t); - void *operator new(size_t, void *m) { return m; } - friend class QQmlPool; - - QQmlPool *_pool; - }; - - inline QQmlPool(); - inline ~QQmlPool(); - - void clear(); - - template<typename T> - inline T *New(); - template<typename T> - inline T *NewRaw(); - template<typename T> - inline T *NewRawArray(int length); - - inline QString *NewString(const QString &); - inline QByteArray *NewByteArray(const QByteArray &); - inline QUrl *NewUrl(const QUrl &); - - template<typename T> - struct List { - List() : m_length(0), m_data(0) {} - List(const List &o) : m_length(o.m_length), m_data(o.m_data) {} - List &operator=(const List &o) { - m_length = o.m_length; - m_data = o.m_data; - return *this; - } - - int count() const { - return m_length; - } - int length() const { - return m_length; - } - const T &at(int index) const { - Q_ASSERT(index < m_length); - return m_data[index]; - }; - T &operator[](int index) { - Q_ASSERT(index < m_length); - return m_data[index]; - }; - const T *data() const { return m_data; } - private: - friend class QQmlPool; - List(T *d, int l) : m_length(l), m_data(d) {} - int m_length; - T *m_data; - }; - - template<typename T> - inline List<T> NewRawList(int length); - -private: - struct StringClass : public QString, public Class { - }; - struct ByteArrayClass : public QByteArray, public Class { - }; - struct UrlClass : public QUrl, public Class { - }; - - inline void *allocate(int size); - void newpage(); - - template<typename T> - inline void initialize(POD *); - template<typename T> - inline void initialize(Class *); - template<typename T> - static void destroy(Class *c); - - struct Page { - struct Header { - Page *next; - char *free; - } header; - - static const int pageSize = 4 * 4096 - sizeof(Header); - - char memory[pageSize]; - }; - - Page *_page; - Class *_classList; -}; - -QQmlPool::QQmlPool() -: _page(0), _classList(0) -{ -} - -QQmlPool::~QQmlPool() -{ - clear(); -} - -template<typename T> -T *QQmlPool::New() -{ - T *rv = new (allocate(sizeof(T))) T; - initialize<T>(rv); - rv->_pool = this; - return rv; -} - -template<typename T> -T *QQmlPool::NewRaw() -{ - return (T*)allocate(sizeof(T)); -} - -template<typename T> -T *QQmlPool::NewRawArray(int length) -{ - return (T*)allocate(length * sizeof(T)); -} - -template<typename T> -QQmlPool::List<T> QQmlPool::NewRawList(int length) -{ - return List<T>(NewRawArray<T>(length), length); -} - -QString *QQmlPool::NewString(const QString &s) -{ - QString *rv = New<StringClass>(); - *rv = s; - return rv; -} - -QByteArray *QQmlPool::NewByteArray(const QByteArray &s) -{ - QByteArray *rv = New<ByteArrayClass>(); - *rv = s; - return rv; -} - -QUrl *QQmlPool::NewUrl(const QUrl &s) -{ - QUrl *rv = New<UrlClass>(); - *rv = s; - return rv; -} - -void *QQmlPool::allocate(int size) -{ - if (!_page || (_page->header.free + size) > (_page->memory + Page::pageSize)) - newpage(); - - void *rv = _page->header.free; - _page->header.free += size + ((8 - size) & 7); // ensure 8 byte alignment; - return rv; -} - -template<typename T> -void QQmlPool::initialize(QQmlPool::POD *) -{ -} - -template<typename T> -void QQmlPool::initialize(QQmlPool::Class *c) -{ - c->_next = _classList; - c->_destroy = &destroy<T>; - _classList = c; -} - -template<typename T> -void QQmlPool::destroy(Class *c) -{ - static_cast<T *>(c)->~T(); -} - -QQmlPool *QQmlPool::Class::pool() const -{ - return _pool; -} - -QQmlPool *QQmlPool::POD::pool() const -{ - return _pool; -} - -QT_END_NAMESPACE - -#endif // QQMLPOOL_P_H - diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h index 59ed77b580..ba2ca43990 100644 --- a/src/qml/qml/ftw/qqmlrefcount_p.h +++ b/src/qml/qml/ftw/qqmlrefcount_p.h @@ -72,13 +72,16 @@ template<class T> class QQmlRefPointer { public: + enum Mode { + AddRef, + Adopt + }; inline QQmlRefPointer(); - inline QQmlRefPointer(T *); + inline QQmlRefPointer(T *, Mode m = AddRef); inline QQmlRefPointer(const QQmlRefPointer<T> &); inline ~QQmlRefPointer(); inline QQmlRefPointer<T> &operator=(const QQmlRefPointer<T> &o); - inline QQmlRefPointer<T> &operator=(T *); inline bool isNull() const { return !o; } @@ -87,7 +90,7 @@ public: inline operator T*() const { return o; } inline T* data() const { return o; } - inline QQmlRefPointer<T> &take(T *); + inline QQmlRefPointer<T> &adopt(T *); private: T *o; @@ -133,10 +136,11 @@ QQmlRefPointer<T>::QQmlRefPointer() } template<class T> -QQmlRefPointer<T>::QQmlRefPointer(T *o) +QQmlRefPointer<T>::QQmlRefPointer(T *o, Mode m) : o(o) { - if (o) o->addref(); + if (m == AddRef && o) + o->addref(); } template<class T> @@ -161,21 +165,12 @@ QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(const QQmlRefPointer<T> &other) return *this; } -template<class T> -QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(T *other) -{ - if (other) other->addref(); - if (o) o->release(); - o = other; - return *this; -} - /*! Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership of the callers reference of other. */ template<class T> -QQmlRefPointer<T> &QQmlRefPointer<T>::take(T *other) +QQmlRefPointer<T> &QQmlRefPointer<T>::adopt(T *other) { if (o) o->release(); o = other; diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp index 4addcd9e58..62f6f76a7e 100644 --- a/src/qml/qml/ftw/qqmlthread.cpp +++ b/src/qml/qml/ftw/qqmlthread.cpp @@ -377,4 +377,31 @@ void QQmlThread::internalPostMethodToMain(Message *message) d->unlock(); } +void QQmlThread::waitForNextMessage() +{ + Q_ASSERT(!isThisThread()); + d->lock(); + Q_ASSERT(d->m_mainThreadWaiting == false); + + d->m_mainThreadWaiting = true; + + if (d->mainSync || !d->threadList.isEmpty()) { + if (d->mainSync) { + QQmlThread::Message *message = d->mainSync; + unlock(); + message->call(this); + delete message; + lock(); + d->mainSync = 0; + wakeOne(); + } else { + d->wait(); + } + } + + d->m_mainThreadWaiting = false; + d->unlock(); +} + + QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h index 86d7d2cf19..73658536ac 100644 --- a/src/qml/qml/ftw/qqmlthread_p.h +++ b/src/qml/qml/ftw/qqmlthread_p.h @@ -108,6 +108,8 @@ public: template<typename T, typename T2, class V, class V2, class O> inline void postMethodToMain(void (O::*Member)(V, V2), const T &, const T2 &); + void waitForNextMessage(); + protected: virtual void startupThread(); virtual void shutdownThread(); diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri index e733bcec05..4d84cc82ae 100644 --- a/src/qml/qml/qml.pri +++ b/src/qml/qml/qml.pri @@ -23,7 +23,6 @@ SOURCES += \ $$PWD/qqmlvaluetype.cpp \ $$PWD/qqmlaccessors.cpp \ $$PWD/qqmlxmlhttprequest.cpp \ - $$PWD/qqmlwatcher.cpp \ $$PWD/qqmlcleanup.cpp \ $$PWD/qqmlpropertycache.cpp \ $$PWD/qqmlnotifier.cpp \ @@ -35,7 +34,6 @@ SOURCES += \ $$PWD/qqmlimport.cpp \ $$PWD/qqmllist.cpp \ $$PWD/qqmllocale.cpp \ - $$PWD/qqmlabstractexpression.cpp \ $$PWD/qqmljavascriptexpression.cpp \ $$PWD/qqmlabstractbinding.cpp \ $$PWD/qqmlvaluetypeproxybinding.cpp \ @@ -92,7 +90,6 @@ HEADERS += \ $$PWD/qqmlvaluetype_p.h \ $$PWD/qqmlaccessors_p.h \ $$PWD/qqmlxmlhttprequest_p.h \ - $$PWD/qqmlwatcher_p.h \ $$PWD/qqmlcleanup_p.h \ $$PWD/qqmlpropertycache_p.h \ $$PWD/qqmlnotifier_p.h \ @@ -107,7 +104,6 @@ HEADERS += \ $$PWD/qqmlscriptstring_p.h \ $$PWD/qqmllocale_p.h \ $$PWD/qqmlcomponentattached_p.h \ - $$PWD/qqmlabstractexpression_p.h \ $$PWD/qqmljavascriptexpression_p.h \ $$PWD/qqmlabstractbinding_p.h \ $$PWD/qqmlvaluetypeproxybinding_p.h \ diff --git a/src/qml/qml/qqmlabstractbinding.cpp b/src/qml/qml/qqmlabstractbinding.cpp index 40c8f451b4..4e0763e95a 100644 --- a/src/qml/qml/qqmlabstractbinding.cpp +++ b/src/qml/qml/qqmlabstractbinding.cpp @@ -39,24 +39,19 @@ QT_BEGIN_NAMESPACE -extern QQmlAbstractBinding::VTable QQmlBinding_vtable; -extern QQmlAbstractBinding::VTable QQmlValueTypeProxyBinding_vtable; - -QQmlAbstractBinding::VTable *QQmlAbstractBinding::vTables[] = { - &QQmlBinding_vtable, - &QQmlValueTypeProxyBinding_vtable -}; - -QQmlAbstractBinding::QQmlAbstractBinding(BindingType bt) - : m_nextBindingPtr(bt) +QQmlAbstractBinding::QQmlAbstractBinding() + : m_targetIndex(-1) { + Q_ASSERT(!isAddedToObject()); } QQmlAbstractBinding::~QQmlAbstractBinding() { - Q_ASSERT(isAddedToObject() == false); - Q_ASSERT(nextBinding() == 0); - Q_ASSERT(*m_mePtr == 0); + Q_ASSERT(!ref); + Q_ASSERT(!isAddedToObject()); + + if (m_nextBinding.data() && !m_nextBinding->ref.deref()) + delete m_nextBinding.data(); } /*! @@ -72,40 +67,45 @@ void QQmlAbstractBinding::addToObject() Q_ASSERT(!nextBinding()); Q_ASSERT(isAddedToObject() == false); - QObject *obj = object(); + QObject *obj = targetObject(); Q_ASSERT(obj); QQmlData *data = QQmlData::get(obj, true); int coreIndex; - if (QQmlPropertyData::decodeValueTypePropertyIndex(propertyIndex(), &coreIndex) != -1) { + if (QQmlPropertyData::decodeValueTypePropertyIndex(targetPropertyIndex(), &coreIndex) != -1) { // Value type // Find the value type proxy (if there is one) QQmlValueTypeProxyBinding *proxy = 0; if (data->hasBindingBit(coreIndex)) { QQmlAbstractBinding *b = data->bindings; - while (b && b->propertyIndex() != coreIndex) + while (b && b->targetPropertyIndex() != coreIndex) b = b->nextBinding(); - Q_ASSERT(b && b->bindingType() == QQmlAbstractBinding::ValueTypeProxy); + Q_ASSERT(b && b->isValueTypeProxy()); proxy = static_cast<QQmlValueTypeProxyBinding *>(b); } if (!proxy) { proxy = new QQmlValueTypeProxyBinding(obj, coreIndex); - Q_ASSERT(proxy->propertyIndex() == coreIndex); - Q_ASSERT(proxy->object() == obj); + Q_ASSERT(proxy->targetPropertyIndex() == coreIndex); + Q_ASSERT(proxy->targetObject() == obj); proxy->addToObject(); } - setNextBinding(proxy->m_bindings); + setNextBinding(proxy->m_bindings.data()); proxy->m_bindings = this; } else { setNextBinding(data->bindings); + if (data->bindings) { + data->bindings->ref.deref(); + Q_ASSERT(data->bindings->ref.refCount > 0); + } data->bindings = this; + ref.ref(); data->setBindingBit(obj, coreIndex); } @@ -118,95 +118,81 @@ Remove the binding from the object. */ void QQmlAbstractBinding::removeFromObject() { - if (isAddedToObject()) { - QObject *obj = object(); - QQmlData *data = QQmlData::get(obj, false); - Q_ASSERT(data); - - int coreIndex; - if (QQmlPropertyData::decodeValueTypePropertyIndex(propertyIndex(), &coreIndex) != -1) { - - // Find the value type binding - QQmlAbstractBinding *vtbinding = data->bindings; - while (vtbinding->propertyIndex() != coreIndex) { - vtbinding = vtbinding->nextBinding(); - Q_ASSERT(vtbinding); - } - Q_ASSERT(vtbinding->bindingType() == QQmlAbstractBinding::ValueTypeProxy); - - QQmlValueTypeProxyBinding *vtproxybinding = - static_cast<QQmlValueTypeProxyBinding *>(vtbinding); - - QQmlAbstractBinding *binding = vtproxybinding->m_bindings; - if (binding == this) { - vtproxybinding->m_bindings = nextBinding(); - } else { - while (binding->nextBinding() != this) { - binding = binding->nextBinding(); - Q_ASSERT(binding); - } - binding->setNextBinding(nextBinding()); - } - - // Value type - we don't remove the proxy from the object. It will sit their happily - // doing nothing until it is removed by a write, a binding change or it is reused - // to hold more sub-bindings. + if (!isAddedToObject()) + return; - } else { + setAddedToObject(false); - if (data->bindings == this) { - data->bindings = nextBinding(); - } else { - QQmlAbstractBinding *binding = data->bindings; - while (binding->nextBinding() != this) { - binding = binding->nextBinding(); - Q_ASSERT(binding); - } - binding->setNextBinding(nextBinding()); - } - - data->clearBindingBit(coreIndex); - } + QObject *obj = targetObject(); + QQmlData *data = QQmlData::get(obj, false); + Q_ASSERT(data); - setNextBinding(0); - setAddedToObject(false); - } -} + QQmlAbstractBinding::Ptr next; + next = nextBinding(); + setNextBinding(0); -void QQmlAbstractBinding::printBindingLoopError(QQmlProperty &prop) -{ - qmlInfo(prop.object()) << QString(QLatin1String("Binding loop detected for property \"%1\"")).arg(prop.name()); -} + int coreIndex; + if (QQmlPropertyData::decodeValueTypePropertyIndex(targetPropertyIndex(), &coreIndex) != -1) { + // Find the value type binding + QQmlAbstractBinding *vtbinding = data->bindings; + while (vtbinding->targetPropertyIndex() != coreIndex) { + vtbinding = vtbinding->nextBinding(); + Q_ASSERT(vtbinding); + } + Q_ASSERT(vtbinding->isValueTypeProxy()); -static void bindingDummyDeleter(QQmlAbstractBinding *) -{ -} + QQmlValueTypeProxyBinding *vtproxybinding = + static_cast<QQmlValueTypeProxyBinding *>(vtbinding); -QQmlAbstractBinding::Pointer QQmlAbstractBinding::weakPointer() -{ - if (m_mePtr.value().isNull()) - m_mePtr.value() = QSharedPointer<QQmlAbstractBinding>(this, bindingDummyDeleter); + QQmlAbstractBinding *binding = vtproxybinding->m_bindings.data(); + if (binding == this) { + vtproxybinding->m_bindings = next; + } else { + while (binding->nextBinding() != this) { + binding = binding->nextBinding(); + Q_ASSERT(binding); + } + binding->setNextBinding(next.data()); + } - return m_mePtr.value().toWeakRef(); -} + // Value type - we don't remove the proxy from the object. It will sit their happily + // doing nothing until it is removed by a write, a binding change or it is reused + // to hold more sub-bindings. + return; + } -void QQmlAbstractBinding::clear() -{ - if (!m_mePtr.isNull()) { - **m_mePtr = 0; - m_mePtr = 0; + if (data->bindings == this) { + if (next.data()) + next->ref.ref(); + data->bindings = next.data(); + if (!ref.deref()) + delete this; + } else { + QQmlAbstractBinding *binding = data->bindings; + while (binding->nextBinding() != this) { + binding = binding->nextBinding(); + Q_ASSERT(binding); + } + binding->setNextBinding(next.data()); } + + data->clearBindingBit(coreIndex); } -void QQmlAbstractBinding::default_retargetBinding(QQmlAbstractBinding *, QObject *, int) +void QQmlAbstractBinding::printBindingLoopError(QQmlProperty &prop) { - qFatal("QQmlAbstractBinding::retargetBinding() called on illegal binding."); + qmlInfo(prop.object()) << QString(QLatin1String("Binding loop detected for property \"%1\"")).arg(prop.name()); } -QString QQmlAbstractBinding::default_expression(const QQmlAbstractBinding *) +QString QQmlAbstractBinding::expression() const { return QLatin1String("<Unknown>"); } +bool QQmlAbstractBinding::isValueTypeProxy() const +{ + return false; +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlabstractbinding_p.h b/src/qml/qml/qqmlabstractbinding_p.h index b5d8181ca5..dd14301aa9 100644 --- a/src/qml/qml/qqmlabstractbinding_p.h +++ b/src/qml/qml/qqmlabstractbinding_p.h @@ -46,6 +46,7 @@ // #include <QtCore/qsharedpointer.h> +#include <QtCore/qshareddata.h> #include <private/qtqmlglobal_p.h> #include <private/qqmlproperty_p.h> #include <private/qpointervaluepair_p.h> @@ -56,162 +57,83 @@ class QQmlObjectCreator; class Q_QML_PRIVATE_EXPORT QQmlAbstractBinding { +protected: + QQmlAbstractBinding(); public: - enum DestroyMode { - - // The binding should disconnect itself upon destroy - DisconnectBinding, - - // The binding doesn't need to disconnect itself, but it can if it wants to. - // - // This is used in QQmlData::destroyed() - at the point at which the bindings are - // destroyed, the notifiers are already disconnected, so no need to disconnect each - // binding again. - // - // Bindings can use this flag to speed up destruction, especially for v4 bindings - // disconnecting a single binding might be slow. - KeepBindingConnected - }; - - struct VTable { - void (*destroy)(QQmlAbstractBinding *, DestroyMode destroyMode); - QString (*expression)(const QQmlAbstractBinding *); - int (*propertyIndex)(const QQmlAbstractBinding *); - QObject *(*object)(const QQmlAbstractBinding *); - void (*setEnabled)(QQmlAbstractBinding *, bool, QQmlPropertyPrivate::WriteFlags); - void (*update)(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags); - void (*retargetBinding)(QQmlAbstractBinding *, QObject *, int); - }; - - typedef QWeakPointer<QQmlAbstractBinding> Pointer; + virtual ~QQmlAbstractBinding(); - enum BindingType { Binding = 0, ValueTypeProxy = 1 }; - inline BindingType bindingType() const; + typedef QExplicitlySharedDataPointer<QQmlAbstractBinding> Ptr; - // Destroy the binding. Use this instead of calling delete. - // Bindings are free to implement their own memory management, so the delete operator is - // not necessarily safe. The default implementation clears the binding, removes it from - // the object and calls delete. - void destroy(DestroyMode destroyMode = DisconnectBinding) - { vtable()->destroy(this, destroyMode); } + virtual QString expression() const; - QString expression() const { return vtable()->expression(this); } + virtual bool isValueTypeProxy() const; // Should return the encoded property index for the binding. Should return this value // even if the binding is not enabled or added to an object. // Encoding is: coreIndex | (valueTypeIndex << 16) - int propertyIndex() const { return vtable()->propertyIndex(this); } + int targetPropertyIndex() const { return m_targetIndex; } // Should return the object for the binding. Should return this object even if the // binding is not enabled or added to the object. - QObject *object() const { return vtable()->object(this); } - - void setEnabled(bool e) { setEnabled(e, QQmlPropertyPrivate::DontRemoveBinding); } - void setEnabled(bool e, QQmlPropertyPrivate::WriteFlags f) { vtable()->setEnabled(this, e, f); } + QObject *targetObject() const { return m_target.data(); } - void update() { update(QQmlPropertyPrivate::DontRemoveBinding); } - void update(QQmlPropertyPrivate::WriteFlags f) { vtable()->update(this, f); } + virtual void setEnabled(bool e, QQmlPropertyPrivate::WriteFlags f = QQmlPropertyPrivate::DontRemoveBinding) = 0; void addToObject(); void removeFromObject(); - static inline Pointer getPointer(QQmlAbstractBinding *p); static void printBindingLoopError(QQmlProperty &prop); - // Default implementation for some VTable functions - template<typename T> - static void default_destroy(QQmlAbstractBinding *, DestroyMode); - static QString default_expression(const QQmlAbstractBinding *); - static void default_retargetBinding(QQmlAbstractBinding *, QObject *, int); - -protected: - QQmlAbstractBinding(BindingType); - ~QQmlAbstractBinding(); - void clear(); + inline QQmlAbstractBinding *nextBinding() const; - // Called by QQmlPropertyPrivate to "move" a binding to a different property. - // This is only used for alias properties. The default implementation qFatal()'s - // to ensure that the method is never called for binding types that don't support it. - void retargetBinding(QObject *o, int i) { vtable()->retargetBinding(this, o, i); } -private: - Pointer weakPointer(); + struct RefCount { + RefCount() : refCount(0) {} + int refCount; + void ref() { ++refCount; } + int deref() { return --refCount; } + operator int() const { return refCount; } + }; + RefCount ref; +protected: friend class QQmlData; - friend class QQmlComponentPrivate; friend class QQmlValueTypeProxyBinding; - friend class QQmlPropertyPrivate; - friend class QtSharedPointer::ExternalRefCount<QQmlAbstractBinding>; - friend class QV4Bindings; friend class QQmlObjectCreator; - typedef QSharedPointer<QQmlAbstractBinding> SharedPointer; - // To save memory, we also store the rarely used weakPointer() instance in here - // We also use the flag bits: - // m_mePtr.flag1: added to object - QPointerValuePair<QQmlAbstractBinding*, SharedPointer> m_mePtr; - inline void setAddedToObject(bool v); inline bool isAddedToObject() const; - inline QQmlAbstractBinding *nextBinding() const; inline void setNextBinding(QQmlAbstractBinding *); + int m_targetIndex; + QFlagPointer<QObject> m_target; // Pointer to the next binding in the linked list of bindings. - // Being a pointer, the address is always aligned to at least 4 bytes, which means the last two - // bits of the pointer are free to be used for something else. They are used to store the binding - // type. The binding type serves as an index into the static vTables array, which is used instead - // of a compiler-generated vTable. Instead of virtual functions, pointers to static functions in - // the vTables array are used for dispatching. - // This saves a compiler-generated pointer to a compiler-generated vTable, and thus reduces - // the binding object size by sizeof(void*). - qintptr m_nextBindingPtr; - - static VTable *vTables[]; - inline const VTable *vtable() const { return vTables[bindingType()]; } + QFlagPointer<QQmlAbstractBinding> m_nextBinding; }; -QQmlAbstractBinding::Pointer -QQmlAbstractBinding::getPointer(QQmlAbstractBinding *p) -{ - return p ? p->weakPointer() : Pointer(); -} - void QQmlAbstractBinding::setAddedToObject(bool v) { - m_mePtr.setFlagValue(v); + m_nextBinding.setFlagValue(v); } bool QQmlAbstractBinding::isAddedToObject() const { - return m_mePtr.flag(); + return m_nextBinding.flag(); } QQmlAbstractBinding *QQmlAbstractBinding::nextBinding() const { - return (QQmlAbstractBinding *)(m_nextBindingPtr & ~0x3); + return m_nextBinding.data(); } void QQmlAbstractBinding::setNextBinding(QQmlAbstractBinding *b) { - m_nextBindingPtr = qintptr(b) | (m_nextBindingPtr & 0x3); -} - -QQmlAbstractBinding::BindingType QQmlAbstractBinding::bindingType() const -{ - return (BindingType)(m_nextBindingPtr & 0x3); -} - -template<typename T> -void QQmlAbstractBinding::default_destroy(QQmlAbstractBinding *This, DestroyMode mode) -{ - // Assume the binding disconnects itself in the destructor, which for example QQmlBinding - // does in the destructor of its base class, QQmlJavaScriptExpression - Q_UNUSED(mode); - - This->removeFromObject(); - This->clear(); - delete static_cast<T *>(This); + if (b) + b->ref.ref(); + if (m_nextBinding.data() && !m_nextBinding->ref.deref()) + delete m_nextBinding.data(); + m_nextBinding = b; } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlabstractexpression.cpp b/src/qml/qml/qqmlabstractexpression.cpp deleted file mode 100644 index c55c86952c..0000000000 --- a/src/qml/qml/qqmlabstractexpression.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlabstractexpression_p.h" - -QT_BEGIN_NAMESPACE - -QQmlAbstractExpression::QQmlAbstractExpression() -: m_prevExpression(0), m_nextExpression(0) -{ -} - -QQmlAbstractExpression::~QQmlAbstractExpression() -{ - if (m_prevExpression) { - *m_prevExpression = m_nextExpression; - if (m_nextExpression) - m_nextExpression->m_prevExpression = m_prevExpression; - } - - if (m_context.isT2()) - m_context.asT2()->_s = 0; -} - -QQmlContextData *QQmlAbstractExpression::context() const -{ - if (m_context.isT1()) return m_context.asT1(); - else return m_context.asT2()->_c; -} - -void QQmlAbstractExpression::setContext(QQmlContextData *context) -{ - if (m_prevExpression) { - *m_prevExpression = m_nextExpression; - if (m_nextExpression) - m_nextExpression->m_prevExpression = m_prevExpression; - m_prevExpression = 0; - m_nextExpression = 0; - } - - if (m_context.isT1()) m_context = context; - else m_context.asT2()->_c = context; - - if (context) { - m_nextExpression = context->expressions; - if (m_nextExpression) - m_nextExpression->m_prevExpression = &m_nextExpression; - m_prevExpression = &context->expressions; - context->expressions = this; - } -} - -void QQmlAbstractExpression::refresh() -{ -} - -bool QQmlAbstractExpression::isValid() const -{ - return context() != 0; -} - -QT_END_NAMESPACE - diff --git a/src/qml/qml/qqmlabstractexpression_p.h b/src/qml/qml/qqmlabstractexpression_p.h deleted file mode 100644 index 82ba010434..0000000000 --- a/src/qml/qml/qqmlabstractexpression_p.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLABSTRACTEXPRESSION_P_H -#define QQMLABSTRACTEXPRESSION_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. -// - -#include <private/qqmlcontext_p.h> -#include <private/qfieldlist_p.h> -#include <private/qflagpointer_p.h> - -QT_BEGIN_NAMESPACE - -class Q_QML_PRIVATE_EXPORT QQmlAbstractExpression -{ -public: - QQmlAbstractExpression(); - virtual ~QQmlAbstractExpression(); - - bool isValid() const; - - QQmlContextData *context() const; - void setContext(QQmlContextData *); - - virtual void refresh(); - - class DeleteWatcher { - public: - inline DeleteWatcher(QQmlAbstractExpression *); - inline ~DeleteWatcher(); - inline bool wasDeleted() const; - private: - friend class QQmlAbstractExpression; - QQmlContextData *_c; - QQmlAbstractExpression **_w; - QQmlAbstractExpression *_s; - }; - -private: - friend class QQmlContext; - friend class QQmlContextData; - friend class QQmlContextPrivate; - - QBiPointer<QQmlContextData, DeleteWatcher> m_context; - QQmlAbstractExpression **m_prevExpression; - QQmlAbstractExpression *m_nextExpression; -}; - -QQmlAbstractExpression::DeleteWatcher::DeleteWatcher(QQmlAbstractExpression *e) -: _c(0), _w(0), _s(e) -{ - if (e->m_context.isT1()) { - _w = &_s; - _c = e->m_context.asT1(); - e->m_context = this; - } else { - // Another watcher is already registered - _w = &e->m_context.asT2()->_s; - } -} - -QQmlAbstractExpression::DeleteWatcher::~DeleteWatcher() -{ - Q_ASSERT(*_w == 0 || (*_w == _s && _s->m_context.isT2())); - if (*_w && _s->m_context.asT2() == this) - _s->m_context = _c; -} - -bool QQmlAbstractExpression::DeleteWatcher::wasDeleted() const -{ - return *_w == 0; -} - -QT_END_NAMESPACE - -#endif // QQMLABSTRACTEXPRESSION_P_H diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index f223d099e4..3613c17242 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -43,43 +43,28 @@ #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> #include <QVariant> #include <QtCore/qdebug.h> QT_BEGIN_NAMESPACE -// Used in qqmlabstractbinding.cpp -QQmlAbstractBinding::VTable QQmlBinding_vtable = { - QQmlAbstractBinding::default_destroy<QQmlBinding>, - QQmlBinding::expression, - QQmlBinding::propertyIndex, - QQmlBinding::object, - QQmlBinding::setEnabled, - QQmlBinding::update, - QQmlBinding::retargetBinding -}; - -QQmlBinding::Identifier QQmlBinding::Invalid = -1; - -static QQmlJavaScriptExpression::VTable QQmlBinding_jsvtable = { - QQmlBinding::expressionIdentifier, - QQmlBinding::expressionChanged -}; - QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContext *ctxt) -: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding) + : QQmlJavaScriptExpression(), + QQmlAbstractBinding() { setNotifyOnValueChanged(true); - QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt)); + QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt)); setScopeObject(obj); - QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine(); - v4function.set(v4, qmlBinding(context(), obj, str, QString(), 0)); + createQmlBinding(context(), obj, str, QString(), 0); } QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt) -: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding) + : QQmlJavaScriptExpression(), + QQmlAbstractBinding() { if (ctxt && !ctxt->isValid()) return; @@ -100,51 +85,52 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte } setNotifyOnValueChanged(true); - QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context)); + QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context)); setScopeObject(obj ? obj : scriptPrivate->scope); QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine(); if (runtimeFunction) { - v4function.set(v4, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, scopeObject(), runtimeFunction)); + m_function.set(v4, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, scopeObject(), runtimeFunction)); } else { QString code = scriptPrivate->script; - v4function.set(v4, qmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber)); + createQmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber); } } QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt) -: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding) + : QQmlJavaScriptExpression(), + QQmlAbstractBinding() { setNotifyOnValueChanged(true); - QQmlAbstractExpression::setContext(ctxt); + QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(obj); - QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine(); - v4function.set(v4, qmlBinding(ctxt, obj, str, QString(), 0)); + createQmlBinding(ctxt, obj, str, QString(), 0); } QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt, const QString &url, quint16 lineNumber, quint16 columnNumber) -: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding) + : QQmlJavaScriptExpression(), + QQmlAbstractBinding() { Q_UNUSED(columnNumber); setNotifyOnValueChanged(true); - QQmlAbstractExpression::setContext(ctxt); + QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(obj); - QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine(); - v4function.set(v4, qmlBinding(ctxt, obj, str, url, lineNumber)); + createQmlBinding(ctxt, obj, str, url, lineNumber); } QQmlBinding::QQmlBinding(const QV4::Value &functionPtr, QObject *obj, QQmlContextData *ctxt) -: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding) + : QQmlJavaScriptExpression(), + QQmlAbstractBinding() { setNotifyOnValueChanged(true); - QQmlAbstractExpression::setContext(ctxt); + QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(obj); - v4function.set(functionPtr.asObject()->engine(), functionPtr); + m_function.set(functionPtr.as<QV4::Object>()->engine(), functionPtr); } QQmlBinding::~QQmlBinding() @@ -162,90 +148,243 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) return; // Check that the target has not been deleted - if (QQmlData::wasDeleted(object())) + if (QQmlData::wasDeleted(targetObject())) return; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); QV4::Scope scope(ep->v4engine()); - QV4::ScopedFunctionObject f(scope, v4function.value()); + QV4::ScopedFunctionObject f(scope, m_function.value()); Q_ASSERT(f); - if (!updatingFlag()) { - QQmlBindingProfiler prof(ep->profiler, f); - setUpdatingFlag(true); + if (updatingFlag()) { + QQmlProperty p = QQmlPropertyPrivate::restore(targetObject(), getPropertyData(), 0); + QQmlAbstractBinding::printBindingLoopError(p); + return; + } + + QQmlBindingProfiler prof(ep->profiler, f); + setUpdatingFlag(true); - QQmlAbstractExpression::DeleteWatcher watcher(this); + QQmlJavaScriptExpression::DeleteWatcher watcher(this); - if (m_core.propType == qMetaTypeId<QQmlBinding *>()) { + QQmlPropertyData pd = getPropertyData(); - int idx = m_core.coreIndex; - Q_ASSERT(idx != -1); + if (pd.propType == qMetaTypeId<QQmlBinding *>()) { - QQmlBinding *t = this; - int status = -1; - void *a[] = { &t, 0, &status, &flags }; - QMetaObject::metacall(*m_coreObject, QMetaObject::WriteProperty, idx, a); + int idx = pd.coreIndex; + Q_ASSERT(idx != -1); - } else { - ep->referenceScarceResources(); + QQmlBinding *t = this; + int status = -1; + void *a[] = { &t, 0, &status, &flags }; + QMetaObject::metacall(*m_target, QMetaObject::WriteProperty, idx, a); - bool isUndefined = false; + } else { + ep->referenceScarceResources(); - QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(context(), f, &isUndefined)); + bool isUndefined = false; - bool needsErrorLocationData = false; - if (!watcher.wasDeleted() && !hasError()) - needsErrorLocationData = !QQmlPropertyPrivate::writeBinding(*m_coreObject, m_core, context(), - this, result, isUndefined, flags); + QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined)); - if (!watcher.wasDeleted()) { + bool error = false; + if (!watcher.wasDeleted() && isAddedToObject() && !hasError()) + error = !write(pd, result, isUndefined, flags); - if (needsErrorLocationData) - delayedError()->setErrorLocation(f->sourceLocation()); + if (!watcher.wasDeleted()) { - if (hasError()) { - if (!delayedError()->addError(ep)) ep->warning(this->error(context()->engine)); - } else { - clearError(); - } + if (error) { + delayedError()->setErrorLocation(f->sourceLocation()); + delayedError()->setErrorObject(m_target.data()); + } + if (hasError()) { + if (!delayedError()->addError(ep)) ep->warning(this->error(context()->engine)); + } else { + clearError(); } - ep->dereferenceScarceResources(); } - if (!watcher.wasDeleted()) - setUpdatingFlag(false); - } else { - QQmlProperty p = property(); - QQmlAbstractBinding::printBindingLoopError(p); + ep->dereferenceScarceResources(); } + + if (!watcher.wasDeleted()) + setUpdatingFlag(false); +} + +// Returns true if successful, false if an error description was set on expression +bool QQmlBinding::write(const QQmlPropertyData &core, + const QV4::Value &result, bool isUndefined, + QQmlPropertyPrivate::WriteFlags flags) +{ + Q_ASSERT(m_target.data()); + Q_ASSERT(core.coreIndex != -1); + + QQmlEngine *engine = context()->engine; + QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine); + +#define QUICK_STORE(cpptype, conversion) \ + { \ + cpptype o = (conversion); \ + int status = -1; \ + void *argv[] = { &o, 0, &status, &flags }; \ + QMetaObject::metacall(m_target.data(), QMetaObject::WriteProperty, core.coreIndex, argv); \ + return true; \ + } \ + + + if (!isUndefined && !core.isValueTypeVirtual()) { + switch (core.propType) { + case QMetaType::Int: + if (result.isInteger()) + QUICK_STORE(int, result.integerValue()) + else if (result.isNumber()) + QUICK_STORE(int, result.doubleValue()) + break; + case QMetaType::Double: + if (result.isNumber()) + QUICK_STORE(double, result.asDouble()) + break; + case QMetaType::Float: + if (result.isNumber()) + QUICK_STORE(float, result.asDouble()) + break; + case QMetaType::QString: + if (result.isString()) + QUICK_STORE(QString, result.toQStringNoThrow()) + break; + default: + if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) { + if (vtw->d()->valueType->typeId == core.propType) { + return vtw->write(m_target.data(), core.coreIndex); + } + } + break; + } + } +#undef QUICK_STORE + + int type = core.isValueTypeVirtual() ? core.valueTypePropType : core.propType; + + QQmlJavaScriptExpression::DeleteWatcher watcher(this); + + QVariant value; + bool isVarProperty = core.isVarProperty(); + + if (isUndefined) { + } else if (core.isQList()) { + value = QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QObject *> >()); + } else if (result.isNull() && core.isQObject()) { + value = QVariant::fromValue((QObject *)0); + } else if (core.propType == qMetaTypeId<QList<QUrl> >()) { + value = QQmlPropertyPrivate::resolvedUrlSequence(QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QUrl> >()), context()); + } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) { + value = QV8Engine::getV4(v8engine)->toVariant(result, type); + } + + if (hasError()) { + return false; + } else if (isVarProperty) { + const QV4::FunctionObject *f = result.as<QV4::FunctionObject>(); + if (f && f->isBinding()) { + // we explicitly disallow this case to avoid confusion. Users can still store one + // in an array in a var property if they need to, but the common case is user error. + delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); + return false; + } + + QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_target.data()); + Q_ASSERT(vmemo); + vmemo->setVMEProperty(core.coreIndex, result); + } else if (isUndefined && core.isResettable()) { + void *args[] = { 0 }; + QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex, args); + } else if (isUndefined && type == qMetaTypeId<QVariant>()) { + QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, QVariant(), context(), flags); + } else if (type == qMetaTypeId<QJSValue>()) { + const QV4::FunctionObject *f = result.as<QV4::FunctionObject>(); + if (f && f->isBinding()) { + delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); + return false; + } + QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, QVariant::fromValue( + QJSValue(QV8Engine::getV4(v8engine), result.asReturnedValue())), + context(), flags); + } else if (isUndefined) { + QString errorStr = QLatin1String("Unable to assign [undefined] to "); + if (!QMetaType::typeName(type)) + errorStr += QLatin1String("[unknown property type]"); + else + errorStr += QLatin1String(QMetaType::typeName(type)); + delayedError()->setErrorDescription(errorStr); + return false; + } else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>()) { + if (f->isBinding()) + delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); + else + delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var.")); + return false; + } else if (!QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, value, context(), flags)) { + + if (watcher.wasDeleted()) + return true; + + const char *valueType = 0; + const char *propertyType = 0; + + if (value.userType() == QMetaType::QObjectStar) { + if (QObject *o = *(QObject *const *)value.constData()) { + valueType = o->metaObject()->className(); + + QQmlMetaObject propertyMetaObject = QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate::get(engine), type); + if (!propertyMetaObject.isNull()) + propertyType = propertyMetaObject.className(); + } + } else if (value.userType() != QVariant::Invalid) { + if (value.userType() == QMetaType::VoidStar) + valueType = "null"; + else + valueType = QMetaType::typeName(value.userType()); + } + + if (!valueType) + valueType = "undefined"; + if (!propertyType) + propertyType = QMetaType::typeName(type); + if (!propertyType) + propertyType = "[unknown property type]"; + + delayedError()->setErrorDescription(QLatin1String("Unable to assign ") + + QLatin1String(valueType) + + QLatin1String(" to ") + + QLatin1String(propertyType)); + return false; + } + + return true; } QVariant QQmlBinding::evaluate() { QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); - QV4::Scope scope(ep->v4engine()); ep->referenceScarceResources(); bool isUndefined = false; - QV4::ScopedValue f(scope, v4function.value()); - QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(context(), f, &isUndefined)); + QV4::Scope scope(ep->v4engine()); + QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined)); ep->dereferenceScarceResources(); return scope.engine->toVariant(result, qMetaTypeId<QList<QObject*> >()); } -QString QQmlBinding::expressionIdentifier(QQmlJavaScriptExpression *e) +QString QQmlBinding::expressionIdentifier() { - QQmlBinding *This = static_cast<QQmlBinding *>(e); - - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(This->context()->engine); + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); QV4::Scope scope(ep->v4engine()); - QV4::ScopedValue f(scope, This->v4function.value()); - QV4::Function *function = f->asFunctionObject()->function(); + 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; @@ -254,10 +393,9 @@ QString QQmlBinding::expressionIdentifier(QQmlJavaScriptExpression *e) return url + QLatin1Char(':') + QString::number(lineNumber) + QLatin1Char(':') + QString::number(columnNumber); } -void QQmlBinding::expressionChanged(QQmlJavaScriptExpression *e) +void QQmlBinding::expressionChanged() { - QQmlBinding *This = static_cast<QQmlBinding *>(e); - This->update(); + update(); } void QQmlBinding::refresh() @@ -265,36 +403,6 @@ void QQmlBinding::refresh() update(); } -QString QQmlBinding::expression(const QQmlAbstractBinding *This) -{ - return static_cast<const QQmlBinding *>(This)->expression(); -} - -int QQmlBinding::propertyIndex(const QQmlAbstractBinding *This) -{ - return static_cast<const QQmlBinding *>(This)->propertyIndex(); -} - -QObject *QQmlBinding::object(const QQmlAbstractBinding *This) -{ - return static_cast<const QQmlBinding *>(This)->object(); -} - -void QQmlBinding::setEnabled(QQmlAbstractBinding *This, bool e, QQmlPropertyPrivate::WriteFlags f) -{ - static_cast<QQmlBinding *>(This)->setEnabled(e, f); -} - -void QQmlBinding::update(QQmlAbstractBinding *This , QQmlPropertyPrivate::WriteFlags f) -{ - static_cast<QQmlBinding *>(This)->update(f); -} - -void QQmlBinding::retargetBinding(QQmlAbstractBinding *This, QObject *o, int i) -{ - static_cast<QQmlBinding *>(This)->retargetBinding(o, i); -} - void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags) { setEnabledFlag(e); @@ -307,44 +415,92 @@ void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags) QString QQmlBinding::expression() const { QV4::Scope scope(QQmlEnginePrivate::get(context()->engine)->v4engine()); - QV4::ScopedValue v(scope, v4function.value()); + QV4::ScopedValue v(scope, m_function.value()); return v->toQStringNoThrow(); } -QObject *QQmlBinding::object() const +void QQmlBinding::setTarget(const QQmlProperty &prop) { - if (m_coreObject.hasValue()) return m_coreObject.constValue()->target; - else return *m_coreObject; + setTarget(prop.object(), QQmlPropertyPrivate::get(prop)->core); } -int QQmlBinding::propertyIndex() const +void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core) { - if (m_coreObject.hasValue()) return m_coreObject.constValue()->targetProperty; - else return m_core.encodedIndex(); -} + m_target = object; -void QQmlBinding::retargetBinding(QObject *t, int i) -{ - m_coreObject.value().target = t; - m_coreObject.value().targetProperty = i; -} + if (!object) { + m_targetIndex = -1; + return; + } -void QQmlBinding::setTarget(const QQmlProperty &prop) -{ - setTarget(prop.object(), QQmlPropertyPrivate::get(prop)->core, - QQmlPropertyPrivate::get(prop)->context); -} + QQmlPropertyData pd = core; -void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, QQmlContextData *ctxt) -{ - m_coreObject = object; - m_core = core; - m_ctxt = ctxt; + while (pd.isAlias()) { + int coreIndex = pd.coreIndex; + int valueTypeIndex = pd.getValueTypeCoreIndex(); + QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); + + int aValueTypeIndex; + if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) { + m_target = 0; + m_targetIndex = -1; + return; + } + if (valueTypeIndex == -1) + valueTypeIndex = aValueTypeIndex; + + QQmlData *data = QQmlData::get(object, false); + if (!data || !data->propertyCache) { + m_target = 0; + m_targetIndex = -1; + return; + } + QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); + Q_ASSERT(propertyData); + + m_target = object; + pd = *propertyData; + if (valueTypeIndex != -1) { + const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(pd.propType); + Q_ASSERT(valueTypeMetaObject); + QMetaProperty vtProp = valueTypeMetaObject->property(valueTypeIndex); + pd.setFlags(pd.getFlags() | QQmlPropertyData::IsValueTypeVirtual); + pd.valueTypeFlags = QQmlPropertyData::flagsForProperty(vtProp); + pd.valueTypePropType = vtProp.userType(); + pd.valueTypeCoreIndex = valueTypeIndex; + } + } + m_targetIndex = pd.encodedIndex(); + + QQmlData *data = QQmlData::get(*m_target, true); + if (!data->propertyCache) { + data->propertyCache = QQmlEnginePrivate::get(context()->engine)->cache(m_target->metaObject()); + data->propertyCache->addref(); + } } -QQmlProperty QQmlBinding::property() const +QQmlPropertyData QQmlBinding::getPropertyData() const { - return QQmlPropertyPrivate::restore(object(), m_core, *m_ctxt); + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(m_targetIndex, &coreIndex); + + QQmlData *data = QQmlData::get(*m_target, false); + Q_ASSERT(data && data->propertyCache); + + QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); + Q_ASSERT(propertyData); + + QQmlPropertyData d = *propertyData; + if (valueTypeIndex != -1) { + const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(d.propType); + Q_ASSERT(valueTypeMetaObject); + QMetaProperty vtProp = valueTypeMetaObject->property(valueTypeIndex); + d.setFlags(d.getFlags() | QQmlPropertyData::IsValueTypeVirtual); + d.valueTypeFlags = QQmlPropertyData::flagsForProperty(vtProp); + d.valueTypePropType = vtProp.userType(); + d.valueTypeCoreIndex = valueTypeIndex; + } + return d; } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index 1e440b2e86..a435847819 100644 --- a/src/qml/qml/qqmlbinding_p.h +++ b/src/qml/qml/qqmlbinding_p.h @@ -57,16 +57,15 @@ #include <private/qpointervaluepair_p.h> #include <private/qqmlabstractbinding_p.h> -#include <private/qqmlabstractexpression_p.h> #include <private/qqmljavascriptexpression_p.h> QT_BEGIN_NAMESPACE class QQmlContext; class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlJavaScriptExpression, - public QQmlAbstractExpression, public QQmlAbstractBinding { + friend class QQmlAbstractBinding; public: QQmlBinding(const QString &, QObject *, QQmlContext *); QQmlBinding(const QQmlScriptString &, QObject *, QQmlContext *); @@ -74,84 +73,62 @@ public: QQmlBinding(const QString &, QObject *, QQmlContextData *, const QString &url, quint16 lineNumber, quint16 columnNumber); QQmlBinding(const QV4::Value &, QObject *, QQmlContextData *); + ~QQmlBinding(); void setTarget(const QQmlProperty &); - void setTarget(QObject *, const QQmlPropertyData &, QQmlContextData *); - QQmlProperty property() const; + void setTarget(QObject *, const QQmlPropertyData &); void setNotifyOnValueChanged(bool); - // Inherited from QQmlAbstractExpression + // Inherited from QQmlJavaScriptExpression virtual void refresh(); - // "Inherited" from QQmlAbstractBinding - static QString expression(const QQmlAbstractBinding *); - static int propertyIndex(const QQmlAbstractBinding *); - static QObject *object(const QQmlAbstractBinding *); - static void setEnabled(QQmlAbstractBinding *, bool, QQmlPropertyPrivate::WriteFlags); - static void update(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags); - static void retargetBinding(QQmlAbstractBinding *, QObject *, int); - - void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags); - void update(QQmlPropertyPrivate::WriteFlags flags); - void update() { update(QQmlPropertyPrivate::DontRemoveBinding); } - - QString expression() const; - QObject *object() const; - int propertyIndex() const; - void retargetBinding(QObject *, int); + // Inherited from QQmlAbstractBinding + virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding); + virtual QString expression() const; + void update(QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding); typedef int Identifier; - static Identifier Invalid; + enum { + Invalid = -1 + }; QVariant evaluate(); - static QString expressionIdentifier(QQmlJavaScriptExpression *); - static void expressionChanged(QQmlJavaScriptExpression *); - -protected: - friend class QQmlAbstractBinding; - ~QQmlBinding(); + virtual QString expressionIdentifier(); + virtual void expressionChanged(); private: - QV4::PersistentValue v4function; - inline bool updatingFlag() const; inline void setUpdatingFlag(bool); inline bool enabledFlag() const; inline void setEnabledFlag(bool); + QQmlPropertyData getPropertyData() const; - struct Retarget { - QObject *target; - int targetProperty; - }; + bool write(const QQmlPropertyData &core, + const QV4::Value &result, bool isUndefined, + QQmlPropertyPrivate::WriteFlags flags); - QPointerValuePair<QObject, Retarget> m_coreObject; - QQmlPropertyData m_core; - // We store some flag bits in the following flag pointers. - // m_ctxt:flag1 - updatingFlag - // m_ctxt:flag2 - enabledFlag - QFlagPointer<QQmlContextData> m_ctxt; }; bool QQmlBinding::updatingFlag() const { - return m_ctxt.flag(); + return m_target.flag(); } void QQmlBinding::setUpdatingFlag(bool v) { - m_ctxt.setFlagValue(v); + m_target.setFlagValue(v); } bool QQmlBinding::enabledFlag() const { - return m_ctxt.flag2(); + return m_target.flag2(); } void QQmlBinding::setEnabledFlag(bool v) { - m_ctxt.setFlag2Value(v); + m_target.setFlag2Value(v); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 766e657c59..3d1a9f8a88 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -43,11 +43,12 @@ #include "qqmlcontext.h" #include "qqmlglobal_p.h" #include <private/qqmlprofiler_p.h> -#include <private/qv4debugservice_p.h> +#include <private/qqmldebugconnector_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> #include <private/qqmlcompiler_p.h> #include "qqmlinfo.h" -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <QtCore/qstringbuilder.h> #include <QtCore/qdebug.h> @@ -55,59 +56,68 @@ QT_BEGIN_NAMESPACE -static QQmlJavaScriptExpression::VTable QQmlBoundSignalExpression_jsvtable = { - QQmlBoundSignalExpression::expressionIdentifier, - QQmlBoundSignalExpression::expressionChanged -}; - -QQmlBoundSignalExpression::ExtraData::ExtraData(const QString &handlerName, const QString ¶meterString, - const QString &expression, const QString &fileName, - quint16 line, quint16 column) - : m_handlerName(handlerName), - m_parameterString(parameterString), - m_expression(expression), - m_sourceLocation(fileName, line, column) -{ -} - QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, const QString &expression, const QString &fileName, quint16 line, quint16 column, const QString &handlerName, const QString ¶meterString) - : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), + : QQmlJavaScriptExpression(), m_index(index), - m_target(target), - m_extra(new ExtraData(handlerName, parameterString, expression, fileName, line, column)) + m_target(target) { - setExpressionFunctionValid(false); - setInvalidParameterName(false); - init(ctxt, scope); + + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine()); + QV4::ExecutionEngine *v4 = ep->v4engine(); + + QString function; + + // Add some leading whitespace to account for the binding's column offset. + // It's 2 off because a, we start counting at 1 and b, the '(' below is not counted. + function.fill(QChar(QChar::Space), qMax(column, (quint16)2) - 2); + function += QStringLiteral("(function "); + function += handlerName; + function += QLatin1Char('('); + + if (parameterString.isEmpty()) { + QString error; + //TODO: look at using the property cache here (as in the compiler) + // for further optimization + QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index); + function += QQmlPropertyCache::signalParameterStringForJS(v4, signal.parameterNames(), &error); + + if (!error.isEmpty()) { + qmlInfo(scopeObject()) << error; + return; + } + } else + function += parameterString; + + function += QStringLiteral(") { "); + function += expression; + function += QStringLiteral(" })"); + + m_function.set(v4, evalFunction(context(), scopeObject(), function, fileName, line)); + + if (m_function.isNullOrUndefined()) + return; // could not evaluate function. Not valid. + } QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, const QV4::Value &function) - : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), + : QQmlJavaScriptExpression(), m_index(index), - m_function(function.asObject()->engine(), function), - m_target(target), - m_extra(0) + m_target(target) { - setExpressionFunctionValid(true); - setInvalidParameterName(false); - + m_function.set(function.as<QV4::Object>()->engine(), function); init(ctxt, scope); } QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction) - : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), + : QQmlJavaScriptExpression(), m_index(index), - m_target(target), - m_extra(0) + m_target(target) { - setExpressionFunctionValid(true); - setInvalidParameterName(false); - // It's important to call init first, because m_index gets remapped in case of cloned signals. init(ctxt, scope); @@ -117,9 +127,8 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, m_function.set(engine, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, scope, runtimeFunction, signal.parameterNames(), &error)); if (!error.isEmpty()) { qmlInfo(scopeObject()) << error; - setInvalidParameterName(true); - } else - setInvalidParameterName(false); + m_function.clear(); + } } void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope) @@ -134,34 +143,30 @@ void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope) QQmlBoundSignalExpression::~QQmlBoundSignalExpression() { - delete m_extra.data(); } -QString QQmlBoundSignalExpression::expressionIdentifier(QQmlJavaScriptExpression *e) +QString QQmlBoundSignalExpression::expressionIdentifier() { - QQmlBoundSignalExpression *This = static_cast<QQmlBoundSignalExpression *>(e); - QQmlSourceLocation loc = This->sourceLocation(); + QQmlSourceLocation loc = sourceLocation(); return loc.sourceFile + QLatin1Char(':') + QString::number(loc.line); } -void QQmlBoundSignalExpression::expressionChanged(QQmlJavaScriptExpression *) +void QQmlBoundSignalExpression::expressionChanged() { // bound signals do not notify on change. } QQmlSourceLocation QQmlBoundSignalExpression::sourceLocation() const { - if (expressionFunctionValid()) { - QV4::Function *f = function(); - Q_ASSERT(f); + 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; } - Q_ASSERT(!m_extra.isNull()); - return m_extra->m_sourceLocation; + return QQmlSourceLocation(); } QString QQmlBoundSignalExpression::expression() const @@ -171,10 +176,8 @@ QString QQmlBoundSignalExpression::expression() const QV4::Scope scope(QQmlEnginePrivate::get(engine())->v4engine()); QV4::ScopedValue v(scope, m_function.value()); return v->toQStringNoThrow(); - } else { - Q_ASSERT(!m_extra.isNull()); - return m_extra->m_expression; } + return QString(); } QV4::Function *QQmlBoundSignalExpression::function() const @@ -194,108 +197,79 @@ void QQmlBoundSignalExpression::evaluate(void **a) { Q_ASSERT (context() && engine()); - if (invalidParameterName()) + if (!expressionFunctionValid()) return; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine()); QV4::Scope scope(ep->v4engine()); ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation. - { - if (!expressionFunctionValid()) { - Q_ASSERT(!m_extra.isNull()); - QString expression; - - // Add some leading whitespace to account for the binding's column offset. - // It's 2 off because a, we start counting at 1 and b, the '(' below is not counted. - expression.fill(QChar(QChar::Space), qMax(m_extra->m_sourceLocation.column, (quint16)2) - 2); - expression += QStringLiteral("(function "); - expression += m_extra->m_handlerName; - expression += QLatin1Char('('); - - if (m_extra->m_parameterString.isEmpty()) { - QString error; - //TODO: look at using the property cache here (as in the compiler) - // for further optimization - QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index); - expression += QQmlPropertyCache::signalParameterStringForJS(scope.engine, signal.parameterNames(), &error); - - if (!error.isEmpty()) { - qmlInfo(scopeObject()) << error; - setInvalidParameterName(true); - ep->dereferenceScarceResources(); - return; - } - } else - expression += m_extra->m_parameterString; - - expression += QStringLiteral(") { "); - expression += m_extra->m_expression; - expression += QStringLiteral(" })"); - - m_extra->m_expression.clear(); - m_extra->m_handlerName.clear(); - m_extra->m_parameterString.clear(); - - m_function.set(scope.engine, evalFunction(context(), scopeObject(), expression, - m_extra->m_sourceLocation.sourceFile, m_extra->m_sourceLocation.line, &m_extra->m_v8qmlscope)); - - if (m_function.isNullOrUndefined()) { - ep->dereferenceScarceResources(); - return; // could not evaluate function. Not valid. - } - - setExpressionFunctionValid(true); - } - QVarLengthArray<int, 9> dummy; - //TODO: lookup via signal index rather than method index as an optimization - int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex(); - int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, dummy, 0); - int argCount = argsTypes ? *argsTypes : 0; - - QV4::ScopedValue f(scope, m_function.value()); - QV4::ScopedCallData callData(scope, argCount); - for (int ii = 0; ii < argCount; ++ii) { - int type = argsTypes[ii + 1]; - //### ideally we would use metaTypeToJS, however it currently gives different results - // for several cases (such as QVariant type and QObject-derived types) - //args[ii] = engine->metaTypeToJS(type, a[ii + 1]); - if (type == QMetaType::QVariant) { - callData->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1])); - } else if (type == QMetaType::Int) { - //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise - callData->args[ii] = QV4::Primitive::fromInt32(*reinterpret_cast<const int*>(a[ii + 1])); - } else if (type == qMetaTypeId<QQmlV4Handle>()) { - callData->args[ii] = *reinterpret_cast<QQmlV4Handle *>(a[ii + 1]); - } else if (ep->isQObject(type)) { - if (!*reinterpret_cast<void* const *>(a[ii + 1])) - callData->args[ii] = QV4::Primitive::nullValue(); - else - callData->args[ii] = QV4::QObjectWrapper::wrap(ep->v4engine(), *reinterpret_cast<QObject* const *>(a[ii + 1])); - } else { - callData->args[ii] = scope.engine->fromVariant(QVariant(type, a[ii + 1])); - } + QVarLengthArray<int, 9> dummy; + //TODO: lookup via signal index rather than method index as an optimization + int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex(); + int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, dummy, 0); + int argCount = argsTypes ? *argsTypes : 0; + + QV4::ScopedCallData callData(scope, argCount); + for (int ii = 0; ii < argCount; ++ii) { + int type = argsTypes[ii + 1]; + //### ideally we would use metaTypeToJS, however it currently gives different results + // for several cases (such as QVariant type and QObject-derived types) + //args[ii] = engine->metaTypeToJS(type, a[ii + 1]); + if (type == QMetaType::QVariant) { + callData->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1])); + } else if (type == QMetaType::Int) { + //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise + callData->args[ii] = QV4::Primitive::fromInt32(*reinterpret_cast<const int*>(a[ii + 1])); + } else if (type == qMetaTypeId<QQmlV4Handle>()) { + callData->args[ii] = *reinterpret_cast<QQmlV4Handle *>(a[ii + 1]); + } else if (ep->isQObject(type)) { + if (!*reinterpret_cast<void* const *>(a[ii + 1])) + callData->args[ii] = QV4::Primitive::nullValue(); + else + callData->args[ii] = QV4::QObjectWrapper::wrap(ep->v4engine(), *reinterpret_cast<QObject* const *>(a[ii + 1])); + } else { + callData->args[ii] = scope.engine->fromVariant(QVariant(type, a[ii + 1])); } - - QQmlJavaScriptExpression::evaluate(context(), f, callData, 0); } + + QQmlJavaScriptExpression::evaluate(callData, 0); + ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. } //////////////////////////////////////////////////////////////////////// -QQmlAbstractBoundSignal::QQmlAbstractBoundSignal() -: m_prevSignal(0), m_nextSignal(0) + +/*! \internal + \a signal MUST be in the signal index range (see QObjectPrivate::signalIndex()). + This is different from QMetaMethod::methodIndex(). +*/ +QQmlBoundSignal::QQmlBoundSignal(QObject *target, int signal, QObject *owner, + QQmlEngine *engine) + : QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlBoundSignal), + m_prevSignal(0), m_nextSignal(0), + m_expression(0) { + addToObject(owner); + + /* + If this is a cloned method, connect to the 'original'. For example, + for the signal 'void aSignal(int parameter = 0)', if the method + index refers to 'aSignal()', get the index of 'aSignal(int)'. + This ensures that 'parameter' will be available from QML. + */ + signal = QQmlPropertyCache::originalClone(target, signal); + QQmlNotifierEndpoint::connect(target, signal, engine); } -QQmlAbstractBoundSignal::~QQmlAbstractBoundSignal() +QQmlBoundSignal::~QQmlBoundSignal() { removeFromObject(); } -void QQmlAbstractBoundSignal::addToObject(QObject *obj) +void QQmlBoundSignal::addToObject(QObject *obj) { Q_ASSERT(!m_prevSignal); Q_ASSERT(obj); @@ -308,7 +282,7 @@ void QQmlAbstractBoundSignal::addToObject(QObject *obj) data->signalHandlers = this; } -void QQmlAbstractBoundSignal::removeFromObject() +void QQmlBoundSignal::removeFromObject() { if (m_prevSignal) { *m_prevSignal = m_nextSignal; @@ -318,40 +292,6 @@ void QQmlAbstractBoundSignal::removeFromObject() } } -/*! \internal - \a signal MUST be in the signal index range (see QObjectPrivate::signalIndex()). - This is different from QMetaMethod::methodIndex(). -*/ -QQmlBoundSignal::QQmlBoundSignal(QObject *target, int signal, QObject *owner, - QQmlEngine *engine) -: m_expression(0), m_index(signal), m_isEvaluating(false) -{ - addToObject(owner); - setCallback(QQmlNotifierEndpoint::QQmlBoundSignal); - - /* - If this is a cloned method, connect to the 'original'. For example, - for the signal 'void aSignal(int parameter = 0)', if the method - index refers to 'aSignal()', get the index of 'aSignal(int)'. - This ensures that 'parameter' will be available from QML. - */ - m_index = QQmlPropertyCache::originalClone(target, m_index); - QQmlNotifierEndpoint::connect(target, m_index, engine); -} - -QQmlBoundSignal::~QQmlBoundSignal() -{ - m_expression = 0; -} - -/*! - Returns the signal index in the range returned by QObjectPrivate::signalIndex(). - This is different from QMetaMethod::methodIndex(). -*/ -int QQmlBoundSignal::index() const -{ - return m_index; -} /*! Returns the signal expression. @@ -362,45 +302,29 @@ QQmlBoundSignalExpression *QQmlBoundSignal::expression() const } /*! - Sets the signal expression to \a e. Returns the current signal expression, - or null if there is no signal expression. + Sets the signal expression to \a e. - The QQmlBoundSignal instance adds a reference to \a e. The caller - assumes ownership of the returned QQmlBoundSignalExpression reference. + The QQmlBoundSignal instance takes ownership of \a e (and does not add a reference). */ -QQmlBoundSignalExpressionPointer QQmlBoundSignal::setExpression(QQmlBoundSignalExpression *e) +void QQmlBoundSignal::takeExpression(QQmlBoundSignalExpression *e) { - QQmlBoundSignalExpressionPointer rv = m_expression; - m_expression = e; - if (m_expression) m_expression->setNotifyOnValueChanged(false); - return rv; -} - -/*! - Sets the signal expression to \a e. Returns the current signal expression, - or null if there is no signal expression. - - The QQmlBoundSignal instance takes ownership of \a e (and does not add a reference). The caller - assumes ownership of the returned QQmlBoundSignalExpression reference. -*/ -QQmlBoundSignalExpressionPointer QQmlBoundSignal::takeExpression(QQmlBoundSignalExpression *e) -{ - QQmlBoundSignalExpressionPointer rv = m_expression; m_expression.take(e); - if (m_expression) m_expression->setNotifyOnValueChanged(false); - return rv; + if (m_expression) + m_expression->setNotifyOnValueChanged(false); } void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a) { QQmlBoundSignal *s = static_cast<QQmlBoundSignal*>(e); + if (!s->m_expression) return; - if (QQmlDebugService::isDebuggingEnabled()) - QV4DebugService::instance()->signalEmitted(QString::fromLatin1(QMetaObjectPrivate::signal(s->m_expression->target()->metaObject(), s->m_index).methodSignature())); - - s->m_isEvaluating = true; + QV4DebugService *service = QQmlDebugConnector::service<QV4DebugService>(); + if (service) + service->signalEmitted(QString::fromLatin1(QMetaObjectPrivate::signal( + s->m_expression->target()->metaObject(), + s->signalIndex()).methodSignature())); QQmlEngine *engine; if (s->m_expression && (engine = s->m_expression->engine())) { @@ -410,8 +334,6 @@ void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a) QQmlEnginePrivate::warning(engine, s->m_expression->error(engine)); } } - - s->m_isEvaluating = false; } //////////////////////////////////////////////////////////////////////// diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h index 8d677ea039..3742317484 100644 --- a/src/qml/qml/qqmlboundsignal_p.h +++ b/src/qml/qml/qqmlboundsignal_p.h @@ -47,7 +47,6 @@ #include <QtCore/qmetaobject.h> -#include <private/qqmlabstractexpression_p.h> #include <private/qqmljavascriptexpression_p.h> #include <private/qqmlboundsignalexpressionpointer_p.h> #include <private/qqmlnotifier_p.h> @@ -58,7 +57,7 @@ QT_BEGIN_NAMESPACE -class Q_QML_PRIVATE_EXPORT QQmlBoundSignalExpression : public QQmlAbstractExpression, public QQmlJavaScriptExpression, public QQmlRefCount +class Q_QML_PRIVATE_EXPORT QQmlBoundSignalExpression : public QQmlJavaScriptExpression, public QQmlRefCount { public: QQmlBoundSignalExpression(QObject *target, int index, @@ -73,9 +72,9 @@ public: QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction); - // "inherited" from QQmlJavaScriptExpression. - static QString expressionIdentifier(QQmlJavaScriptExpression *); - static void expressionChanged(QQmlJavaScriptExpression *); + // inherited from QQmlJavaScriptExpression. + virtual QString expressionIdentifier(); + virtual void expressionChanged(); // evaluation of a bound signal expression doesn't return any value void evaluate(void **a); @@ -92,80 +91,35 @@ private: void init(QQmlContextData *ctxt, QObject *scope); - bool expressionFunctionValid() const { return m_extra.flag(); } - void setExpressionFunctionValid(bool v) { m_extra.setFlagValue(v); } - - bool invalidParameterName() const { return m_extra.flag2(); } - void setInvalidParameterName(bool v) { m_extra.setFlag2Value(v); } + bool expressionFunctionValid() const { return !m_function.isNullOrUndefined(); } int m_index; - QV4::PersistentValue m_function; - QObject *m_target; - - // only needed when !expressionFunctionValid() - struct ExtraData { - ExtraData(const QString &handlerName, const QString ¶meterString, - const QString &expression, const QString &fileName, - quint16 line, quint16 column); - QString m_handlerName; - QString m_parameterString; - QString m_expression; - QQmlSourceLocation m_sourceLocation; - QV4::PersistentValue m_v8qmlscope; - }; - - // We store some flag bits in the following flag pointers. - // flag - expressionFunctionValid - // flag2 - invalidParameterName - QFlagPointer<ExtraData> m_extra; }; -class Q_QML_PRIVATE_EXPORT QQmlAbstractBoundSignal +class Q_QML_PRIVATE_EXPORT QQmlBoundSignal : public QQmlNotifierEndpoint { public: - QQmlAbstractBoundSignal(); - virtual ~QQmlAbstractBoundSignal(); - - virtual int index() const = 0; - virtual QQmlBoundSignalExpression *expression() const = 0; - virtual QQmlBoundSignalExpressionPointer setExpression(QQmlBoundSignalExpression *) = 0; - virtual QQmlBoundSignalExpressionPointer takeExpression(QQmlBoundSignalExpression *) = 0; - virtual bool isEvaluating() const = 0; + QQmlBoundSignal(QObject *target, int signal, QObject *owner, QQmlEngine *engine); + ~QQmlBoundSignal(); void removeFromObject(); -protected: - void addToObject(QObject *owner); + + QQmlBoundSignalExpression *expression() const; + void takeExpression(QQmlBoundSignalExpression *); private: - friend class QQmlData; + friend void QQmlBoundSignal_callback(QQmlNotifierEndpoint *, void **); friend class QQmlPropertyPrivate; + friend class QQmlData; friend class QQmlEngineDebugService; - QQmlAbstractBoundSignal **m_prevSignal; - QQmlAbstractBoundSignal *m_nextSignal; -}; -class Q_QML_PRIVATE_EXPORT QQmlBoundSignal : public QQmlAbstractBoundSignal, - public QQmlNotifierEndpoint -{ -public: - QQmlBoundSignal(QObject *target, int signal, QObject *owner, QQmlEngine *engine); - virtual ~QQmlBoundSignal(); - - int index() const; - - QQmlBoundSignalExpression *expression() const; - QQmlBoundSignalExpressionPointer setExpression(QQmlBoundSignalExpression *); - QQmlBoundSignalExpressionPointer takeExpression(QQmlBoundSignalExpression *); + void addToObject(QObject *owner); - bool isEvaluating() const { return m_isEvaluating; } - -private: - friend void QQmlBoundSignal_callback(QQmlNotifierEndpoint *, void **); + QQmlBoundSignal **m_prevSignal; + QQmlBoundSignal *m_nextSignal; QQmlBoundSignalExpressionPointer m_expression; - int m_index; - bool m_isEvaluating; }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 9210610cec..d62aada9c6 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -43,7 +43,8 @@ #include "qqmlengine.h" #include "qqmlbinding_p.h" #include "qqmlglobal_p.h" -#include <private/qqmlenginedebugservice_p.h> +#include <private/qqmldebugconnector_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> #include "qqmlincubator.h" #include "qqmlincubator_p.h" #include <private/qqmljavascriptexpression_p.h> @@ -53,6 +54,7 @@ #include <private/qv4functionobject_p.h> #include <private/qv4script_p.h> #include <private/qv4scopedvalue_p.h> +#include <private/qv4objectiterator_p.h> #include <QStack> #include <QStringList> @@ -61,23 +63,6 @@ #include <qqmlinfo.h> #include "qqmlmemoryprofiler_p.h" -#define INITIALPROPERTIES_SOURCE \ - "(function(object, values) {"\ - "try {"\ - "for (var property in values) {" \ - "try {"\ - "var properties = property.split(\".\");"\ - "var o = object;"\ - "for (var ii = 0; ii < properties.length - 1; ++ii) {"\ - "o = o[properties[ii]];"\ - "}"\ - "o[properties[properties.length - 1]] = values[property];"\ - "} catch(e) {}"\ - "}"\ - "} catch(e) {}"\ - "})" - - namespace { QThreadStorage<int> creationDepth; } @@ -98,7 +83,6 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension); \class QQmlComponent \since 5.0 \inmodule QtQml - \mainclass \brief The QQmlComponent class encapsulates a QML component definition @@ -896,10 +880,11 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context) depthIncreased = false; } - if (enginePriv->isDebugging && rv) { + QQmlEngineDebugService *service = QQmlDebugConnector::service<QQmlEngineDebugService>(); + if (service && rv) { if (!context->isInternal) context->asQQmlContextPrivate()->instances.append(rv); - QQmlEngineDebugService::instance()->objectCreated(engine, rv); + service->objectCreated(engine, rv); } return rv; @@ -1194,6 +1179,46 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent) \sa incubateObject() */ + +static void setInitialProperties(QV4::ExecutionEngine *engine, const QV4::Value &o, const QV4::Value &v) +{ + QV4::Scope scope(engine); + QV4::ScopedObject object(scope); + QV4::ScopedObject valueMap(scope, v); + QV4::ObjectIterator it(scope, valueMap, QV4::ObjectIterator::EnumerableOnly|QV4::ObjectIterator::WithProtoChain); + QV4::ScopedString name(scope); + QV4::ScopedValue val(scope); + if (engine->hasException) + return; + + while (1) { + name = it.nextPropertyNameAsString(val); + if (!name) + break; + object = o; + const QStringList properties = name->toQString().split(QLatin1Char('.')); + for (int i = 0; i < properties.length() - 1; ++i) { + name = engine->newString(properties.at(i)); + object = object->get(name); + if (engine->hasException || !object) { + break; + } + } + if (engine->hasException || !object) { + engine->hasException = false; + continue; + } + name = engine->newString(properties.last()); + object->put(name, val); + if (engine->hasException) { + engine->hasException = false; + continue; + } + } + + engine->hasException = false; +} + /*! \internal */ @@ -1216,7 +1241,7 @@ void QQmlComponent::createObject(QQmlV4Function *args) if (args->length() >= 2) { QV4::ScopedValue v(scope, (*args)[1]); - if (!v->asObject() || v->asArrayObject()) { + if (!v->as<QV4::Object>() || v->as<QV4::ArrayObject>()) { qmlInfo(this) << tr("createObject: value is not an object"); args->setReturnValue(QV4::Encode::null()); return; @@ -1239,16 +1264,8 @@ void QQmlComponent::createObject(QQmlV4Function *args) QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(v4, rv)); Q_ASSERT(object->isObject()); - if (!valuemap->isUndefined()) { - QV4::ScopedObject qmlglobal(scope, args->qmlGlobal()); - QV4::ScopedValue f(scope, QV4::Script::evaluate(v4, QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlglobal)); - Q_ASSERT(f->asFunctionObject()); - QV4::ScopedCallData callData(scope, 2); - callData->thisObject = v4->globalObject(); - callData->args[0] = object; - callData->args[1] = valuemap; - f->asFunctionObject()->call(callData); - } + if (!valuemap->isUndefined()) + setInitialProperties(v4, object, valuemap); d->completeCreate(); @@ -1256,10 +1273,7 @@ void QQmlComponent::createObject(QQmlV4Function *args) QQmlData::get(rv)->explicitIndestructibleSet = false; QQmlData::get(rv)->indestructible = false; - if (!rv) - args->setReturnValue(QV4::Encode::null()); - else - args->setReturnValue(object->asReturnedValue()); + args->setReturnValue(object->asReturnedValue()); } /*! @@ -1342,7 +1356,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) if (args->length() >= 2) { QV4::ScopedValue v(scope, (*args)[1]); if (v->isNull()) { - } else if (!v->asObject() || v->asArrayObject()) { + } else if (!v->as<QV4::Object>() || v->as<QV4::ArrayObject>()) { qmlInfo(this) << tr("createObject: value is not an object"); args->setReturnValue(QV4::Encode::null()); return; @@ -1383,25 +1397,17 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) } // XXX used by QSGLoader -void QQmlComponentPrivate::initializeObjectWithInitialProperties(const QV4::Value &qmlGlobal, const QV4::Value &valuemap, QObject *toCreate) +void QQmlComponentPrivate::initializeObjectWithInitialProperties(const QV4::Value &valuemap, QObject *toCreate) { QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); QV4::ExecutionEngine *v4engine = QV8Engine::getV4(ep->v8engine()); QV4::Scope scope(v4engine); QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(v4engine, toCreate)); - Q_ASSERT(object->asObject()); - - if (!valuemap.isUndefined()) { - QV4::ScopedObject qmlGlobalObj(scope, qmlGlobal); - QV4::ScopedFunctionObject f(scope, QV4::Script::evaluate(v4engine, - QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlGlobalObj)); - QV4::ScopedCallData callData(scope, 2); - callData->thisObject = v4engine->globalObject(); - callData->args[0] = object; - callData->args[1] = valuemap; - f->call(callData); - } + Q_ASSERT(object->as<QV4::Object>()); + + if (!valuemap.isUndefined()) + setInitialProperties(v4engine, object, valuemap); } QQmlComponentExtension::QQmlComponentExtension(QV4::ExecutionEngine *v4) @@ -1491,13 +1497,8 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o) if (!d()->valuemap.isUndefined()) { QV4::ExecutionEngine *v4 = engine(); QV4::Scope scope(v4); - - QV4::ScopedFunctionObject f(scope, QV4::Script::evaluate(v4, QString::fromLatin1(INITIALPROPERTIES_SOURCE), d()->qmlGlobal.asObject())); - QV4::ScopedCallData callData(scope, 2); - callData->thisObject = v4->globalObject(); - callData->args[0] = QV4::QObjectWrapper::wrap(v4, o); - callData->args[1] = d()->valuemap; - f->call(callData); + QV4::ScopedObject obj(scope, QV4::QObjectWrapper::wrap(v4, o)); + setInitialProperties(v4, obj, d()->valuemap); } } diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h index 8c866c585a..121c83db5c 100644 --- a/src/qml/qml/qqmlcomponent.h +++ b/src/qml/qml/qqmlcomponent.h @@ -63,8 +63,8 @@ class Q_QML_EXPORT QQmlComponent : public QObject Q_PROPERTY(QUrl url READ url CONSTANT) public: - Q_ENUMS(CompilationMode) enum CompilationMode { PreferSynchronous, Asynchronous }; + Q_ENUM(CompilationMode) QQmlComponent(QObject *parent = 0); QQmlComponent(QQmlEngine *, QObject *parent=0); @@ -74,8 +74,8 @@ public: QQmlComponent(QQmlEngine *, const QUrl &url, CompilationMode mode, QObject *parent = 0); virtual ~QQmlComponent(); - Q_ENUMS(Status) enum Status { Null, Ready, Loading, Error }; + Q_ENUM(Status) Status status() const; bool isNull() const; @@ -125,7 +125,6 @@ private: QT_END_NAMESPACE -Q_DECLARE_METATYPE(QQmlComponent::Status) QML_DECLARE_TYPE(QQmlComponent) QML_DECLARE_TYPEINFO(QQmlComponent, QML_HAS_ATTACHED_PROPERTIES) diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index adc6e173d2..15ec88dd52 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -82,7 +82,7 @@ public: QObject *beginCreate(QQmlContextData *); void completeCreate(); - void initializeObjectWithInitialProperties(const QV4::Value &qmlGlobal, const QV4::Value &valuemap, QObject *toCreate); + void initializeObjectWithInitialProperties(const QV4::Value &valuemap, QObject *toCreate); QQmlTypeData *typeData; virtual void typeDataReady(QQmlTypeData *); diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index fb51bad3a7..b056731e96 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -57,7 +57,6 @@ QQmlContextPrivate::QQmlContextPrivate() /*! \class QQmlContext \brief The QQmlContext class defines a context within a QML engine. - \mainclass \inmodule QtQml Contexts allow data to be exposed to the QML components instantiated by the @@ -585,9 +584,9 @@ void QQmlContextData::clearContext() { emitDestruction(); - QQmlAbstractExpression *expression = expressions; + QQmlJavaScriptExpression *expression = expressions; while (expression) { - QQmlAbstractExpression *nextExpression = expression->m_nextExpression; + QQmlJavaScriptExpression *nextExpression = expression->m_nextExpression; expression->m_prevExpression = 0; expression->m_nextExpression = 0; @@ -652,9 +651,9 @@ void QQmlContextData::setParent(QQmlContextData *p, bool parentTakesOwnership) } } -void QQmlContextData::refreshExpressionsRecursive(QQmlAbstractExpression *expression) +void QQmlContextData::refreshExpressionsRecursive(QQmlJavaScriptExpression *expression) { - QQmlAbstractExpression::DeleteWatcher w(expression); + QQmlJavaScriptExpression::DeleteWatcher w(expression); if (expression->m_nextExpression) refreshExpressionsRecursive(expression->m_nextExpression); @@ -808,7 +807,7 @@ QV4::IdentifierHash<int> &QQmlContextData::propertyNames() const { if (propertyNameCache.isEmpty()) { propertyNameCache = QV4::IdentifierHash<int>(QV8Engine::getV4(engine->handle())); - for (QHash<int, int>::ConstIterator it = objectIndexToId.begin(), end = objectIndexToId.end(); + for (QHash<int, int>::ConstIterator it = objectIndexToId.cbegin(), end = objectIndexToId.cend(); it != end; ++it) { const QV4::CompiledData::Object *obj = typeCompilationUnit->data->objectAt(it.key()); const QString name = typeCompilationUnit->data->stringAt(obj->idIndex); diff --git a/src/qml/qml/qqmlcontext.h b/src/qml/qml/qqmlcontext.h index c714846147..e69a2f8f69 100644 --- a/src/qml/qml/qqmlcontext.h +++ b/src/qml/qml/qqmlcontext.h @@ -72,6 +72,7 @@ public: void setContextProperty(const QString &, QObject *); void setContextProperty(const QString &, const QVariant &); + // ### Qt 6: no need for a mutable object, this should become a const QObject pointer QString nameForObject(QObject *) const; QUrl resolvedUrl(const QUrl &); diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h index f5fd7d0a5c..95254d4baa 100644 --- a/src/qml/qml/qqmlcontext_p.h +++ b/src/qml/qml/qqmlcontext_p.h @@ -69,7 +69,7 @@ class QQmlExpression; class QQmlEngine; class QQmlExpression; class QQmlExpressionPrivate; -class QQmlAbstractExpression; +class QQmlJavaScriptExpression; class QQmlContextData; class QQmlContextPrivate : public QObjectPrivate @@ -171,7 +171,7 @@ public: QQmlContextData **prevChild; // Expressions that use this context - QQmlAbstractExpression *expressions; + QQmlJavaScriptExpression *expressions; // Doubly-linked list of objects that are owned by this context QQmlData *contextObjects; @@ -212,7 +212,7 @@ public: private: void refreshExpressionsRecursive(bool isGlobal); - void refreshExpressionsRecursive(QQmlAbstractExpression *); + void refreshExpressionsRecursive(QQmlJavaScriptExpression *); ~QQmlContextData() {} }; diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp index 5844eab54f..23084fb202 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/qml/qqmlcontextwrapper.cpp @@ -38,13 +38,14 @@ #include <private/qqmlcontext_p.h> #include <private/qv4engine_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4objectproto_p.h> #include <private/qv4mm_p.h> #include <private/qv4function_p.h> #include <private/qv4compileddata_p.h> #include <private/qqmltypewrapper_p.h> #include <private/qqmllistwrapper_p.h> +#include <private/qqmljavascriptexpression_p.h> #include <private/qjsvalue_p.h> QT_BEGIN_NAMESPACE @@ -60,7 +61,6 @@ Heap::QmlContextWrapper::QmlContextWrapper(QV4::ExecutionEngine *engine, QQmlCon , isNullWrapper(false) , context(context) , scopeObject(scopeObject) - , idObjectsWrapper(Q_NULLPTR) { } @@ -93,49 +93,30 @@ ReturnedValue QmlContextWrapper::urlScope(ExecutionEngine *v4, const QUrl &url) return w.asReturnedValue(); } -QQmlContextData *QmlContextWrapper::callingContext(ExecutionEngine *v4) -{ - Scope scope(v4); - QV4::Scoped<QmlContextWrapper> c(scope, v4->qmlContextObject()); - - return !!c ? c->getContext() : 0; -} - QQmlContextData *QmlContextWrapper::getContext(const Value &value) { if (!value.isObject()) return 0; - QV4::ExecutionEngine *v4 = value.asObject()->engine(); + QV4::ExecutionEngine *v4 = value.as<Object>()->engine(); Scope scope(v4); QV4::Scoped<QmlContextWrapper> c(scope, value); return c ? c->getContext() : 0; } -void QmlContextWrapper::takeContextOwnership(const Value &qmlglobal) -{ - Q_ASSERT(qmlglobal.isObject()); - - QV4::ExecutionEngine *v4 = qmlglobal.asObject()->engine(); - Scope scope(v4); - QV4::Scoped<QmlContextWrapper> c(scope, qmlglobal); - Q_ASSERT(c); - c->d()->ownsContext = true; -} - -ReturnedValue QmlContextWrapper::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QmlContextWrapper>()); - QmlContextWrapper *resource = static_cast<QmlContextWrapper *>(m); + const QmlContextWrapper *resource = static_cast<const QmlContextWrapper *>(m); QV4::ExecutionEngine *v4 = resource->engine(); QV4::Scope scope(v4); // In V8 the JS global object would come _before_ the QML global object, // so simulate that here. bool hasProp; - QV4::ScopedValue result(scope, v4->globalObject()->get(name, &hasProp)); + QV4::ScopedValue result(scope, v4->globalObject->get(name, &hasProp)); if (hasProp) { if (hasProperty) *hasProperty = hasProp; @@ -145,7 +126,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, String *name, bool *hasProperty if (resource->d()->isNullWrapper) return Object::get(m, name, hasProperty); - if (QV4::QmlContextWrapper::callingContext(v4) != resource->d()->context) + if (v4->callingQmlContext() != resource->d()->context) return Object::get(m, name, hasProperty); result = Object::get(m, name, &hasProp); @@ -209,7 +190,8 @@ ReturnedValue QmlContextWrapper::get(Managed *m, String *name, bool *hasProperty if (propertyIdx < context->idValueCount) { - ep->captureProperty(&context->idValues[propertyIdx].bindings); + if (ep->propertyCapture) + ep->propertyCapture->captureProperty(&context->idValues[propertyIdx].bindings); if (hasProperty) *hasProperty = true; return QV4::QObjectWrapper::wrap(v4, context->idValues[propertyIdx]); @@ -217,8 +199,8 @@ ReturnedValue QmlContextWrapper::get(Managed *m, String *name, bool *hasProperty QQmlContextPrivate *cp = context->asQQmlContextPrivate(); - ep->captureProperty(context->asQQmlContext(), -1, - propertyIdx + cp->notifyIndex); + if (ep->propertyCapture) + ep->propertyCapture->captureProperty(context->asQQmlContext(), -1, propertyIdx + cp->notifyIndex); const QVariant &value = cp->propertyValues.at(propertyIdx); if (hasProperty) @@ -278,10 +260,9 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) return; QV4::Scoped<QmlContextWrapper> wrapper(scope, resource); - PropertyAttributes attrs; - Property *pd = wrapper->__getOwnProperty__(name, &attrs); - if (pd) { - wrapper->putValue(pd, attrs, value); + uint member = wrapper->internalClass()->find(name); + if (member < UINT_MAX) { + wrapper->putValue(wrapper->propertyAt(member), wrapper->internalClass()->propertyData[member], value); return; } @@ -342,14 +323,6 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) Object::put(m, name, value); } -void QmlContextWrapper::markObjects(Heap::Base *m, ExecutionEngine *engine) -{ - QmlContextWrapper::Data *This = static_cast<QmlContextWrapper::Data *>(m); - if (This->idObjectsWrapper) - This->idObjectsWrapper->mark(engine); - Object::markObjects(m, engine); -} - void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const CompiledData::Function *compiledFunction) { // Let the caller check and avoid the function call :) @@ -358,13 +331,13 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; if (!ep) return; - QQmlEnginePrivate::PropertyCapture *capture = ep->propertyCapture; + QQmlPropertyCapture *capture = ep->propertyCapture; if (!capture) return; QV4::Scope scope(engine); - QV4::Scoped<QmlContextWrapper> contextWrapper(scope, engine->qmlContextObject()); - QQmlContextData *qmlContext = contextWrapper->getContext(); + QV4::Scoped<QmlContext> context(scope, engine->qmlContext()); + QQmlContextData *qmlContext = context->qmlContext(); const quint32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable(); const int idObjectDependencyCount = compiledFunction->nDependingIdObjects; @@ -382,7 +355,7 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C capture->captureProperty(qmlContext->contextObject, propertyIndex, notifyIndex); } - QObject *scopeObject = contextWrapper->getScopeObject(); + QObject *scopeObject = context->qmlScope(); const quint32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable(); const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties; for (int i = 0; i < scopePropertyDependencyCount; ++i) { @@ -393,15 +366,6 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C } -ReturnedValue QmlContextWrapper::idObjectsArray() -{ - if (!d()->idObjectsWrapper) { - ExecutionEngine *v4 = engine(); - d()->idObjectsWrapper = v4->memoryManager->alloc<QQmlIdObjectsArray>(v4, this); - } - return d()->idObjectsWrapper->asReturnedValue(); -} - ReturnedValue QmlContextWrapper::qmlSingletonWrapper(ExecutionEngine *v4, String *name) { if (!d()->context->imports) @@ -423,46 +387,4 @@ ReturnedValue QmlContextWrapper::qmlSingletonWrapper(ExecutionEngine *v4, String return QJSValuePrivate::convertedToValue(engine(), siinfo->scriptApi(e)); } -DEFINE_OBJECT_VTABLE(QQmlIdObjectsArray); - -Heap::QQmlIdObjectsArray::QQmlIdObjectsArray(ExecutionEngine *engine, QV4::QmlContextWrapper *contextWrapper) - : Heap::Object(engine) - , contextWrapper(contextWrapper->d()) -{ -} - -ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasProperty) -{ - Scope scope(static_cast<QV4::QQmlIdObjectsArray*>(m)->engine()); - Scoped<QQmlIdObjectsArray> This(scope, static_cast<QV4::QQmlIdObjectsArray*>(m)); - Scoped<QmlContextWrapper> contextWrapper(scope, This->d()->contextWrapper); - QQmlContextData *context = contextWrapper->getContext(); - if (!context) { - if (hasProperty) - *hasProperty = false; - return Encode::undefined(); - } - if (index >= (uint)context->idValueCount) { - if (hasProperty) - *hasProperty = false; - return Encode::undefined(); - } - - if (hasProperty) - *hasProperty = true; - - QQmlEnginePrivate *ep = scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : 0; - if (ep) - ep->captureProperty(&context->idValues[index].bindings); - - return QObjectWrapper::wrap(This->engine(), context->idValues[index].data()); -} - -void QQmlIdObjectsArray::markObjects(Heap::Base *that, ExecutionEngine *engine) -{ - QQmlIdObjectsArray::Data *This = static_cast<QQmlIdObjectsArray::Data *>(that); - This->contextWrapper->mark(engine); - Object::markObjects(that, engine); -} - QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h index 52d8677103..7b5d3216df 100644 --- a/src/qml/qml/qqmlcontextwrapper_p.h +++ b/src/qml/qml/qqmlcontextwrapper_p.h @@ -48,7 +48,7 @@ #include <QtCore/qglobal.h> #include <private/qtqmlglobal_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> #include <private/qqmlcontext_p.h> #include <private/qv4functionobject_p.h> @@ -65,8 +65,6 @@ struct QmlContextWrapper; namespace Heap { -struct QQmlIdObjectsArray; - struct QmlContextWrapper : Object { QmlContextWrapper(ExecutionEngine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext = false); ~QmlContextWrapper(); @@ -76,12 +74,6 @@ struct QmlContextWrapper : Object { QQmlGuardedContextData context; QPointer<QObject> scopeObject; - QQmlIdObjectsArray *idObjectsWrapper; -}; - -struct QQmlIdObjectsArray : Object { - QQmlIdObjectsArray(QV4::ExecutionEngine *engine, QV4::QmlContextWrapper *contextWrapper); - QmlContextWrapper *contextWrapper; }; } @@ -94,8 +86,9 @@ struct Q_QML_EXPORT QmlContextWrapper : Object static ReturnedValue qmlScope(ExecutionEngine *e, QQmlContextData *ctxt, QObject *scope); static ReturnedValue urlScope(ExecutionEngine *v4, const QUrl &); - static QQmlContextData *callingContext(ExecutionEngine *v4); - static void takeContextOwnership(const Value &qmlglobal); + void takeContextOwnership() { + d()->ownsContext = true; + } inline QObject *getScopeObject() const { return d()->scopeObject; } inline QQmlContextData *getContext() const { return d()->context; } @@ -103,24 +96,12 @@ struct Q_QML_EXPORT QmlContextWrapper : Object void setReadOnly(bool b) { d()->readOnly = b; } - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); - static void markObjects(Heap::Base *m, ExecutionEngine *engine); static void registerQmlDependencies(ExecutionEngine *context, const CompiledData::Function *compiledFunction); - ReturnedValue idObjectsArray(); ReturnedValue qmlSingletonWrapper(ExecutionEngine *e, String *name); - -}; - -struct QQmlIdObjectsArray : public Object -{ - V4_OBJECT2(QQmlIdObjectsArray, Object) - - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); - static void markObjects(Heap::Base *that, ExecutionEngine *engine); - }; } diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index 04c42b638d..3d2a76693a 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -48,8 +48,9 @@ #include <private/qtqmlglobal_p.h> #include <private/qobject_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4persistent_p.h> +#include <qjsengine.h> QT_BEGIN_NAMESPACE @@ -58,7 +59,7 @@ class QQmlEngine; class QQmlGuardImpl; class QQmlCompiledData; class QQmlAbstractBinding; -class QQmlAbstractBoundSignal; +class QQmlBoundSignal; class QQmlContext; class QQmlPropertyCache; class QQmlContextData; @@ -72,15 +73,7 @@ class QQmlNotifierEndpoint; class Q_QML_PRIVATE_EXPORT QQmlData : public QAbstractDeclarativeData { public: - QQmlData() - : ownedByQml1(false), ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false), - hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false), - hasVMEMetaObject(false), parentFrozen(false), bindingBitsSize(0), bindingBits(0), notifyList(0), context(0), outerContext(0), - bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0), - lineNumber(0), columnNumber(0), jsEngineId(0), compiledData(0), deferredData(0), - propertyCache(0), guards(0), extendedData(0) { - init(); - } + QQmlData(); static inline void init() { static bool initialized = false; @@ -158,7 +151,7 @@ public: QQmlContextData *outerContext; QQmlAbstractBinding *bindings; - QQmlAbstractBoundSignal *signalHandlers; + QQmlBoundSignal *signalHandlers; // Linked list for QQmlContext::contextObjects QQmlData *nextContextObject; diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp index 7f6310d58e..57b50733ea 100644 --- a/src/qml/qml/qqmldirparser.cpp +++ b/src/qml/qml/qqmldirparser.cpp @@ -146,7 +146,7 @@ bool QQmlDirParser::parse(const QString &source) if (invalidLine) { reportError(lineNumber, 0, - QString::fromLatin1("invalid qmldir directive contains too many tokens")); + QStringLiteral("invalid qmldir directive contains too many tokens")); continue; } else if (sectionCount == 0) { continue; // no sections, no party. @@ -154,17 +154,17 @@ bool QQmlDirParser::parse(const QString &source) } else if (sections[0] == QLatin1String("module")) { if (sectionCount != 2) { reportError(lineNumber, 0, - QString::fromLatin1("module identifier directive requires one argument, but %1 were provided").arg(sectionCount - 1)); + QStringLiteral("module identifier directive requires one argument, but %1 were provided").arg(sectionCount - 1)); continue; } if (!_typeNamespace.isEmpty()) { reportError(lineNumber, 0, - QString::fromLatin1("only one module identifier directive may be defined in a qmldir file")); + QStringLiteral("only one module identifier directive may be defined in a qmldir file")); continue; } if (!firstLine) { reportError(lineNumber, 0, - QString::fromLatin1("module identifier directive must be the first directive in a qmldir file")); + QStringLiteral("module identifier directive must be the first directive in a qmldir file")); continue; } @@ -173,7 +173,7 @@ bool QQmlDirParser::parse(const QString &source) } else if (sections[0] == QLatin1String("plugin")) { if (sectionCount < 2 || sectionCount > 3) { reportError(lineNumber, 0, - QString::fromLatin1("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1)); + QStringLiteral("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1)); continue; } @@ -185,7 +185,7 @@ bool QQmlDirParser::parse(const QString &source) } else if (sections[0] == QLatin1String("internal")) { if (sectionCount != 3) { reportError(lineNumber, 0, - QString::fromLatin1("internal types require 2 arguments, but %1 were provided").arg(sectionCount - 1)); + QStringLiteral("internal types require 2 arguments, but %1 were provided").arg(sectionCount - 1)); continue; } Component entry(sections[1], sections[2], -1, -1); @@ -194,7 +194,7 @@ bool QQmlDirParser::parse(const QString &source) } else if (sections[0] == QLatin1String("singleton")) { if (sectionCount < 3 || sectionCount > 4) { reportError(lineNumber, 0, - QString::fromLatin1("singleton types require 2 or 3 arguments, but %1 were provided").arg(sectionCount - 1)); + QStringLiteral("singleton types require 2 or 3 arguments, but %1 were provided").arg(sectionCount - 1)); continue; } else if (sectionCount == 3) { // handle qmldir directory listing case where singleton is defined in the following pattern: @@ -218,7 +218,7 @@ bool QQmlDirParser::parse(const QString &source) } else if (sections[0] == QLatin1String("typeinfo")) { if (sectionCount != 2) { reportError(lineNumber, 0, - QString::fromLatin1("typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1)); + QStringLiteral("typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1)); continue; } #ifdef QT_CREATOR @@ -228,13 +228,13 @@ bool QQmlDirParser::parse(const QString &source) } else if (sections[0] == QLatin1String("designersupported")) { if (sectionCount != 1) - reportError(lineNumber, 0, QString::fromLatin1("designersupported does not expect any argument")); + reportError(lineNumber, 0, QStringLiteral("designersupported does not expect any argument")); else _designerSupported = true; } else if (sections[0] == QLatin1String("depends")) { if (sectionCount != 3) { reportError(lineNumber, 0, - QString::fromLatin1("depends requires 2 arguments, but %1 were provided").arg(sectionCount - 1)); + QStringLiteral("depends requires 2 arguments, but %1 were provided").arg(sectionCount - 1)); continue; } @@ -268,7 +268,7 @@ bool QQmlDirParser::parse(const QString &source) } } else { reportError(lineNumber, 0, - QString::fromLatin1("a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount)); + QStringLiteral("a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount)); } firstLine = false; @@ -304,7 +304,9 @@ QList<QQmlError> QQmlDirParser::errors(const QString &uri) const { QUrl url(uri); QList<QQmlError> errors; - for (int i = 0; i < _errors.size(); ++i) { + const int numErrors = _errors.size(); + errors.reserve(numErrors); + for (int i = 0; i < numErrors; ++i) { const QQmlJS::DiagnosticMessage &msg = _errors.at(i); QQmlError e; QString description = msg.message; @@ -362,14 +364,14 @@ bool QQmlDirParser::designerSupported() const QDebug &operator<< (QDebug &debug, const QQmlDirParser::Component &component) { - const QString output = QString::fromLatin1("{%1 %2.%3}"). + const QString output = QStringLiteral("{%1 %2.%3}"). arg(component.typeName).arg(component.majorVersion).arg(component.minorVersion); return debug << qPrintable(output); } QDebug &operator<< (QDebug &debug, const QQmlDirParser::Script &script) { - const QString output = QString::fromLatin1("{%1 %2.%3}"). + const QString output = QStringLiteral("{%1 %2.%3}"). arg(script.nameSpace).arg(script.majorVersion).arg(script.minorVersion); return debug << qPrintable(output); } diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index ffc890a2cf..9c5e48ae32 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -42,7 +42,6 @@ #include "qqmlexpression.h" #include "qqmlcomponent.h" #include "qqmlvme_p.h" -#include <private/qqmlenginedebugservice_p.h> #include "qqmlstringconverters_p.h" #include "qqmlxmlhttprequest_p.h" #include "qqmlscriptstring.h" @@ -54,11 +53,7 @@ #include "qqmllist_p.h" #include "qqmltypenamecache_p.h" #include "qqmlnotifier_p.h" -#include <private/qqmldebugserver_p.h> -#include <private/qqmlprofilerservice_p.h> -#include <private/qv4debugservice_p.h> -#include <private/qdebugmessageservice_p.h> -#include <private/qqmlenginecontrolservice_p.h> +#include <private/qqmldebugconnector_p.h> #include "qqmlincubator.h" #include "qqmlabstracturlinterceptor.h" #include <private/qqmlboundsignal_p.h> @@ -225,7 +220,6 @@ void QQmlEnginePrivate::activateDesignerMode() /*! \class QQmlImageProviderBase \brief The QQmlImageProviderBase class is used to register image providers in the QML engine. - \mainclass \inmodule QtQml Image providers must be registered with the QML engine. The only information the QML @@ -247,6 +241,10 @@ void QQmlEnginePrivate::activateDesignerMode() The QQuickImageProvider::requestPixmap() method will be called for all image requests. \value Texture The Image Provider provides QSGTextureProvider based images. The QQuickImageProvider::requestTexture() method will be called for all image requests. + \value ImageResponse The Image provider provides QQuickTextureFactory based images. + Should only be used in QQuickAsyncImageProvider or its subclasses. + The QQuickAsyncImageProvider::requestImageResponse() method will be called for all image requests. + Since Qt 5.6 \omitvalue Invalid */ @@ -594,7 +592,7 @@ the same object as is returned from the Qt.include() call. // Qt.include() is implemented in qv4include.cpp QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) -: propertyCapture(0), rootContext(0), isDebugging(false), +: propertyCapture(0), rootContext(0), profiler(0), outputWarningsToMsgLog(true), cleanup(0), erroredBindings(0), inProgressCreations(0), workerScriptEngine(0), @@ -607,8 +605,8 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) QQmlEnginePrivate::~QQmlEnginePrivate() { - typedef QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::Iterator TypePropertyCacheIt; - typedef QHash<int, QQmlCompiledData *>::Iterator CompositeTypesIt; + typedef QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::const_iterator TypePropertyCacheIt; + typedef QHash<int, QQmlCompiledData *>::const_iterator CompositeTypesIt; if (inProgressCreations) qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations); @@ -627,9 +625,9 @@ QQmlEnginePrivate::~QQmlEnginePrivate() if (incubationController) incubationController->d = 0; incubationController = 0; - for (TypePropertyCacheIt iter = typePropertyCache.begin(), end = typePropertyCache.end(); iter != end; ++iter) + for (TypePropertyCacheIt iter = typePropertyCache.cbegin(), end = typePropertyCache.cend(); iter != end; ++iter) (*iter)->release(); - for (CompositeTypesIt iter = m_compositeTypes.begin(), end = m_compositeTypes.end(); iter != end; ++iter) { + for (CompositeTypesIt iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) { iter.value()->isRegisteredWithEngine = false; // since unregisterInternalCompositeType() will not be called in this @@ -666,6 +664,17 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o) } } +QQmlData::QQmlData() + : ownedByQml1(false), ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false), + hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false), + hasVMEMetaObject(false), parentFrozen(false), bindingBitsSize(0), bindingBits(0), notifyList(0), context(0), outerContext(0), + bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0), + lineNumber(0), columnNumber(0), jsEngineId(0), compiledData(0), deferredData(0), + propertyCache(0), guards(0), extendedData(0) +{ + init(); +} + void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o) { QQmlData *ddata = static_cast<QQmlData *>(d); @@ -799,7 +808,7 @@ void QQmlData::markAsDeleted(QObject *o) QQmlData::setQueuedForDeletion(o); QObjectPrivate *p = QObjectPrivate::get(o); - for (QList<QObject *>::iterator it = p->children.begin(), end = p->children.end(); it != end; ++it) { + for (QList<QObject *>::const_iterator it = p->children.constBegin(), end = p->children.constEnd(); it != end; ++it) { QQmlData::markAsDeleted(*it); } } @@ -824,14 +833,12 @@ void QQmlData::flushPendingBindingImpl(int coreIndex) // Find the binding QQmlAbstractBinding *b = bindings; - while (b && *b->m_mePtr && b->propertyIndex() != coreIndex) + while (b && b->targetPropertyIndex() != coreIndex) b = b->nextBinding(); - if (b && b->propertyIndex() == coreIndex) { - b->clear(); + if (b && b->targetPropertyIndex() == coreIndex) b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); - } } bool QQmlEnginePrivate::baseModulesUninitialized = true; @@ -861,15 +868,9 @@ void QQmlEnginePrivate::init() rootContext = new QQmlContext(q,true); - if (QCoreApplication::instance()->thread() == q->thread() && - QQmlEngineDebugService::isDebuggingEnabled()) { - isDebugging = true; - QQmlEngineDebugService::instance(); - QV4DebugService::instance(); - QQmlProfilerService::instance(); - QDebugMessageService::instance(); - QQmlEngineControlService::instance(); - QQmlDebugServer::instance()->addEngine(q); + if (QCoreApplication::instance()->thread() == q->thread() && QQmlDebugConnector::instance()) { + QQmlDebugConnector::instance()->open(); + QQmlDebugConnector::instance()->addEngine(q); } } @@ -886,7 +887,6 @@ QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine() \since 5.0 \inmodule QtQml \brief The QQmlEngine class provides an environment for instantiating QML components. - \mainclass Each QML component is instantiated in a QQmlContext. QQmlContext's are essential for passing data to QML @@ -947,8 +947,9 @@ QQmlEngine::QQmlEngine(QQmlEnginePrivate &dd, QObject *parent) QQmlEngine::~QQmlEngine() { Q_D(QQmlEngine); - if (d->isDebugging) - QQmlDebugServer::instance()->removeEngine(this); + QQmlDebugConnector *server = QQmlDebugConnector::instance(); + if (server) + server->removeEngine(this); d->typeLoader.invalidate(); @@ -1492,51 +1493,6 @@ Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *o #endif // QT_DEPRECATED_SINCE(5, 1) -QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning) -{ -#ifndef QQML_NO_DEBUG_PROTOCOL - if (!QQmlEnginePrivate::qml_debugging_enabled - && printWarning) { - qDebug("QML debugging is enabled. Only use this in a safe environment."); - } - QQmlEnginePrivate::qml_debugging_enabled = true; -#else - Q_UNUSED(printWarning); -#endif -} - -/*! - * \enum QQmlDebuggingEnabler::StartMode - * - * Defines the debug server's start behavior. You can interrupt QML engines starting while a debug - * client is connecting, in order to set breakpoints in or profile startup code. - * - * \value DoNotWaitForClient Run any QML engines as usual while the debug services are connecting. - * \value WaitForClient If a QML engine starts while the debug services are connecting, - * interrupt it until they are done. - */ - -/*! - * Enables debugging for QML engines created after calling this function. The debug server will - * listen on \a port at \a hostName and block the QML engine until it receives a connection if - * \a mode is \c WaitForClient. If \a mode is not specified it won't block and if \a hostName is not - * specified it will listen on all available interfaces. You can only start one debug server at a - * time. A debug server may have already been started if the -qmljsdebugger= command line argument - * was given. This method returns \c true if a new debug server was successfully started, or - * \c false otherwise. - */ -bool QQmlDebuggingEnabler::startTcpDebugServer(int port, StartMode mode, const QString &hostName) -{ -#ifndef QQML_NO_DEBUG_PROTOCOL - return QQmlDebugServer::enable(port, port, mode == WaitForClient, hostName); -#else - Q_UNUSED(port); - Q_UNUSED(block); - Q_UNUSED(hostName); - return false; -#endif -} - class QQmlDataExtended { public: QQmlDataExtended(); @@ -1678,12 +1634,11 @@ void QQmlData::destroyed(QObject *object) QQmlAbstractBinding *binding = bindings; while (binding) { - QQmlAbstractBinding *next = binding->nextBinding(); binding->setAddedToObject(false); - binding->setNextBinding(0); - binding->destroy(); - binding = next; + binding = binding->nextBinding(); } + if (bindings && !bindings->ref.deref()) + delete bindings; if (compiledData) { compiledData->release(); @@ -1696,9 +1651,9 @@ void QQmlData::destroyed(QObject *object) deferredData = 0; } - QQmlAbstractBoundSignal *signalHandler = signalHandlers; + QQmlBoundSignal *signalHandler = signalHandlers; while (signalHandler) { - if (signalHandler->isEvaluating()) { + if (signalHandler->isNotifying()) { // The object is being deleted during signal handler evaluation. // This will cause a crash due to invalid memory access when the // evaluation has completed. @@ -1710,7 +1665,7 @@ void QQmlData::destroyed(QObject *object) if (location.sourceFile.isEmpty()) location.sourceFile = QStringLiteral("<Unknown File>"); locationString.append(location.sourceFile); - locationString.append(QString::fromLatin1(":%0: ").arg(location.line)); + locationString.append(QStringLiteral(":%0: ").arg(location.line)); QString source = expr->expression(); if (source.size() > 100) { source.truncate(96); @@ -1727,7 +1682,7 @@ void QQmlData::destroyed(QObject *object) "%s", object, qPrintable(locationString)); } - QQmlAbstractBoundSignal *next = signalHandler->m_nextSignal; + QQmlBoundSignal *next = signalHandler->m_nextSignal; signalHandler->m_prevSignal = 0; signalHandler->m_nextSignal = 0; delete signalHandler; @@ -2140,8 +2095,7 @@ QString QQmlEngine::offlineStoragePath() const return d->offlineStoragePath; } -QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion, - QQmlError &error) +QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion) { QList<QQmlType *> types; @@ -2203,10 +2157,10 @@ QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersi // Properties override: // * other elements of the same name +#if 0 bool overloadError = false; QString overloadName; -#if 0 for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin(); !overloadError && iter != raw->stringCache.end(); ++iter) { @@ -2223,7 +2177,6 @@ QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersi overloadError = true; } } -#endif if (overloadError) { if (hasCopied) raw->release(); @@ -2231,6 +2184,7 @@ QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersi error.setDescription(QLatin1String("Type ") + type->qmlTypeName() + QLatin1Char(' ') + QString::number(type->majorVersion()) + QLatin1Char('.') + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation.")); return 0; } +#endif if (!hasCopied) raw->addref(); typePropertyCache.insert(qMakePair(type, minorVersion), raw); @@ -2281,8 +2235,8 @@ bool QQmlEnginePrivate::isList(int t) const int QQmlEnginePrivate::listType(int t) const { Locker locker(this); - QHash<int, int>::ConstIterator iter = m_qmlLists.find(t); - if (iter != m_qmlLists.end()) + QHash<int, int>::ConstIterator iter = m_qmlLists.constFind(t); + if (iter != m_qmlLists.cend()) return *iter; else return QQmlMetaType::listType(t); @@ -2291,8 +2245,8 @@ int QQmlEnginePrivate::listType(int t) const QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const { Locker locker(this); - QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t); - if (iter != m_compositeTypes.end()) { + QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t); + if (iter != m_compositeTypes.cend()) { return QQmlMetaObject((*iter)->rootPropertyCache); } else { QQmlType *type = QQmlMetaType::qmlType(t); @@ -2303,8 +2257,8 @@ QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const { Locker locker(this); - QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t); - if (iter != m_compositeTypes.end()) { + QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t); + if (iter != m_compositeTypes.cend()) { return QQmlMetaObject((*iter)->rootPropertyCache); } else { QQmlType *type = QQmlMetaType::qmlType(t); @@ -2315,8 +2269,8 @@ QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t) { Locker locker(this); - QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t); - if (iter != m_compositeTypes.end()) { + QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t); + if (iter != m_compositeTypes.cend()) { return (*iter)->rootPropertyCache; } else { QQmlType *type = QQmlMetaType::qmlType(t); @@ -2328,8 +2282,8 @@ QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t) QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t) { Locker locker(this); - QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t); - if (iter != m_compositeTypes.end()) { + QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t); + if (iter != m_compositeTypes.cend()) { return (*iter)->rootPropertyCache; } else { QQmlType *type = QQmlMetaType::qmlType(t); diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index df673c1fd5..61a884279d 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -52,7 +52,9 @@ public: Image, Pixmap, Texture, - Invalid + Invalid, + ImageResponse + // ### Qt6: reorder these, and give Invalid a fixed large value }; enum Flag { diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index f1fbad3cf8..26ee3bd655 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -85,7 +85,6 @@ class QQmlImportDatabase; class QNetworkReply; class QNetworkAccessManager; class QQmlNetworkAccessManagerFactory; -class QQmlAbstractBinding; class QQmlTypeNameCache; class QQmlComponentAttached; class QQmlCleanup; @@ -95,6 +94,7 @@ class QQmlObjectCreator; class QDir; class QQmlIncubator; class QQmlProfiler; +class QQmlPropertyCapture; // This needs to be declared here so that the pool for it can live in QQmlEnginePrivate. // The inline method definitions are in qqmljavascriptexpression_p.h @@ -123,21 +123,11 @@ public: // is just qmlClearTypeRegistrations (which can't be called while an engine exists) static bool baseModulesUninitialized; - class PropertyCapture { - public: - inline virtual ~PropertyCapture() {} - virtual void captureProperty(QQmlNotifier *) = 0; - virtual void captureProperty(QObject *, int, int) = 0; - }; - - PropertyCapture *propertyCapture; - inline void captureProperty(QQmlNotifier *); - inline void captureProperty(QObject *, int, int); + QQmlPropertyCapture *propertyCapture; QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool; QQmlContext *rootContext; - bool isDebugging; QQmlProfiler *profiler; void enableProfiler(); @@ -208,7 +198,7 @@ public: inline static void deleteInEngineThread(QQmlEngine *, T *); // These methods may be called from the loader thread - inline QQmlPropertyCache *cache(QQmlType *, int, QQmlError &error); + inline QQmlPropertyCache *cache(QQmlType *, int); using QJSEnginePrivate::cache; // These methods may be called from the loader thread @@ -262,7 +252,7 @@ public: private: // Must be called locked - QQmlPropertyCache *createCache(QQmlType *, int, QQmlError &error); + QQmlPropertyCache *createCache(QQmlType *, int); // These members must be protected by a QQmlEnginePrivate::Locker as they are required by // the threaded loader. Only access them through their respective accessor methods. @@ -346,7 +336,7 @@ Returns a QQmlPropertyCache for \a type with \a minorVersion. The returned cache is not referenced, so if it is to be stored, call addref(). */ -QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQmlError &error) +QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion) { Q_ASSERT(type); @@ -355,7 +345,7 @@ QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQ Locker locker(this); QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion)); - if (!rv) rv = createCache(type, minorVersion, error); + if (!rv) rv = createCache(type, minorVersion); return rv; } @@ -414,18 +404,6 @@ QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e) return get(qmlEngine); } -void QQmlEnginePrivate::captureProperty(QQmlNotifier *n) -{ - if (propertyCapture) - propertyCapture->captureProperty(n); -} - -void QQmlEnginePrivate::captureProperty(QObject *o, int c, int n) -{ - if (propertyCapture) - propertyCapture->captureProperty(o, c, n); -} - void QQmlEnginePrivate::setDebugChangesCache(const QHash<QUrl, QByteArray> &changes) { Locker locker(this); diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index 35e0bc8c64..332b99ee8f 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -45,13 +45,8 @@ QT_BEGIN_NAMESPACE -static QQmlJavaScriptExpression::VTable QQmlExpressionPrivate_jsvtable = { - QQmlExpressionPrivate::expressionIdentifier, - QQmlExpressionPrivate::expressionChanged -}; - QQmlExpressionPrivate::QQmlExpressionPrivate() -: QQmlJavaScriptExpression(&QQmlExpressionPrivate_jsvtable), +: QQmlJavaScriptExpression(), expressionFunctionValid(true), line(0), column(0) { @@ -65,7 +60,7 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QOb { expression = expr; - QQmlAbstractExpression::setContext(ctxt); + QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(me); expressionFunctionValid = false; } @@ -74,9 +69,9 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, QV4::Function *runtimeFu { expressionFunctionValid = true; QV4::ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(ctxt->engine); - function.set(engine, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, me, runtimeFunction)); + m_function.set(engine, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, me, runtimeFunction)); - QQmlAbstractExpression::setContext(ctxt); + QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(me); } @@ -246,18 +241,12 @@ void QQmlExpression::setExpression(const QString &expression) // Must be called with a valid handle scope QV4::ReturnedValue QQmlExpressionPrivate::v4value(bool *isUndefined) { - Q_Q(QQmlExpression); - - QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(q->engine())->v4engine(); - if (!expressionFunctionValid) { - function.set(v4, qmlBinding(context(), scopeObject(), expression, url, line, &qmlscope)); + createQmlBinding(context(), scopeObject(), expression, url, line); expressionFunctionValid = true; } - QV4::Scope scope(v4); - QV4::ScopedValue f(scope, function.value()); - return evaluate(context(), f, isUndefined); + return evaluate(isUndefined); } QVariant QQmlExpressionPrivate::value(bool *isUndefined) @@ -432,22 +421,15 @@ QQmlError QQmlExpression::error() const calling QQmlExpression::evaluate()) before this signal will be emitted. */ -void QQmlExpressionPrivate::expressionChanged(QQmlJavaScriptExpression *e) -{ - QQmlExpressionPrivate *This = static_cast<QQmlExpressionPrivate *>(e); - This->expressionChanged(); -} - void QQmlExpressionPrivate::expressionChanged() { Q_Q(QQmlExpression); emit q->valueChanged(); } -QString QQmlExpressionPrivate::expressionIdentifier(QQmlJavaScriptExpression *e) +QString QQmlExpressionPrivate::expressionIdentifier() { - QQmlExpressionPrivate *This = static_cast<QQmlExpressionPrivate *>(e); - return QLatin1Char('"') + This->expression + QLatin1Char('"'); + return QLatin1Char('"') + expression + QLatin1Char('"'); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h index d8da387878..2303539194 100644 --- a/src/qml/qml/qqmlexpression_p.h +++ b/src/qml/qml/qqmlexpression_p.h @@ -52,7 +52,6 @@ #include <private/qflagpointer_p.h> #include <private/qdeletewatcher_p.h> #include <private/qpointervaluepair_p.h> -#include <private/qqmlabstractexpression_p.h> #include <private/qqmljavascriptexpression_p.h> QT_BEGIN_NAMESPACE @@ -60,8 +59,7 @@ QT_BEGIN_NAMESPACE class QQmlExpression; class QString; class QQmlExpressionPrivate : public QObjectPrivate, - public QQmlJavaScriptExpression, - public QQmlAbstractExpression + public QQmlJavaScriptExpression { Q_DECLARE_PUBLIC(QQmlExpression) public: @@ -82,16 +80,12 @@ public: bool expressionFunctionValid:1; - // "Inherited" from QQmlJavaScriptExpression - static QString expressionIdentifier(QQmlJavaScriptExpression *); - static void expressionChanged(QQmlJavaScriptExpression *); + // Inherited from QQmlJavaScriptExpression + virtual QString expressionIdentifier(); virtual void expressionChanged(); QString expression; - QV4::PersistentValue qmlscope; - QV4::PersistentValue function; - QString url; // This is a QString for a reason. QUrls are slooooooow... quint16 line; quint16 column; diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp index d904242f93..0a2f4079c2 100644 --- a/src/qml/qml/qqmlglobal.cpp +++ b/src/qml/qml/qqmlglobal.cpp @@ -359,7 +359,7 @@ QObject *QQmlGuiProvider::inputMethod() { // We don't have any input method code by default QObject *o = new QObject(); - o->setObjectName(QString::fromLatin1("No inputMethod available")); + o->setObjectName(QStringLiteral("No inputMethod available")); QQmlEngine::setObjectOwnership(o, QQmlEngine::JavaScriptOwnership); return o; } @@ -368,7 +368,7 @@ QObject *QQmlGuiProvider::inputMethod() QObject *QQmlGuiProvider::styleHints() { QObject *o = new QObject(); - o->setObjectName(QString::fromLatin1("No styleHints available")); + o->setObjectName(QStringLiteral("No styleHints available")); QQmlEngine::setObjectOwnership(o, QQmlEngine::JavaScriptOwnership); return o; } diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index ff48a10d95..b17bb0455d 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -169,6 +169,7 @@ QQmlType *getTypeForUrl(const QString &urlString, const QHashedStringRef& typeNa } // namespace +#ifndef QT_NO_LIBRARY struct RegisteredPlugin { QString uri; QPluginLoader* loader; @@ -193,6 +194,7 @@ void qmlClearEnginePlugins() } typedef QPair<QStaticPlugin, QJsonArray> StaticPluginPair; +#endif class QQmlImportNamespace { @@ -292,9 +294,10 @@ 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 bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QString &qmldirPath, QList<QQmlError> *errors); +#endif }; /*! @@ -382,7 +385,7 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const // We need to exclude the entry for the current baseUrl. This can happen for example // when handling qmldir files on the remote dir case and the current type is marked as // singleton. -bool excludeBaseUrl(const QString &importUrl, const QString &fileName, const QString baseUrl) +bool excludeBaseUrl(const QString &importUrl, const QString &fileName, const QString &baseUrl) { if (importUrl.isEmpty()) return false; @@ -398,7 +401,7 @@ bool excludeBaseUrl(const QString &importUrl, const QString &fileName, const QSt return true; } -void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::CompositeSingletonReference> &resultList, QUrl baseUrl) +void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::CompositeSingletonReference> &resultList, const QUrl &baseUrl) { typedef QQmlDirComponents::const_iterator ConstIterator; @@ -826,6 +829,7 @@ QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStr } +#ifndef QT_NO_LIBRARY /*! Get all static plugins that are QML plugins and has a meta data URI that begins with \a uri. Note that if e.g uri == "a", and different plugins have meta data "a", "a.2.1", "a.b.c", all @@ -869,6 +873,7 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res } return true; } +#endif /*! Import an extension defined by a qmldir file. @@ -995,6 +1000,13 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, } #else + Q_UNUSED(qmldirFilePath); + Q_UNUSED(uri); + Q_UNUSED(vmaj); + Q_UNUSED(vmin); + Q_UNUSED(database); + Q_UNUSED(qmldir); + Q_UNUSED(errors); return false; #endif // QT_NO_LIBRARY return true; @@ -1931,6 +1943,12 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba return true; #else + Q_UNUSED(instance); + Q_UNUSED(basePath); + Q_UNUSED(uri); + Q_UNUSED(typeNamespace); + Q_UNUSED(vmaj); + Q_UNUSED(errors); return false; #endif } @@ -2011,6 +2029,11 @@ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QStr return true; #else + Q_UNUSED(filePath); + Q_UNUSED(uri); + Q_UNUSED(typeNamespace); + Q_UNUSED(vmaj); + Q_UNUSED(errors); return false; #endif } diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 02bd1c4b83..5f30eac066 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -35,7 +35,7 @@ #include <private/qqmlexpression_p.h> #include <private/qqmlcontextwrapper_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4script_p.h> #include <private/qv4errorobject_p.h> @@ -83,13 +83,22 @@ void QQmlDelayedError::catchJavaScriptException(QV4::ExecutionEngine *engine) } -QQmlJavaScriptExpression::QQmlJavaScriptExpression(VTable *v) -: m_vtable(v) +QQmlJavaScriptExpression::QQmlJavaScriptExpression() + : m_error(0), + m_context(0), + m_prevExpression(0), + m_nextExpression(0) { } QQmlJavaScriptExpression::~QQmlJavaScriptExpression() { + if (m_prevExpression) { + *m_prevExpression = m_nextExpression; + if (m_nextExpression) + m_nextExpression->m_prevExpression = m_prevExpression; + } + clearGuards(); if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion. m_scopeObject.asT2()->_s = 0; @@ -106,40 +115,62 @@ void QQmlJavaScriptExpression::resetNotifyOnValueChanged() clearGuards(); } -QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, - const QV4::Value &function, bool *isUndefined) +void QQmlJavaScriptExpression::setContext(QQmlContextData *context) { - QV4::ExecutionEngine *v4 = QV8Engine::getV4(context->engine); + if (m_prevExpression) { + *m_prevExpression = m_nextExpression; + if (m_nextExpression) + m_nextExpression->m_prevExpression = m_prevExpression; + m_prevExpression = 0; + m_nextExpression = 0; + } + + m_context = context; + + if (context) { + m_nextExpression = context->expressions; + if (m_nextExpression) + m_nextExpression->m_prevExpression = &m_nextExpression; + m_prevExpression = &context->expressions; + context->expressions = this; + } +} + +void QQmlJavaScriptExpression::refresh() +{ +} + +QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(bool *isUndefined) +{ + QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_context->engine); QV4::Scope scope(v4); QV4::ScopedCallData callData(scope); - return evaluate(context, function, callData, isUndefined); + return evaluate(callData, isUndefined); } -QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, - const QV4::Value &function, - QV4::CallData *callData, - bool *isUndefined) +QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined) { - Q_ASSERT(context && context->engine); + Q_ASSERT(m_context && m_context->engine); - if (function.isUndefined()) { + QV4::Value *f = m_function.valueRef(); + if (!f || f->isUndefined()) { if (isUndefined) *isUndefined = true; return QV4::Encode::undefined(); } - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine); + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(m_context->engine); // All code that follows must check with watcher before it accesses data members // incase we have been deleted. DeleteWatcher watcher(this); Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty()); - GuardCapture capture(context->engine, this, &watcher); + QQmlPropertyCapture capture(m_context->engine, this, &watcher); - QQmlEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture; - ep->propertyCapture = notifyOnValueChanged()?&capture:0; + QQmlPropertyCapture *lastPropertyCapture = ep->propertyCapture; + ep->propertyCapture = notifyOnValueChanged() ? &capture : 0; if (notifyOnValueChanged()) @@ -148,14 +179,14 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine()); QV4::Scope scope(v4); QV4::ScopedValue result(scope, QV4::Primitive::undefinedValue()); - callData->thisObject = v4->globalObject(); + callData->thisObject = v4->globalObject; if (scopeObject()) { QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(v4, scopeObject())); if (value->isObject()) callData->thisObject = value; } - result = function.asFunctionObject()->call(callData); + result = f->as<QV4::FunctionObject>()->call(callData); if (scope.hasException()) { if (watcher.wasDeleted()) scope.engine->catchException(); // ignore exception @@ -178,7 +209,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, capture.errorString = 0; } - while (Guard *g = capture.guards.takeFirst()) + while (QQmlJavaScriptExpressionGuard *g = capture.guards.takeFirst()) g->Delete(); ep->propertyCapture = lastPropertyCapture; @@ -186,7 +217,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, return result->asReturnedValue(); } -void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n) +void QQmlPropertyCapture::captureProperty(QQmlNotifier *n) { if (watcher->wasDeleted()) return; @@ -196,13 +227,13 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n) while (!guards.isEmpty() && !guards.first()->isConnected(n)) guards.takeFirst()->Delete(); - Guard *g = 0; + QQmlJavaScriptExpressionGuard *g = 0; if (!guards.isEmpty()) { g = guards.takeFirst(); g->cancelNotify(); Q_ASSERT(g->isConnected(n)); } else { - g = Guard::New(expression, engine); + g = QQmlJavaScriptExpressionGuard::New(expression, engine); g->connect(n); } @@ -213,7 +244,7 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n) \a n is in the signal index range (see QObjectPrivate::signalIndex()). */ -void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, int n) +void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n) { if (watcher->wasDeleted()) return; @@ -223,7 +254,7 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, if (!errorString) { errorString = new QStringList; QString preamble = QLatin1String("QQmlExpression: Expression ") + - expression->m_vtable->expressionIdentifier(expression) + + expression->expressionIdentifier() + QLatin1String(" depends on non-NOTIFYable properties:"); errorString->append(preamble); } @@ -242,13 +273,13 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, while (!guards.isEmpty() && !guards.first()->isConnected(o, n)) guards.takeFirst()->Delete(); - Guard *g = 0; + QQmlJavaScriptExpressionGuard *g = 0; if (!guards.isEmpty()) { g = guards.takeFirst(); g->cancelNotify(); Q_ASSERT(g->isConnected(o, n)); } else { - g = Guard::New(expression, engine); + g = QQmlJavaScriptExpressionGuard::New(expression, engine); g->connect(o, n, engine); } @@ -258,31 +289,31 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, void QQmlJavaScriptExpression::clearError() { - if (m_vtable.hasValue()) { - m_vtable.value().clearError(); - m_vtable.value().removeError(); - } + if (m_error) + delete m_error; + m_error = 0; } QQmlError QQmlJavaScriptExpression::error(QQmlEngine *engine) const { Q_UNUSED(engine); - if (m_vtable.hasValue()) - return m_vtable.constValue()->error(); + if (m_error) + return m_error->error(); else return QQmlError(); } QQmlDelayedError *QQmlJavaScriptExpression::delayedError() { - return &m_vtable.value(); + if (!m_error) + m_error = new QQmlDelayedError; + return m_error; } QV4::ReturnedValue QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObject, - const QString &code, const QString &filename, quint16 line, - QV4::PersistentValue *qmlscope) + const QString &code, const QString &filename, quint16 line) { QQmlEngine *engine = ctxt->engine; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); @@ -308,14 +339,11 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObje ep->warning(error); return QV4::Encode::undefined(); } - if (qmlscope) - qmlscope->set(v4, qmlScopeObject); return result->asReturnedValue(); } -QV4::ReturnedValue QQmlJavaScriptExpression::qmlBinding(QQmlContextData *ctxt, QObject *qmlScope, - const QString &code, const QString &filename, quint16 line, - QV4::PersistentValue *qmlscope) +void QQmlJavaScriptExpression::createQmlBinding(QQmlContextData *ctxt, QObject *qmlScope, + const QString &code, const QString &filename, quint16 line) { QQmlEngine *engine = ctxt->engine; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); @@ -339,17 +367,15 @@ QV4::ReturnedValue QQmlJavaScriptExpression::qmlBinding(QQmlContextData *ctxt, Q error.setUrl(QUrl::fromLocalFile(filename)); error.setObject(qmlScope); ep->warning(error); - return QV4::Encode::undefined(); + result = QV4::Encode::undefined(); } - if (qmlscope) - qmlscope->set(v4, qmlScopeObject); - return result->asReturnedValue(); + m_function.set(v4, result); } void QQmlJavaScriptExpression::clearGuards() { - while (Guard *g = activeGuards.takeFirst()) + while (QQmlJavaScriptExpressionGuard *g = activeGuards.takeFirst()) g->Delete(); } @@ -358,7 +384,7 @@ void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *e, void **) QQmlJavaScriptExpression *expression = static_cast<QQmlJavaScriptExpressionGuard *>(e)->expression; - expression->m_vtable->expressionChanged(expression); + expression->expressionChanged(); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 989d5a0b0d..dfcf8b2d68 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -89,23 +89,17 @@ private: QQmlDelayedError **prevError; }; -class QQmlJavaScriptExpression +class Q_QML_PRIVATE_EXPORT QQmlJavaScriptExpression { public: - // Although this looks crazy, we implement our own "vtable" here, rather than relying on - // C++ virtuals, to save memory. By doing it ourselves, we can overload the storage - // location that is use for the vtable to also store the rarely used delayed error. - // If we use C++ virtuals, we can't do this and it consts us an extra sizeof(void *) in - // memory for every expression. - struct VTable { - QString (*expressionIdentifier)(QQmlJavaScriptExpression *); - void (*expressionChanged)(QQmlJavaScriptExpression *); - }; + QQmlJavaScriptExpression(); + virtual ~QQmlJavaScriptExpression(); - QQmlJavaScriptExpression(VTable *vtable); + virtual QString expressionIdentifier() = 0; + virtual void expressionChanged() = 0; - QV4::ReturnedValue evaluate(QQmlContextData *, const QV4::Value &function, bool *isUndefined); - QV4::ReturnedValue evaluate(QQmlContextData *, const QV4::Value &function, QV4::CallData *callData, bool *isUndefined); + QV4::ReturnedValue evaluate(bool *isUndefined); + QV4::ReturnedValue evaluate(QV4::CallData *callData, bool *isUndefined); inline bool notifyOnValueChanged() const; @@ -115,6 +109,13 @@ public: inline QObject *scopeObject() const; inline void setScopeObject(QObject *v); + bool isValid() const { return context() != 0; } + + QQmlContextData *context() const { return m_context; } + void setContext(QQmlContextData *context); + + virtual void refresh(); + class DeleteWatcher { public: inline DeleteWatcher(QQmlJavaScriptExpression *); @@ -136,46 +137,50 @@ public: static QV4::ReturnedValue evalFunction(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, - quint16 line, - QV4::PersistentValue *qmlscope = 0); - // doesn't require rewriting the expression - static QV4::ReturnedValue qmlBinding(QQmlContextData *ctxt, QObject *scope, - const QString &code, - const QString &filename, quint16 line, - QV4::PersistentValue *qmlscope = 0); + quint16 line); protected: - ~QQmlJavaScriptExpression(); + void createQmlBinding(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, quint16 line); private: - typedef QQmlJavaScriptExpressionGuard Guard; + friend class QQmlContextData; + friend class QQmlPropertyCapture; friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **); - struct GuardCapture : public QQmlEnginePrivate::PropertyCapture { - GuardCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e, DeleteWatcher *w) - : engine(engine), expression(e), watcher(w), errorString(0) { } - - ~GuardCapture() { - Q_ASSERT(guards.isEmpty()); - Q_ASSERT(errorString == 0); - } - - virtual void captureProperty(QQmlNotifier *); - virtual void captureProperty(QObject *, int, int); - - QQmlEngine *engine; - QQmlJavaScriptExpression *expression; - DeleteWatcher *watcher; - QFieldList<Guard, &Guard::next> guards; - QStringList *errorString; - }; - - QPointerValuePair<VTable, QQmlDelayedError> m_vtable; + QQmlDelayedError *m_error; // We store some flag bits in the following flag pointers. // activeGuards:flag1 - notifyOnValueChanged // activeGuards:flag2 - useSharedContext QBiPointer<QObject, DeleteWatcher> m_scopeObject; - QForwardFieldList<Guard, &Guard::next> activeGuards; + QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> activeGuards; + + QQmlContextData *m_context; + QQmlJavaScriptExpression **m_prevExpression; + QQmlJavaScriptExpression *m_nextExpression; + +protected: + QV4::PersistentValue m_function; +}; + +class QQmlPropertyCapture +{ +public: + QQmlPropertyCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e, QQmlJavaScriptExpression::DeleteWatcher *w) + : engine(engine), expression(e), watcher(w), errorString(0) { } + + ~QQmlPropertyCapture() { + Q_ASSERT(guards.isEmpty()); + Q_ASSERT(errorString == 0); + } + + void captureProperty(QQmlNotifier *); + void captureProperty(QObject *, int, int); + + QQmlEngine *engine; + QQmlJavaScriptExpression *expression; + QQmlJavaScriptExpression::DeleteWatcher *watcher; + QFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> guards; + QStringList *errorString; }; QQmlJavaScriptExpression::DeleteWatcher::DeleteWatcher(QQmlJavaScriptExpression *e) @@ -222,18 +227,18 @@ void QQmlJavaScriptExpression::setScopeObject(QObject *v) bool QQmlJavaScriptExpression::hasError() const { - return m_vtable.hasValue() && m_vtable.constValue()->isValid(); + return m_error && m_error->isValid(); } bool QQmlJavaScriptExpression::hasDelayedError() const { - return m_vtable.hasValue(); + return m_error; } QQmlJavaScriptExpressionGuard::QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *e) -: expression(e), next(0) + : QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlJavaScriptExpressionGuard), + expression(e), next(0) { - setCallback(QQmlNotifierEndpoint::QQmlJavaScriptExpressionGuard); } QQmlJavaScriptExpressionGuard * diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index bcb1e72f0b..d09f4df54c 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -92,13 +92,13 @@ QVariant QmlListWrapper::toVariant() const } -ReturnedValue QmlListWrapper::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue QmlListWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QmlListWrapper>()); - QmlListWrapper *w = static_cast<QmlListWrapper *>(m); + const QmlListWrapper *w = static_cast<const QmlListWrapper *>(m); QV4::ExecutionEngine *v4 = w->engine(); - if (name->equals(v4->id_length) && !w->d()->object.isNull()) { + if (name->equals(v4->id_length()) && !w->d()->object.isNull()) { quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0; return Primitive::fromUInt32(count).asReturnedValue(); } @@ -110,12 +110,12 @@ ReturnedValue QmlListWrapper::get(Managed *m, String *name, bool *hasProperty) return Object::get(m, name, hasProperty); } -ReturnedValue QmlListWrapper::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue QmlListWrapper::getIndexed(const Managed *m, uint index, bool *hasProperty) { Q_UNUSED(hasProperty); Q_ASSERT(m->as<QmlListWrapper>()); - QmlListWrapper *w = static_cast<QmlListWrapper *>(m); + const QmlListWrapper *w = static_cast<const QmlListWrapper *>(m); QV4::ExecutionEngine *v4 = w->engine(); quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0; @@ -138,9 +138,9 @@ void QmlListWrapper::put(Managed *m, String *name, const Value &value) Q_UNUSED(value); } -void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attrs) +void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs) { - *name = (Heap::String *)0; + name->setM(0); *index = UINT_MAX; Q_ASSERT(m->as<QmlListWrapper>()); QmlListWrapper *w = static_cast<QmlListWrapper *>(m); diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h index 3590bcb1c9..ff006d4302 100644 --- a/src/qml/qml/qqmllistwrapper_p.h +++ b/src/qml/qml/qqmllistwrapper_p.h @@ -50,7 +50,7 @@ #include <QtQml/qqmllist.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> QT_BEGIN_NAMESPACE @@ -81,10 +81,10 @@ struct Q_QML_EXPORT QmlListWrapper : Object QVariant toVariant() const; - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); - static void advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes); + static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); }; } diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index 62b5b76ede..7f49798da6 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -65,13 +65,13 @@ static bool isLocaleObject(const QV4::Value &val) void QQmlDateExtension::registerExtension(QV4::ExecutionEngine *engine) { - engine->datePrototype.asObject()->defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); - engine->datePrototype.asObject()->defineDefaultProperty(QStringLiteral("toLocaleTimeString"), method_toLocaleTimeString); - engine->datePrototype.asObject()->defineDefaultProperty(QStringLiteral("toLocaleDateString"), method_toLocaleDateString); - engine->dateCtor.objectValue()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString); - engine->dateCtor.objectValue()->defineDefaultProperty(QStringLiteral("fromLocaleTimeString"), method_fromLocaleTimeString); - engine->dateCtor.objectValue()->defineDefaultProperty(QStringLiteral("fromLocaleDateString"), method_fromLocaleDateString); - engine->dateCtor.objectValue()->defineDefaultProperty(QStringLiteral("timeZoneUpdated"), method_timeZoneUpdated); + engine->datePrototype()->defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); + engine->datePrototype()->defineDefaultProperty(QStringLiteral("toLocaleTimeString"), method_toLocaleTimeString); + engine->datePrototype()->defineDefaultProperty(QStringLiteral("toLocaleDateString"), method_toLocaleDateString); + engine->dateCtor()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString); + engine->dateCtor()->defineDefaultProperty(QStringLiteral("fromLocaleTimeString"), method_fromLocaleTimeString); + engine->dateCtor()->defineDefaultProperty(QStringLiteral("fromLocaleDateString"), method_fromLocaleDateString); + engine->dateCtor()->defineDefaultProperty(QStringLiteral("timeZoneUpdated"), method_timeZoneUpdated); } QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::CallContext *ctx) @@ -81,7 +81,7 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::CallContext *ct QV4::Scope scope(ctx); - QV4::DateObject *date = ctx->thisObject().asDateObject(); + QV4::DateObject *date = ctx->thisObject().as<DateObject>(); if (!date) return QV4::DatePrototype::method_toLocaleString(ctx); @@ -125,7 +125,7 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleTimeString(QV4::CallContext QV4::Scope scope(ctx); - QV4::DateObject *date = ctx->thisObject().asDateObject(); + QV4::DateObject *date = ctx->thisObject().as<DateObject>(); if (!date) return QV4::DatePrototype::method_toLocaleTimeString(ctx); @@ -170,7 +170,7 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleDateString(QV4::CallContext QV4::Scope scope(ctx); - QV4::DateObject *dateObj = ctx->thisObject().asDateObject(); + QV4::DateObject *dateObj = ctx->thisObject().as<DateObject>(); if (!dateObj) return QV4::DatePrototype::method_toLocaleDateString(ctx); @@ -347,9 +347,9 @@ QV4::ReturnedValue QQmlDateExtension::method_timeZoneUpdated(QV4::CallContext *c void QQmlNumberExtension::registerExtension(QV4::ExecutionEngine *engine) { - engine->numberPrototype.asObject()->defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); - engine->numberPrototype.asObject()->defineDefaultProperty(QStringLiteral("toLocaleCurrencyString"), method_toLocaleCurrencyString); - engine->numberCtor.objectValue()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString); + engine->numberPrototype()->defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); + engine->numberPrototype()->defineDefaultProperty(QStringLiteral("toLocaleCurrencyString"), method_toLocaleCurrencyString); + engine->numberCtor()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString); } QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(QV4::CallContext *ctx) @@ -815,15 +815,15 @@ QV4::ReturnedValue QQmlLocale::wrap(ExecutionEngine *v4, const QLocale &locale) void QQmlLocale::registerStringLocaleCompare(QV4::ExecutionEngine *engine) { - engine->stringPrototype.asObject()->defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare); + engine->stringPrototype()->defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare); } QV4::ReturnedValue QQmlLocale::method_localeCompare(QV4::CallContext *ctx) { - if (ctx->argc() != 1 || (!ctx->args()[0].isString() && !ctx->args()[0].asStringObject())) + if (ctx->argc() != 1 || (!ctx->args()[0].isString() && !ctx->args()[0].as<StringObject>())) return QV4::StringPrototype::method_localeCompare(ctx); - if (!ctx->thisObject().isString() && !ctx->thisObject().asStringObject()) + if (!ctx->thisObject().isString() && !ctx->thisObject().as<StringObject>()) return QV4::StringPrototype::method_localeCompare(ctx); QString thisString = ctx->thisObject().toQStringNoThrow(); diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h index d4436482cf..cb9fe9bbef 100644 --- a/src/qml/qml/qqmllocale_p.h +++ b/src/qml/qml/qqmllocale_p.h @@ -74,10 +74,6 @@ private: class Q_AUTOTEST_EXPORT QQmlLocale { Q_GADGET - Q_ENUMS(MeasurementSystem) - Q_ENUMS(FormatType) - Q_ENUMS(CurrencySymbolFormat) - Q_ENUMS(DayOfWeek) public: ~QQmlLocale(); @@ -88,16 +84,19 @@ public: ImperialUSSystem = QLocale::ImperialUSSystem, ImperialUKSystem = QLocale::ImperialUKSystem }; + Q_ENUM(MeasurementSystem) enum FormatType { LongFormat = QLocale::LongFormat, ShortFormat = QLocale::ShortFormat, NarrowFormat = QLocale::NarrowFormat }; + Q_ENUM(FormatType) enum CurrencySymbolFormat { CurrencyIsoCode = QLocale::CurrencyIsoCode, CurrencySymbol = QLocale::CurrencySymbol, CurrencyDisplayName = QLocale::CurrencyDisplayName }; + Q_ENUM(CurrencySymbolFormat) // Qt defines Sunday as 7, but JS Date assigns Sunday 0 enum DayOfWeek { Sunday = 0, @@ -108,6 +107,7 @@ public: Friday = Qt::Friday, Saturday = Qt::Saturday }; + Q_ENUM(DayOfWeek) static QV4::ReturnedValue locale(QV4::ExecutionEngine *engine, const QString &localeName); static QV4::ReturnedValue wrap(QV4::ExecutionEngine *engine, const QLocale &locale); @@ -137,7 +137,7 @@ struct QQmlLocaleData : public QV4::Object V4_NEEDS_DESTROY static QLocale *getThisLocale(QV4::CallContext *ctx) { - QV4::Object *o = ctx->thisObject().asObject(); + QV4::Object *o = ctx->thisObject().as<Object>(); QQmlLocaleData *thisObject = o ? o->as<QQmlLocaleData>() : 0; if (!thisObject) { ctx->engine()->throwTypeError(); diff --git a/src/qml/qml/qqmlmemoryprofiler.cpp b/src/qml/qml/qqmlmemoryprofiler.cpp index cdd60e2dec..531666340b 100644 --- a/src/qml/qml/qqmlmemoryprofiler.cpp +++ b/src/qml/qml/qqmlmemoryprofiler.cpp @@ -63,11 +63,13 @@ static qmlmemprofile_pop_location *memprofile_pop_location; static qmlmemprofile_save *memprofile_save; static qmlmemprofile_is_enabled *memprofile_is_enabled; +#ifndef QT_NO_LIBRARY extern QFunctionPointer qt_linux_find_symbol_sys(const char *symbol); +#endif static bool openLibrary() { -#ifdef Q_OS_LINUX +#if defined(Q_OS_LINUX) && !defined(QT_NO_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/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index cb8c2bd3b5..fbb21f4562 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -258,7 +258,7 @@ QObject *QQmlType::SingletonInstanceInfo::qobjectApi(QQmlEngine *e) const return qobjectApis.value(e); } -void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, QJSValue v) +void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, const QJSValue &v) { scriptApis.insert(e, v); } @@ -1110,7 +1110,9 @@ void qmlClearTypeRegistrations() // Declared in qqml.h data->uriToModule.clear(); QQmlEnginePrivate::baseModulesUninitialized = true; //So the engine re-registers its types +#ifndef QT_NO_LIBRARY qmlClearEnginePlugins(); +#endif } int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent) @@ -1440,8 +1442,8 @@ bool QQmlMetaType::isAnyModule(const QString &uri) QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin(); - iter != data->uriToModule.end(); ++iter) { + for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.cbegin(); + iter != data->uriToModule.cend(); ++iter) { if ((*iter)->module() == uri) return true; } @@ -1718,7 +1720,7 @@ QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStrin QQmlMetaTypeData *data = metaTypeData(); QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(name); - while (it != data->nameToType.end() && it.key() == name) { + while (it != data->nameToType.cend() && it.key() == name) { // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty if (version_major < 0 || module.isEmpty() || (*it)->availableInVersion(module, version_major,version_minor)) return (*it); @@ -1752,7 +1754,7 @@ QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStri QQmlMetaTypeData *data = metaTypeData(); QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.constFind(metaObject); - while (it != data->metaObjectToType.end() && it.key() == metaObject) { + while (it != data->metaObjectToType.cend() && it.key() == metaObject) { QQmlType *t = *it; if (version_major < 0 || module.isEmpty() || t->availableInVersion(module, version_major,version_minor)) return t; @@ -1823,8 +1825,9 @@ QList<QString> QQmlMetaType::qmlTypeNames() QQmlMetaTypeData *data = metaTypeData(); QList<QString> names; - QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin(); - while (it != data->nameToType.end()) { + names.reserve(data->nameToType.count()); + QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.cbegin(); + while (it != data->nameToType.cend()) { names += (*it)->qmlTypeName(); ++it; } diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index e5ac20d314..61a6567f1d 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -191,7 +191,7 @@ public: void setQObjectApi(QQmlEngine *, QObject *); QObject *qobjectApi(QQmlEngine *) const; - void setScriptApi(QQmlEngine *, QJSValue); + void setScriptApi(QQmlEngine *, const QJSValue &); QJSValue scriptApi(QQmlEngine *) const; void init(QQmlEngine *); diff --git a/src/qml/qml/qqmlnotifier_p.h b/src/qml/qml/qqmlnotifier_p.h index 2742bfc84b..90902c089d 100644 --- a/src/qml/qml/qqmlnotifier_p.h +++ b/src/qml/qml/qqmlnotifier_p.h @@ -63,9 +63,6 @@ class QQmlNotifierEndpoint QQmlNotifierEndpoint *next; QQmlNotifierEndpoint **prev; public: - inline QQmlNotifierEndpoint(); - inline ~QQmlNotifierEndpoint(); - // QQmlNotifierEndpoint can only invoke one of a set of pre-defined callbacks. // To add another callback, extend this enum and add the callback to the top // of qqmlnotifier.cpp. Four bits are reserved for the callback, so there can @@ -77,7 +74,8 @@ public: QQmlVMEMetaObjectEndpoint = 3 }; - inline void setCallback(Callback c) { callback = c; } + inline QQmlNotifierEndpoint(Callback callback); + inline ~QQmlNotifierEndpoint(); inline bool isConnected(); inline bool isConnected(QObject *source, int sourceSignal); @@ -90,6 +88,8 @@ public: inline bool isNotifying() const; inline void cancelNotify(); + inline int signalIndex() const { return sourceSignal; } + private: friend class QQmlData; friend class QQmlNotifier; @@ -135,8 +135,8 @@ void QQmlNotifier::notify() if (endpoints) emitNotify(endpoints, args); } -QQmlNotifierEndpoint::QQmlNotifierEndpoint() -: next(0), prev(0), senderPtr(0), callback(None), sourceSignal(-1) +QQmlNotifierEndpoint::QQmlNotifierEndpoint(Callback callback) +: next(0), prev(0), senderPtr(0), callback(callback), sourceSignal(-1) { } diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 3c2f3690b9..0b977f2551 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -62,14 +62,6 @@ struct ActiveOCRestorer }; } -static void removeBindingOnProperty(QObject *o, int index) -{ - int coreIndex; - int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex); - QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(o, coreIndex, valueTypeIndex, 0); - if (binding) binding->destroy(); -} - QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext, void *activeVMEDataForRootContext) : phase(Startup) , compiledData(compiledData) @@ -137,11 +129,6 @@ QQmlObjectCreator::~QQmlObjectCreator() { QQmlObjectCreatorRecursionWatcher watcher(this); } - for (int i = 0; i < sharedState->allCreatedBindings.count(); ++i) { - QQmlAbstractBinding *b = sharedState->allCreatedBindings.at(i); - if (b) - b->m_mePtr = 0; - } for (int i = 0; i < sharedState->allParserStatusCallbacks.count(); ++i) { QQmlParserStatus *ps = sharedState->allParserStatusCallbacks.at(i); if (ps) @@ -660,15 +647,12 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) // ### this is best done through type-compile-time binding skip lists. if (_valueTypeProperty) { - QQmlAbstractBinding *binding = - QQmlPropertyPrivate::binding(_bindingTarget, _valueTypeProperty->coreIndex, -1); + QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(_bindingTarget, _valueTypeProperty->coreIndex); - if (binding && binding->bindingType() != QQmlAbstractBinding::ValueTypeProxy) { - QQmlPropertyPrivate::setBinding(_bindingTarget, _valueTypeProperty->coreIndex, -1, 0); - binding->destroy(); + if (binding && !binding->isValueTypeProxy()) { + QQmlPropertyPrivate::removeBinding(_bindingTarget, _valueTypeProperty->coreIndex); } else if (binding) { - QQmlValueTypeProxyBinding *proxy = - static_cast<QQmlValueTypeProxyBinding *>(binding); + QQmlValueTypeProxyBinding *proxy = static_cast<QQmlValueTypeProxyBinding *>(binding); if (qmlTypeForObject(_bindingTarget)) { quint32 bindingSkipList = 0; @@ -731,7 +715,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con // ### resolve this at compile time if (property && property->propType == qMetaTypeId<QQmlScriptString>()) { QQmlScriptString ss(binding->valueAsScriptString(qmlUnit), context->asQQmlContext(), _scopeObject); - ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : QQmlBinding::Invalid; + ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid; ss.d.data()->lineNumber = binding->location.line; ss.d.data()->columnNumber = binding->location.column; ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String; @@ -800,7 +784,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con if (_ddata->hasBindingBit(property->coreIndex) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment) && !_valueTypeProperty) - removeBindingOnProperty(_bindingTarget, property->coreIndex); + QQmlPropertyPrivate::removeBinding(_bindingTarget, property->coreIndex); if (binding->type == QV4::CompiledData::Binding::Type_Script) { QV4::Function *runtimeFunction = compiledData->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; @@ -828,18 +812,12 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con if (_valueTypeProperty) targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine); - sharedState->allCreatedBindings.push(qmlBinding); - qmlBinding->m_mePtr = &sharedState->allCreatedBindings.top(); + sharedState->allCreatedBindings.push(QQmlAbstractBinding::Ptr(qmlBinding)); - qmlBinding->setTarget(_bindingTarget, targetCorePropertyData, context); + qmlBinding->setTarget(_bindingTarget, targetCorePropertyData); if (targetCorePropertyData.isAlias()) { - QQmlAbstractBinding *old = - QQmlPropertyPrivate::setBindingNoEnable(_bindingTarget, - targetCorePropertyData.coreIndex, - targetCorePropertyData.getValueTypeCoreIndex(), - qmlBinding); - if (old) { old->destroy(); } + QQmlPropertyPrivate::setBinding(qmlBinding, QQmlPropertyPrivate::DontEnable); } else { qmlBinding->addToObject(); @@ -1011,7 +989,7 @@ QV4::Heap::ExecutionContext *QQmlObjectCreator::currentQmlContext() { if (!_qmlBindingWrapper->objectValue()) { QV4::Scope valueScope(v4); - QV4::ScopedObject qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(v4, context, _scopeObject)); + QV4::Scoped<QV4::QmlContextWrapper> qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(v4, context, _scopeObject)); QV4::ScopedContext global(valueScope, v4->rootContext()); *_qmlBindingWrapper = v4->memoryManager->alloc<QV4::QmlBindingWrapper>(global, qmlScope); } @@ -1124,7 +1102,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo QBitArray bindingsToSkip; if (customParser) { - QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.find(index); + QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.constFind(index); if (customParserBindings != compiledData->customParserBindings.constEnd()) { customParser->imports = compiledData->importCache; @@ -1183,13 +1161,14 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine)); while (!sharedState->allCreatedBindings.isEmpty()) { - QQmlAbstractBinding *b = sharedState->allCreatedBindings.pop(); - if (!b) + QQmlAbstractBinding::Ptr b = sharedState->allCreatedBindings.pop(); + Q_ASSERT(b); + // skip, if b is not added to an object + if (!b->isAddedToObject()) continue; - b->m_mePtr = 0; - QQmlData *data = QQmlData::get(b->object()); + QQmlData *data = QQmlData::get(b->targetObject()); Q_ASSERT(data); - data->clearPendingBindingBit(b->propertyIndex()); + data->clearPendingBindingBit(b->targetPropertyIndex()); b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); @@ -1299,7 +1278,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * QBitArray bindingSkipList = bindingsToSkip; { - QHash<int, QBitArray>::ConstIterator deferredBindings = compiledData->deferredBindingsPerObject.find(_compiledObjectIndex); + QHash<int, QBitArray>::ConstIterator deferredBindings = compiledData->deferredBindingsPerObject.constFind(_compiledObjectIndex); if (deferredBindings != compiledData->deferredBindingsPerObject.constEnd()) { if (bindingSkipList.isEmpty()) bindingSkipList.resize(deferredBindings->count()); diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 60fefe494f..c88c15b525 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -55,7 +55,7 @@ struct QQmlObjectCreatorSharedState : public QSharedData { QQmlContextData *rootContext; QQmlContextData *creationContext; - QFiniteStack<QQmlAbstractBinding*> allCreatedBindings; + QFiniteStack<QQmlAbstractBinding::Ptr> allCreatedBindings; QFiniteStack<QQmlParserStatus*> allParserStatusCallbacks; QFiniteStack<QPointer<QObject> > allCreatedObjects; QV4::Value *allJavaScriptObjects; // pointer to vector on JS stack to reference JS wrappers during creation phase. diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp index fc24b15fd2..c6d2d44ee1 100644 --- a/src/qml/qml/qqmlopenmetaobject.cpp +++ b/src/qml/qml/qqmlopenmetaobject.cpp @@ -277,8 +277,8 @@ void QQmlOpenMetaObject::setValue(int id, const QVariant &value) QVariant QQmlOpenMetaObject::value(const QByteArray &name) const { - QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name); - if (iter == d->type->d->names.end()) + QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.constFind(name); + if (iter == d->type->d->names.cend()) return QVariant(); return d->getData(*iter); @@ -286,8 +286,8 @@ QVariant QQmlOpenMetaObject::value(const QByteArray &name) const QVariant &QQmlOpenMetaObject::operator[](const QByteArray &name) { - QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name); - Q_ASSERT(iter != d->type->d->names.end()); + QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.constFind(name); + Q_ASSERT(iter != d->type->d->names.cend()); return d->getData(*iter); } @@ -299,10 +299,10 @@ QVariant &QQmlOpenMetaObject::operator[](int id) bool QQmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val) { - QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name); + QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.constFind(name); int id = -1; - if (iter == d->type->d->names.end()) { + if (iter == d->type->d->names.cend()) { id = createProperty(name.constData(), "") - d->type->d->propertyOffset; } else { id = *iter; diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 800f650075..c1120b4542 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -55,6 +55,7 @@ #include <private/qmetaobject_p.h> #include <private/qqmlvaluetypewrapper_p.h> #include <QtCore/qdebug.h> +#include <cmath> Q_DECLARE_METATYPE(QList<int>) Q_DECLARE_METATYPE(QList<qreal>) @@ -699,8 +700,7 @@ QQmlPropertyPrivate::binding(const QQmlProperty &that) if (!that.d || !that.isProperty() || !that.d->object) return 0; - return binding(that.d->object, that.d->core.coreIndex, - that.d->core.getValueTypeCoreIndex()); + return binding(that.d->object, that.d->core.encodedIndex()); } /*! @@ -716,65 +716,96 @@ QQmlPropertyPrivate::binding(const QQmlProperty &that) \a flags is passed through to the binding and is used for the initial update (when the binding sets the initial value, it will use these flags for the write). */ -QQmlAbstractBinding * -QQmlPropertyPrivate::setBinding(const QQmlProperty &that, - QQmlAbstractBinding *newBinding, - WriteFlags flags) +void +QQmlPropertyPrivate::setBinding(const QQmlProperty &that, QQmlAbstractBinding *newBinding) { + if (!newBinding) { + removeBinding(that); + return; + } + if (!that.d || !that.isProperty() || !that.d->object) { - if (newBinding) - newBinding->destroy(); - return 0; + if (!newBinding->ref) + delete newBinding; + return; } + setBinding(newBinding); +} + +static void removeOldBinding(QObject *object, int index, QQmlPropertyPrivate::BindingFlags flags = QQmlPropertyPrivate::None) +{ + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex); - if (newBinding) { - // In the case that the new binding is provided, we must target the property it - // is associated with. If we don't do this, retargetBinding() can fail. - QObject *object = newBinding->object(); - int pi = newBinding->propertyIndex(); + QQmlData *data = QQmlData::get(object, false); - int core; - int vt = QQmlPropertyData::decodeValueTypePropertyIndex(pi, &core); + if (!data || !data->hasBindingBit(coreIndex)) + return; - return setBinding(object, core, vt, newBinding, flags); - } else { - return setBinding(that.d->object, that.d->core.coreIndex, - that.d->core.getValueTypeCoreIndex(), - newBinding, flags); - } + QQmlAbstractBinding::Ptr oldBinding; + oldBinding = data->bindings; + + while (oldBinding && oldBinding->targetPropertyIndex() != coreIndex) + oldBinding = oldBinding->nextBinding(); + + if (!oldBinding) + return; + + if (valueTypeIndex != -1 && oldBinding->isValueTypeProxy()) + oldBinding = static_cast<QQmlValueTypeProxyBinding *>(oldBinding.data())->binding(index); + + if (!oldBinding) + return; + + if (!(flags & QQmlPropertyPrivate::DontEnable)) + oldBinding->setEnabled(false, 0); + oldBinding->removeFromObject(); +} + +void QQmlPropertyPrivate::removeBinding(QQmlAbstractBinding *b) +{ + removeBinding(b->targetObject(), b->targetPropertyIndex()); +} + +void QQmlPropertyPrivate::removeBinding(QObject *o, int index) +{ + Q_ASSERT(o); + + QObject *target; + int targetIndex; + findAliasTarget(o, index, &target, &targetIndex); + removeOldBinding(target, targetIndex); +} + +void QQmlPropertyPrivate::removeBinding(const QQmlProperty &that) +{ + if (!that.d || !that.isProperty() || !that.d->object) + return; + + removeBinding(that.d->object, that.d->core.encodedIndex()); } QQmlAbstractBinding * -QQmlPropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex) +QQmlPropertyPrivate::binding(QObject *object, int index) { QQmlData *data = QQmlData::get(object); if (!data) return 0; - QQmlPropertyData *propertyData = - data->propertyCache?data->propertyCache->property(coreIndex):0; - if (propertyData && propertyData->isAlias()) { - QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); + findAliasTarget(object, index, &object, &index); - QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; - if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1) - return 0; - - // This will either be a value type sub-reference or an alias to a value-type sub-reference not both - Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1); - aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex; - return binding(aObject, aCoreIndex, aValueTypeIndex); - } + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex); if (!data->hasBindingBit(coreIndex)) return 0; QQmlAbstractBinding *binding = data->bindings; - while (binding && binding->propertyIndex() != coreIndex) + while (binding && binding->targetPropertyIndex() != coreIndex) binding = binding->nextBinding(); if (binding && valueTypeIndex != -1) { - if (binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) { + if (binding->isValueTypeProxy()) { int index = QQmlPropertyData::encodeValueTypePropertyIndex(coreIndex, valueTypeIndex); binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index); } @@ -786,11 +817,11 @@ QQmlPropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex) void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex, QObject **targetObject, int *targetBindingIndex) { - int coreIndex; - int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(bindingIndex, &coreIndex); - QQmlData *data = QQmlData::get(object, false); if (data) { + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(bindingIndex, &coreIndex); + QQmlPropertyData *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; if (propertyData && propertyData->isAlias()) { @@ -817,119 +848,30 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex, *targetBindingIndex = bindingIndex; } -QQmlAbstractBinding * -QQmlPropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex, - QQmlAbstractBinding *newBinding, WriteFlags flags) -{ - QQmlData *data = QQmlData::get(object, 0 != newBinding); - QQmlAbstractBinding *binding = 0; - - if (data) { - QQmlPropertyData *propertyData = - data->propertyCache?data->propertyCache->property(coreIndex):0; - if (propertyData && propertyData->isAlias()) { - QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); - - QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; - if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) { - if (newBinding) newBinding->destroy(); - return 0; - } - - // This will either be a value type sub-reference or an alias to a value-type sub-reference not both - Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1); - aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex; - return setBinding(aObject, aCoreIndex, aValueTypeIndex, newBinding, flags); - } - } - - if (data && data->hasBindingBit(coreIndex)) { - binding = data->bindings; - - while (binding && binding->propertyIndex() != coreIndex) - binding = binding->nextBinding(); - } - - int index = coreIndex; - if (valueTypeIndex != -1) - index = QQmlPropertyData::encodeValueTypePropertyIndex(index, valueTypeIndex); - - if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) - binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index); - - if (binding) { - binding->removeFromObject(); - binding->setEnabled(false, 0); - } - - if (newBinding) { - if (newBinding->propertyIndex() != index || newBinding->object() != object) - newBinding->retargetBinding(object, index); - - Q_ASSERT(newBinding->propertyIndex() == index); - Q_ASSERT(newBinding->object() == object); - - newBinding->addToObject(); - newBinding->setEnabled(true, flags); - } - - return binding; -} -QQmlAbstractBinding * -QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex, - QQmlAbstractBinding *newBinding) +void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, WriteFlags writeFlags) { - QQmlData *data = QQmlData::get(object, 0 != newBinding); - QQmlAbstractBinding *binding = 0; - - if (data) { - QQmlPropertyData *propertyData = - data->propertyCache?data->propertyCache->property(coreIndex):0; - if (propertyData && propertyData->isAlias()) { - QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); - - QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; - if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) { - if (newBinding) newBinding->destroy(); - return 0; - } + Q_ASSERT(binding); - // This will either be a value type sub-reference or an alias to a value-type sub-reference not both - Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1); - aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex; - return setBindingNoEnable(aObject, aCoreIndex, aValueTypeIndex, newBinding); - } - } + QObject *object = binding->targetObject(); + int index = binding->targetPropertyIndex(); - if (data && data->hasBindingBit(coreIndex)) { - binding = data->bindings; - - while (binding && binding->propertyIndex() != coreIndex) - binding = binding->nextBinding(); +#ifndef QT_NO_DEBUG + int coreIndex; + QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex); + QQmlData *data = QQmlData::get(object, true); + if (data->propertyCache) { + QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); + Q_ASSERT(propertyData && !propertyData->isAlias()); } +#endif - int index = coreIndex; - if (valueTypeIndex != -1) - index = QQmlPropertyData::encodeValueTypePropertyIndex(index, valueTypeIndex); - - if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) - binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index); - - if (binding) - binding->removeFromObject(); - - if (newBinding) { - if (newBinding->propertyIndex() != index || newBinding->object() != object) - newBinding->retargetBinding(object, index); - - Q_ASSERT(newBinding->propertyIndex() == index); - Q_ASSERT(newBinding->object() == object); + removeOldBinding(object, index, flags); - newBinding->addToObject(); - } + binding->addToObject(); + if (!(flags & DontEnable)) + binding->setEnabled(true, writeFlags); - return binding; } /*! @@ -946,9 +888,9 @@ QQmlPropertyPrivate::signalExpression(const QQmlProperty &that) if (!data) return 0; - QQmlAbstractBoundSignal *signalHandler = data->signalHandlers; + QQmlBoundSignal *signalHandler = data->signalHandlers; - while (signalHandler && signalHandler->index() != QQmlPropertyPrivate::get(that)->signalIndex()) + while (signalHandler && signalHandler->signalIndex() != QQmlPropertyPrivate::get(that)->signalIndex()) signalHandler = signalHandler->m_nextSignal; if (signalHandler) @@ -959,48 +901,41 @@ QQmlPropertyPrivate::signalExpression(const QQmlProperty &that) /*! Set the signal expression associated with this signal property to \a expr. - Returns the existing signal expression (if any), otherwise null. - - A reference to \a expr will be added by QML. Ownership of the return value - reference is assumed by the caller. + A reference to \a expr will be added by QML. */ -QQmlBoundSignalExpressionPointer -QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that, - QQmlBoundSignalExpression *expr) +void QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *expr) { if (expr) expr->addref(); - return QQmlPropertyPrivate::takeSignalExpression(that, expr); + QQmlPropertyPrivate::takeSignalExpression(that, expr); } /*! Set the signal expression associated with this signal property to \a expr. - Returns the existing signal expression (if any), otherwise null. - - Ownership of \a expr transfers to QML. Ownership of the return value - reference is assumed by the caller. + Ownership of \a expr transfers to QML. */ -QQmlBoundSignalExpressionPointer -QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that, +void QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *expr) { if (!(that.type() & QQmlProperty::SignalProperty)) { if (expr) expr->release(); - return 0; + return; } QQmlData *data = QQmlData::get(that.d->object, 0 != expr); if (!data) - return 0; + return; - QQmlAbstractBoundSignal *signalHandler = data->signalHandlers; + QQmlBoundSignal *signalHandler = data->signalHandlers; - while (signalHandler && signalHandler->index() != QQmlPropertyPrivate::get(that)->signalIndex()) + while (signalHandler && signalHandler->signalIndex() != QQmlPropertyPrivate::get(that)->signalIndex()) signalHandler = signalHandler->m_nextSignal; - if (signalHandler) - return signalHandler->takeExpression(expr); + if (signalHandler) { + signalHandler->takeExpression(expr); + return; + } if (expr) { int signalIndex = QQmlPropertyPrivate::get(that)->signalIndex(); @@ -1008,7 +943,6 @@ QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that, expr->context()->engine); signal->takeExpression(expr); } - return 0; } /*! @@ -1125,7 +1059,7 @@ QVariant QQmlPropertyPrivate::readValueProperty() } // helper function to allow assignment / binding to QList<QUrl> properties. -static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context) +QVariant QQmlPropertyPrivate::resolvedUrlSequence(const QVariant &value, QQmlContextData *context) { QList<QUrl> urls; if (value.userType() == qMetaTypeId<QUrl>()) { @@ -1138,16 +1072,22 @@ static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *cont urls = value.value<QList<QUrl> >(); } else if (value.userType() == qMetaTypeId<QStringList>()) { QStringList urlStrings = value.value<QStringList>(); - for (int i = 0; i < urlStrings.size(); ++i) + const int urlStringsSize = urlStrings.size(); + urls.reserve(urlStringsSize); + for (int i = 0; i < urlStringsSize; ++i) urls.append(QUrl(urlStrings.at(i))); } else if (value.userType() == qMetaTypeId<QList<QString> >()) { QList<QString> urlStrings = value.value<QList<QString> >(); - for (int i = 0; i < urlStrings.size(); ++i) + const int urlStringsSize = urlStrings.size(); + urls.reserve(urlStringsSize); + for (int i = 0; i < urlStringsSize; ++i) urls.append(QUrl(urlStrings.at(i))); } // note: QList<QByteArray> is not currently supported. QList<QUrl> resolvedUrls; - for (int i = 0; i < urls.size(); ++i) { + const int urlsSize = urls.size(); + resolvedUrls.reserve(urlsSize); + for (int i = 0; i < urlsSize; ++i) { QUrl u = urls.at(i); if (context && u.isRelative() && !u.isEmpty()) u = context->resolvedUrl(u); @@ -1210,12 +1150,8 @@ QQmlPropertyPrivate::writeValueProperty(QObject *object, QQmlContextData *context, WriteFlags flags) { // Remove any existing bindings on this property - if (!(flags & DontRemoveBinding) && object) { - QQmlAbstractBinding *binding = setBinding(object, core.coreIndex, - core.getValueTypeCoreIndex(), - 0, flags); - if (binding) binding->destroy(); - } + if (!(flags & DontRemoveBinding) && object) + removeBinding(object, core.encodedIndex()); bool rv = false; if (core.isValueTypeVirtual()) { @@ -1255,7 +1191,7 @@ bool QQmlPropertyPrivate::write(QObject *object, // Enum values come through the script engine as doubles if (value.userType() == QVariant::Double) { double integral; - double fractional = modf(value.toDouble(), &integral); + double fractional = std::modf(value.toDouble(), &integral); if (qFuzzyIsNull(fractional)) v.convert(QVariant::Int); } @@ -1475,166 +1411,6 @@ bool QQmlPropertyPrivate::write(QObject *object, return true; } -// Returns true if successful, false if an error description was set on expression -bool QQmlPropertyPrivate::writeBinding(QObject *object, - const QQmlPropertyData &core, - QQmlContextData *context, - QQmlJavaScriptExpression *expression, - const QV4::Value &result, bool isUndefined, - WriteFlags flags) -{ - Q_ASSERT(object); - Q_ASSERT(core.coreIndex != -1); - - QQmlEngine *engine = context->engine; - QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine); - -#define QUICK_STORE(cpptype, conversion) \ - { \ - cpptype o = (conversion); \ - int status = -1; \ - void *argv[] = { &o, 0, &status, &flags }; \ - QMetaObject::metacall(object, QMetaObject::WriteProperty, core.coreIndex, argv); \ - return true; \ - } \ - - - if (!isUndefined && !core.isValueTypeVirtual()) { - switch (core.propType) { - case QMetaType::Int: - if (result.isInteger()) - QUICK_STORE(int, result.integerValue()) - else if (result.isNumber()) - QUICK_STORE(int, result.doubleValue()) - break; - case QMetaType::Double: - if (result.isNumber()) - QUICK_STORE(double, result.asDouble()) - break; - case QMetaType::Float: - if (result.isNumber()) - QUICK_STORE(float, result.asDouble()) - break; - case QMetaType::QString: - if (result.isString()) - QUICK_STORE(QString, result.toQStringNoThrow()) - break; - default: - if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) { - if (vtw->d()->valueType->typeId == core.propType) { - return vtw->write(object, core.coreIndex); - } - } - break; - } - } -#undef QUICK_STORE - - int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType; - - QQmlJavaScriptExpression::DeleteWatcher watcher(expression); - - QVariant value; - bool isVarProperty = core.isVarProperty(); - - if (isUndefined) { - } else if (core.isQList()) { - value = QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QObject *> >()); - } else if (result.isNull() && core.isQObject()) { - value = QVariant::fromValue((QObject *)0); - } else if (core.propType == qMetaTypeId<QList<QUrl> >()) { - value = resolvedUrlSequence(QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QUrl> >()), context); - } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) { - value = QV8Engine::getV4(v8engine)->toVariant(result, type); - } - - if (expression->hasError()) { - return false; - } else if (isVarProperty) { - QV4::FunctionObject *f = result.asFunctionObject(); - if (f && f->isBinding()) { - // we explicitly disallow this case to avoid confusion. Users can still store one - // in an array in a var property if they need to, but the common case is user error. - expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); - expression->delayedError()->setErrorObject(object); - return false; - } - - QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); - Q_ASSERT(vmemo); - vmemo->setVMEProperty(core.coreIndex, result); - } else if (isUndefined && core.isResettable()) { - void *args[] = { 0 }; - QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args); - } else if (isUndefined && type == qMetaTypeId<QVariant>()) { - writeValueProperty(object, core, QVariant(), context, flags); - } else if (type == qMetaTypeId<QJSValue>()) { - QV4::FunctionObject *f = result.asFunctionObject(); - if (f && f->isBinding()) { - expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); - expression->delayedError()->setErrorObject(object); - return false; - } - writeValueProperty(object, core, QVariant::fromValue( - QJSValue(QV8Engine::getV4(v8engine), result.asReturnedValue())), - context, flags); - } else if (isUndefined) { - QString errorStr = QLatin1String("Unable to assign [undefined] to "); - if (!QMetaType::typeName(type)) - errorStr += QLatin1String("[unknown property type]"); - else - errorStr += QLatin1String(QMetaType::typeName(type)); - expression->delayedError()->setErrorDescription(errorStr); - expression->delayedError()->setErrorObject(object); - return false; - } else if (QV4::FunctionObject *f = result.asFunctionObject()) { - if (f->isBinding()) - expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); - else - expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var.")); - expression->delayedError()->setErrorObject(object); - return false; - } else if (!writeValueProperty(object, core, value, context, flags)) { - - if (watcher.wasDeleted()) - return true; - - const char *valueType = 0; - const char *propertyType = 0; - - if (value.userType() == QMetaType::QObjectStar) { - if (QObject *o = *(QObject *const *)value.constData()) { - valueType = o->metaObject()->className(); - - QQmlMetaObject propertyMetaObject = rawMetaObjectForType(QQmlEnginePrivate::get(engine), type); - if (!propertyMetaObject.isNull()) - propertyType = propertyMetaObject.className(); - } - } else if (value.userType() != QVariant::Invalid) { - if (value.userType() == QMetaType::VoidStar) - valueType = "null"; - else - valueType = QMetaType::typeName(value.userType()); - } - - if (!valueType) - valueType = "undefined"; - if (!propertyType) - propertyType = QMetaType::typeName(type); - if (!propertyType) - propertyType = "[unknown property type]"; - - expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign ") + - QLatin1String(valueType) + - QLatin1String(" to ") + - QLatin1String(propertyType)); - expression->delayedError()->setErrorObject(object); - return false; - } - - return true; -} - QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType) { QMetaType metaType(userType); diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h index 98e310ebce..51a1db7b90 100644 --- a/src/qml/qml/qqmlproperty_p.h +++ b/src/qml/qml/qqmlproperty_p.h @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE class QQmlContext; class QQmlEnginePrivate; class QQmlJavaScriptExpression; + class Q_QML_PRIVATE_EXPORT QQmlPropertyPrivate : public QQmlRefCount { public: @@ -103,15 +104,18 @@ public: QQmlContextData *, WriteFlags flags = 0); static void findAliasTarget(QObject *, int, QObject **, int *); - static QQmlAbstractBinding *setBinding(QObject *, int coreIndex, - int valueTypeIndex /* -1 */, - QQmlAbstractBinding *, - WriteFlags flags = DontRemoveBinding); - static QQmlAbstractBinding *setBindingNoEnable(QObject *, int coreIndex, - int valueTypeIndex /* -1 */, - QQmlAbstractBinding *); - static QQmlAbstractBinding *binding(QObject *, int coreIndex, - int valueTypeIndex /* -1 */); + enum BindingFlag { + None = 0, + DontEnable = 0x1 + }; + Q_DECLARE_FLAGS(BindingFlags, BindingFlag) + + static void setBinding(QQmlAbstractBinding *binding, BindingFlags flags = None, WriteFlags writeFlags = DontRemoveBinding); + + static void removeBinding(const QQmlProperty &that); + static void removeBinding(QObject *o, int index); + static void removeBinding(QQmlAbstractBinding *b); + static QQmlAbstractBinding *binding(QObject *, int index); static QQmlPropertyData saveValueType(const QQmlPropertyData &, const QMetaObject *, int, @@ -128,20 +132,13 @@ public: // "Public" (to QML) methods static QQmlAbstractBinding *binding(const QQmlProperty &that); - static QQmlAbstractBinding *setBinding(const QQmlProperty &that, - QQmlAbstractBinding *, - WriteFlags flags = DontRemoveBinding); + static void setBinding(const QQmlProperty &that, QQmlAbstractBinding *); static QQmlBoundSignalExpression *signalExpression(const QQmlProperty &that); - static QQmlBoundSignalExpressionPointer setSignalExpression(const QQmlProperty &that, + static void setSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *); - static QQmlBoundSignalExpressionPointer takeSignalExpression(const QQmlProperty &that, + static void takeSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *); static bool write(const QQmlProperty &that, const QVariant &, WriteFlags); - static bool writeBinding(QObject *, const QQmlPropertyData &, - QQmlContextData *context, - QQmlJavaScriptExpression *expression, - const QV4::Value &result, bool isUndefined, - WriteFlags flags); static int valueTypeCoreIndex(const QQmlProperty &that); static int bindingIndex(const QQmlProperty &that); static int bindingIndex(const QQmlPropertyData &that); @@ -150,9 +147,12 @@ public: const QObject *receiver, int method_index, int type = 0, int *types = 0); static void flushSignal(const QObject *sender, int signal_index); + + static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context); }; Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::WriteFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::BindingFlags) QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 0018275b95..cd8eb0d3e2 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -42,7 +42,7 @@ #include <private/qqmlaccessors_p.h> #include <private/qmetaobjectbuilder_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <QtCore/qdebug.h> @@ -837,7 +837,7 @@ void QQmlPropertyCache::updateRecur(const QMetaObject *metaObject) void QQmlPropertyCache::update(const QMetaObject *metaObject) { Q_ASSERT(metaObject); - Q_ASSERT(stringCache.isEmpty()); + stringCache.clear(); // Preallocate enough space in the index caches for all the properties/methods/signals that // are not cached in a parent cache so that the caches never need to be reallocated as this @@ -862,7 +862,6 @@ void QQmlPropertyCache::update(const QMetaObject *metaObject) */ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject) { - stringCache.clear(); propertyIndexCache.clear(); methodIndexCache.clear(); signalHandlerIndexCache.clear(); diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 6ed9ec0d36..4d8c6dd9a5 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -54,7 +54,7 @@ #include <QtCore/qvarlengtharray.h> #include <QtCore/qvector.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> QT_BEGIN_NAMESPACE @@ -174,7 +174,6 @@ public: int propType; // When !NotFullyResolved const char *propTypeName; // When NotFullyResolved }; - int coreIndex; union { // The notify index is in the range returned by QObjectPrivate::signalIndex(). // This is different from QMetaMethod::methodIndex(). @@ -208,6 +207,7 @@ public: qintptr accessorData; }; }; + int coreIndex; private: friend class QQmlPropertyData; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index d713e9ee03..408f17ffde 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -81,7 +81,7 @@ #define ASSERT_MAINTHREAD() do { if (m_thread->isThisThread()) qFatal("QQmlTypeLoader: Caller not in main thread"); } while (false) #define ASSERT_LOADTHREAD() do { if (!m_thread->isThisThread()) qFatal("QQmlTypeLoader: Caller not in load thread"); } while (false) -#define ASSERT_CALLBACK() do { if(!m_manager || !m_manager->m_thread->isThisThread()) qFatal("QQmlDataBlob: An API call was made outside a callback"); } while(false) +#define ASSERT_CALLBACK() do { if (!m_typeLoader || !m_typeLoader->m_thread->isThisThread()) qFatal("QQmlDataBlob: An API call was made outside a callback"); } while (false) #else @@ -1612,6 +1612,20 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode) } else { QQmlTypeLoader::load(typeData, mode); } + } else if ((mode == PreferSynchronous) && QQmlFile::isSynchronous(url)) { + // this was started Asynchronous, but we need to force Synchronous + // completion now (if at all possible with this type of URL). + + if (!m_thread->isThisThread()) { + // this only works when called directly from the UI thread, but not + // when recursively called on the QML thread via resolveTypes() + + while (!typeData->isCompleteOrError()) { + unlock(); + m_thread->waitForNextMessage(); + lock(); + } + } } typeData->addref(); @@ -2114,6 +2128,7 @@ void QQmlTypeData::dataReceived(const Data &data) QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames()); if (!compiler.generateFromQml(code, finalUrlString(), m_document.data())) { QList<QQmlError> errors; + errors.reserve(compiler.errors.count()); foreach (const QQmlJS::DiagnosticMessage &msg, compiler.errors) { QQmlError e; e.setUrl(finalUrl()); @@ -2519,8 +2534,8 @@ QV4::PersistentValue QQmlScriptData::scriptValueForContext(QQmlContextData *pare return QV4::PersistentValue(); } - QV4::ScopedValue qmlglobal(scope, QV4::QmlContextWrapper::qmlScope(v4, ctxt, 0)); - QV4::QmlContextWrapper::takeContextOwnership(qmlglobal); + QV4::Scoped<QV4::QmlContextWrapper> qmlglobal(scope, QV4::QmlContextWrapper::qmlScope(v4, ctxt, 0)); + qmlglobal->takeContextOwnership(); m_program->qml.set(scope.engine, qmlglobal); m_program->run(); @@ -2594,7 +2609,7 @@ void QQmlScriptBlob::dataReceived(const Data &data) return; } if (!unit) { - unit.take(new EmptyCompilationUnit); + unit.adopt(new EmptyCompilationUnit); } irUnit.javaScriptCompilationUnit = unit; irUnit.imports = collector.imports; diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index d9ea273698..5be478fa65 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -60,7 +60,7 @@ #include <private/qflagpointer_p.h> #include <private/qqmlirbuilder_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4script_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp index d0658f2c3c..23cc12c895 100644 --- a/src/qml/qml/qqmltypenamecache.cpp +++ b/src/qml/qml/qqmltypenamecache.cpp @@ -125,7 +125,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, cons const Import *i = static_cast<const Import *>(importNamespace); Q_ASSERT(i->scriptIndex == -1); - QMap<const Import *, QStringHash<Import> >::const_iterator it = m_namespacedImports.find(i); + QMap<const Import *, QStringHash<Import> >::const_iterator it = m_namespacedImports.constFind(i); if (it != m_namespacedImports.constEnd()) { Result r = query(*it, name); if (r.isValid()) diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 8a2118ef27..1d72b2da0d 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -124,19 +124,19 @@ ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, Q } -ReturnedValue QmlTypeWrapper::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QmlTypeWrapper>()); - QV4::ExecutionEngine *v4 = static_cast<QmlTypeWrapper *>(m)->engine(); + QV4::ExecutionEngine *v4 = static_cast<const QmlTypeWrapper *>(m)->engine(); QV4::Scope scope(v4); - Scoped<QmlTypeWrapper> w(scope, static_cast<QmlTypeWrapper *>(m)); + Scoped<QmlTypeWrapper> w(scope, static_cast<const QmlTypeWrapper *>(m)); if (hasProperty) *hasProperty = true; - QQmlContextData *context = v4->v8Engine->callingContext(); + QQmlContextData *context = v4->callingQmlContext(); QObject *object = w->d()->object; @@ -240,7 +240,7 @@ void QmlTypeWrapper::put(Managed *m, String *name, const Value &value) return; QV4::Scope scope(v4); - QQmlContextData *context = v4->v8Engine->callingContext(); + QQmlContextData *context = v4->callingQmlContext(); QQmlType *type = w->d()->type; if (type && !type->isSingleton() && w->d()->object) { diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index 660d2836ff..14741a5bad 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -48,7 +48,7 @@ #include <QtCore/qglobal.h> #include <QtCore/qpointer.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> QT_BEGIN_NAMESPACE @@ -94,7 +94,7 @@ struct Q_QML_EXPORT QmlTypeWrapper : Object Heap::QmlTypeWrapper::TypeNameMode = Heap::QmlTypeWrapper::IncludeEnums); - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); static PropertyAttributes query(const Managed *, String *name); static bool isEqualTo(Managed *that, Managed *o); diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp index 10eaae0c77..6a71a07e9b 100644 --- a/src/qml/qml/qqmlvaluetype.cpp +++ b/src/qml/qml/qqmlvaluetype.cpp @@ -517,7 +517,9 @@ void QQmlEasingValueType::setBezierCurve(const QVariantList &customCurveVariant) if ((variantList.count() % 6) == 0) { bool allRealsOk = true; QList<qreal> reals; - for (int i = 0; i < variantList.count(); i++) { + const int variantListCount = variantList.count(); + reals.reserve(variantListCount); + for (int i = 0; i < variantListCount; i++) { bool ok; const qreal real = variantList.at(i).toReal(&ok); reals.append(real); diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h index 2c02cc0aa1..abd73d7f35 100644 --- a/src/qml/qml/qqmlvaluetype_p.h +++ b/src/qml/qml/qqmlvaluetype_p.h @@ -209,7 +209,6 @@ struct QQmlEasingValueType { QEasingCurve v; Q_GADGET - Q_ENUMS(Type) Q_PROPERTY(QQmlEasingValueType::Type type READ type WRITE setType FINAL) Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude FINAL) @@ -243,6 +242,7 @@ public: SineCurve = QEasingCurve::SineCurve, CosineCurve = QEasingCurve::CosineCurve, Bezier = QEasingCurve::BezierSpline }; + Q_ENUM(Type) Type type() const; qreal amplitude() const; diff --git a/src/qml/qml/qqmlvaluetypeproxybinding.cpp b/src/qml/qml/qqmlvaluetypeproxybinding.cpp index cfc9b196d2..3bc8493cbb 100644 --- a/src/qml/qml/qqmlvaluetypeproxybinding.cpp +++ b/src/qml/qml/qqmlvaluetypeproxybinding.cpp @@ -35,80 +35,42 @@ QT_BEGIN_NAMESPACE -// Used in qqmlabstractbinding.cpp -QQmlAbstractBinding::VTable QQmlValueTypeProxyBinding_vtable = { - QQmlAbstractBinding::default_destroy<QQmlValueTypeProxyBinding>, - QQmlAbstractBinding::default_expression, - QQmlValueTypeProxyBinding::propertyIndex, - QQmlValueTypeProxyBinding::object, - QQmlValueTypeProxyBinding::setEnabled, - QQmlValueTypeProxyBinding::update, - QQmlAbstractBinding::default_retargetBinding -}; - QQmlValueTypeProxyBinding::QQmlValueTypeProxyBinding(QObject *o, int index) -: QQmlAbstractBinding(ValueTypeProxy), m_object(o), m_index(index), m_bindings(0) + : QQmlAbstractBinding(), + m_bindings(0) { + m_target = o; + m_targetIndex = index; } QQmlValueTypeProxyBinding::~QQmlValueTypeProxyBinding() { - QQmlAbstractBinding *binding = m_bindings; - // This must be identical to the logic in QQmlData::destroyed() + QQmlAbstractBinding *binding = m_bindings.data(); while (binding) { - QQmlAbstractBinding *next = binding->nextBinding(); binding->setAddedToObject(false); - binding->setNextBinding(0); - binding->destroy(); - binding = next; + binding = binding->nextBinding(); } } -void QQmlValueTypeProxyBinding::setEnabled(QQmlAbstractBinding *_This, - bool e, QQmlPropertyPrivate::WriteFlags flags) +void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags) { - QQmlValueTypeProxyBinding *This = static_cast<QQmlValueTypeProxyBinding *>(_This); - - if (e) { - QQmlAbstractBinding *bindings = This->m_bindings; - This->recursiveEnable(bindings, flags); - } else { - QQmlAbstractBinding *bindings = This->m_bindings; - This->recursiveDisable(bindings); + QQmlAbstractBinding *b = m_bindings.data(); + while (b) { + b->setEnabled(e, flags); + b = b->nextBinding(); } } -void QQmlValueTypeProxyBinding::recursiveEnable(QQmlAbstractBinding *b, QQmlPropertyPrivate::WriteFlags flags) -{ - if (!b) - return; - - recursiveEnable(b->nextBinding(), flags); - - if (b) - b->setEnabled(true, flags); -} - -void QQmlValueTypeProxyBinding::recursiveDisable(QQmlAbstractBinding *b) -{ - if (!b) - return; - - recursiveDisable(b->nextBinding()); - - if (b) - b->setEnabled(false, 0); -} - -void QQmlValueTypeProxyBinding::update(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags) +bool QQmlValueTypeProxyBinding::isValueTypeProxy() const { + return true; } QQmlAbstractBinding *QQmlValueTypeProxyBinding::binding(int propertyIndex) { - QQmlAbstractBinding *binding = m_bindings; + QQmlAbstractBinding *binding = m_bindings.data(); - while (binding && binding->propertyIndex() != propertyIndex) + while (binding && binding->targetPropertyIndex() != propertyIndex) binding = binding->nextBinding(); return binding; @@ -119,23 +81,20 @@ Removes a collection of bindings, corresponding to the set bits in \a mask. */ void QQmlValueTypeProxyBinding::removeBindings(quint32 mask) { - QQmlAbstractBinding *binding = m_bindings; + QQmlAbstractBinding *binding = m_bindings.data(); QQmlAbstractBinding *lastBinding = 0; while (binding) { - int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(binding->propertyIndex()); + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(binding->targetPropertyIndex()); if (valueTypeIndex != -1 && (mask & (1 << valueTypeIndex))) { QQmlAbstractBinding *remove = binding; + remove->setAddedToObject(false); binding = remove->nextBinding(); if (lastBinding == 0) m_bindings = remove->nextBinding(); else lastBinding->setNextBinding(remove->nextBinding()); - - remove->setAddedToObject(false); - remove->setNextBinding(0); - remove->destroy(); } else { lastBinding = binding; binding = binding->nextBinding(); @@ -143,24 +102,4 @@ void QQmlValueTypeProxyBinding::removeBindings(quint32 mask) } } -int QQmlValueTypeProxyBinding::propertyIndex(const QQmlAbstractBinding *This) -{ - return static_cast<const QQmlValueTypeProxyBinding *>(This)->m_index; -} - -QObject *QQmlValueTypeProxyBinding::object(const QQmlAbstractBinding *This) -{ - return static_cast<const QQmlValueTypeProxyBinding *>(This)->m_object; -} - -int QQmlValueTypeProxyBinding::propertyIndex() const -{ - return m_index; -} - -QObject *QQmlValueTypeProxyBinding::object() const -{ - return m_object; -} - QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlvaluetypeproxybinding_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h index 873fbb4af1..4afadfc17d 100644 --- a/src/qml/qml/qqmlvaluetypeproxybinding_p.h +++ b/src/qml/qml/qqmlvaluetypeproxybinding_p.h @@ -54,30 +54,18 @@ class QQmlValueTypeProxyBinding : public QQmlAbstractBinding public: QQmlValueTypeProxyBinding(QObject *o, int coreIndex); - int propertyIndex() const; - QObject *object() const; - - QQmlAbstractBinding *binding(int propertyIndex); - + QQmlAbstractBinding *binding(int targetPropertyIndex); void removeBindings(quint32 mask); - // "Inherited" from QQmlAbstractBinding - static void setEnabled(QQmlAbstractBinding *, bool, QQmlPropertyPrivate::WriteFlags); - static void update(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags); - static int propertyIndex(const QQmlAbstractBinding *); - static QObject *object(const QQmlAbstractBinding *); + virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags); + virtual bool isValueTypeProxy() const; protected: ~QQmlValueTypeProxyBinding(); private: - void recursiveEnable(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags); - void recursiveDisable(QQmlAbstractBinding *); - friend class QQmlAbstractBinding; - QObject *m_object; - int m_index; - QQmlAbstractBinding *m_bindings; + Ptr m_bindings; }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index e87d9ede77..b0ab85199d 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -43,7 +43,6 @@ #include <private/qv4engine_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4variantobject_p.h> -#include <private/qv4qmlextensions_p.h> #include <private/qv4alloca_p.h> QT_BEGIN_NAMESPACE @@ -165,13 +164,13 @@ bool QQmlValueTypeReference::readReferenceValue() const void QQmlValueTypeWrapper::initProto(ExecutionEngine *v4) { - if (v4->qmlExtensions()->valueTypeWrapperPrototype) + if (v4->valueTypeWrapperPrototype()->as<Object>()) return; Scope scope(v4); ScopedObject o(scope, v4->newObject()); - o->defineDefaultProperty(v4->id_toString, method_toString, 1); - v4->qmlExtensions()->valueTypeWrapperPrototype = o->d(); + o->defineDefaultProperty(v4->id_toString(), method_toString, 1); + v4->jsObjects[QV4::ExecutionEngine::ValueTypeProto] = o->d(); } ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *object, int property, const QMetaObject *metaObject, int typeId) @@ -180,7 +179,7 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *obj initProto(engine); Scoped<QQmlValueTypeReference> r(scope, engine->memoryManager->alloc<QQmlValueTypeReference>(engine)); - ScopedObject proto(scope, engine->qmlExtensions()->valueTypeWrapperPrototype); + ScopedObject proto(scope, engine->valueTypeWrapperPrototype()); r->setPrototype(proto); r->d()->object = object; r->d()->property = property; r->d()->propertyCache = QJSEnginePrivate::get(engine)->cache(metaObject); @@ -195,7 +194,7 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVaria initProto(engine); Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->alloc<QQmlValueTypeWrapper>(engine)); - ScopedObject proto(scope, engine->qmlExtensions()->valueTypeWrapperPrototype); + ScopedObject proto(scope, engine->valueTypeWrapperPrototype()); r->setPrototype(proto); r->d()->propertyCache = QJSEnginePrivate::get(engine)->cache(metaObject); r->d()->valueType = QQmlValueTypeFactory::valueType(typeId); @@ -292,7 +291,7 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx) { - Object *o = ctx->thisObject().asObject(); + Object *o = ctx->thisObject().as<Object>(); if (!o) return ctx->engine()->throwTypeError(); QQmlValueTypeWrapper *w = o->as<QQmlValueTypeWrapper>(); @@ -327,14 +326,14 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx) return Encode(ctx->engine()->newString(result)); } -ReturnedValue QQmlValueTypeWrapper::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QQmlValueTypeWrapper>()); - QQmlValueTypeWrapper *r = static_cast<QQmlValueTypeWrapper *>(m); + const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m); QV4::ExecutionEngine *v4 = r->engine(); // Note: readReferenceValue() can change the reference->type. - if (QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) { + if (const QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) { if (!reference->readReferenceValue()) return Primitive::undefinedValue().asReturnedValue(); } @@ -410,45 +409,41 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) QMetaProperty property = metaObject->property(pd->coreIndex); Q_ASSERT(property.isValid()); - QQmlBinding *newBinding = 0; - - QV4::ScopedFunctionObject f(scope, value); - if (reference && f) { - if (!f->isBinding()) { - // assigning a JS function to a non-var-property is not allowed. - QString error = QStringLiteral("Cannot assign JavaScript function to value-type property"); - ScopedString e(scope, v4->newString(error)); - v4->throwError(e); - return; - } + if (reference) { + QV4::ScopedFunctionObject f(scope, value); + if (f) { + if (!f->isBinding()) { + // assigning a JS function to a non-var-property is not allowed. + QString error = QStringLiteral("Cannot assign JavaScript function to value-type property"); + ScopedString e(scope, v4->newString(error)); + v4->throwError(e); + return; + } - QQmlContextData *context = QmlContextWrapper::callingContext(v4); + QQmlContextData *context = v4->callingQmlContext(); - QQmlPropertyData cacheData; - cacheData.setFlags(QQmlPropertyData::IsWritable | - QQmlPropertyData::IsValueTypeVirtual); - cacheData.propType = writeBackPropertyType; - cacheData.coreIndex = reference->d()->property; - cacheData.valueTypeFlags = 0; - cacheData.valueTypeCoreIndex = pd->coreIndex; - cacheData.valueTypePropType = property.userType(); + QQmlPropertyData cacheData; + cacheData.setFlags(QQmlPropertyData::IsWritable | + QQmlPropertyData::IsValueTypeVirtual); + cacheData.propType = writeBackPropertyType; + cacheData.coreIndex = reference->d()->property; + cacheData.valueTypeFlags = 0; + cacheData.valueTypeCoreIndex = pd->coreIndex; + cacheData.valueTypePropType = property.userType(); - QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); - bindingFunction->initBindingLocation(); + QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); + bindingFunction->initBindingLocation(); - newBinding = new QQmlBinding(value, reference->d()->object, context); - newBinding->setTarget(reference->d()->object, cacheData, context); - } + QQmlBinding *newBinding = new QQmlBinding(value, reference->d()->object, context); + newBinding->setTarget(reference->d()->object, cacheData); + QQmlPropertyPrivate::setBinding(newBinding); + return; + } else { + QQmlPropertyPrivate::removeBinding(reference->d()->object, QQmlPropertyData::encodeValueTypePropertyIndex(reference->d()->property, pd->coreIndex)); - if (reference) { - QQmlAbstractBinding *oldBinding = - QQmlPropertyPrivate::setBinding(reference->d()->object, reference->d()->property, pd->coreIndex, newBinding); - if (oldBinding) - oldBinding->destroy(); + } } - if (newBinding) - return; QVariant v = v4->toVariant(value, property.userType()); diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h index cad48e661c..5f0edfb71d 100644 --- a/src/qml/qml/qqmlvaluetypewrapper_p.h +++ b/src/qml/qml/qqmlvaluetypewrapper_p.h @@ -48,7 +48,7 @@ #include <QtCore/qglobal.h> #include <private/qtqmlglobal_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> QT_BEGIN_NAMESPACE @@ -89,7 +89,7 @@ public: int typeId() const; bool write(QObject *target, int propertyIndex) const; - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); static bool isEqualTo(Managed *m, Managed *other); static PropertyAttributes query(const Managed *, String *name); diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 97fc382c33..9f02c905fc 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -104,13 +104,11 @@ public: inline double asDouble(); inline const QString &asQString(); inline const QUrl &asQUrl(); - inline const QTime &asQTime(); inline const QDate &asQDate(); inline const QDateTime &asQDateTime(); inline const QRectF &asQRectF(); inline const QPointF &asQPointF(); inline const QSizeF &asQSizeF(); - inline const QJSValue &asQJSValue(); inline void setValue(QObject *v, QQmlVMEMetaObject *target, int index); inline void setValue(const QVariant &); @@ -125,9 +123,6 @@ public: inline void setValue(const QRectF &); inline void setValue(const QPointF &); inline void setValue(const QSizeF &); - inline void setValue(const QJSValue &); - - inline void setDataType(int t); inline void ensureValueType(int); @@ -196,9 +191,6 @@ void QQmlVMEVariant::cleanup() } else if (type == qMetaTypeId<QVariant>()) { ((QVariant *)dataPtr())->~QVariant(); type = QVariant::Invalid; - } else if (type == qMetaTypeId<QJSValue>()) { - ((QJSValue *)dataPtr())->~QJSValue(); - type = QVariant::Invalid; } else { if (QQml_valueTypeProvider()->destroyValueType(type, dataPtr(), dataSize())) { type = QVariant::Invalid; @@ -282,14 +274,6 @@ const QUrl &QQmlVMEVariant::asQUrl() return *(QUrl *)(dataPtr()); } -const QTime &QQmlVMEVariant::asQTime() -{ - if (type != QMetaType::QTime) - setValue(QTime()); - - return *(QTime *)(dataPtr()); -} - const QDate &QQmlVMEVariant::asQDate() { if (type != QMetaType::QDate) @@ -330,14 +314,6 @@ const QPointF &QQmlVMEVariant::asQPointF() return *(QPointF *)(dataPtr()); } -const QJSValue &QQmlVMEVariant::asQJSValue() -{ - if (type != qMetaTypeId<QJSValue>()) - setValue(QJSValue()); - - return *(QJSValue *)(dataPtr()); -} - void QQmlVMEVariant::setValue(QObject *v, QQmlVMEMetaObject *target, int index) { if (type != QMetaType::QObjectStar) { @@ -474,22 +450,6 @@ void QQmlVMEVariant::setValue(const QSizeF &v) } } -void QQmlVMEVariant::setValue(const QJSValue &v) -{ - if (type != qMetaTypeId<QJSValue>()) { - cleanup(); - type = qMetaTypeId<QJSValue>(); - new (dataPtr()) QJSValue(v); - } else { - *(QJSValue *)(dataPtr()) = v; - } -} - -void QQmlVMEVariant::setDataType(int t) -{ - type = t; -} - void QQmlVMEVariant::ensureValueType(int t) { if (type != t) { @@ -500,8 +460,8 @@ void QQmlVMEVariant::ensureValueType(int t) } QQmlVMEMetaObjectEndpoint::QQmlVMEMetaObjectEndpoint() + : QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlVMEMetaObjectEndpoint) { - setCallback(QQmlNotifierEndpoint::QQmlVMEMetaObjectEndpoint); } void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *e, void **) @@ -874,10 +834,8 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) int flags = *reinterpret_cast<int*>(a[3]); if (flags & QQmlPropertyPrivate::RemoveBindingOnAliasWrite) { QQmlData *targetData = QQmlData::get(target); - if (targetData && targetData->hasBindingBit(d->propertyIndex())) { - QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(target, d->propertyIndex(), d->isValueTypeAlias()?d->valueTypeIndex():-1, 0); - if (binding) binding->destroy(); - } + if (targetData && targetData->hasBindingBit(d->propertyIndex())) + QQmlPropertyPrivate::removeBinding(target, d->propertyIdx); } } @@ -1183,7 +1141,7 @@ void QQmlVMEMetaObject::setVmeMethod(int index, const QV4::Value &function) v8methods = new QV4::PersistentValue[metaData->methodCount]; int methodIndex = index - methodOffset() - plainSignals; - v8methods[methodIndex].set(function.asObject()->engine(), function); + v8methods[methodIndex].set(function.as<QV4::Object>()->engine(), function); } QV4::ReturnedValue QQmlVMEMetaObject::vmeProperty(int index) @@ -1220,8 +1178,9 @@ bool QQmlVMEMetaObject::ensureVarPropertiesAllocated() void QQmlVMEMetaObject::ensureQObjectWrapper() { - QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine); - QV4::ExecutionEngine *v4 = (ep == 0) ? 0 : ep->v4engine(); + Q_ASSERT(ctxt && ctxt->engine); + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(ctxt->engine); + QV4::ExecutionEngine *v4 = ep->v4engine(); QV4::QObjectWrapper::wrap(v4, object); } @@ -1251,7 +1210,7 @@ void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e) void QQmlVMEMetaObject::allocateVarPropertiesArray() { QQmlEngine *qml = qmlEngine(object); - assert(qml); + Q_ASSERT(qml); QV4::ExecutionEngine *v4 = QV8Engine::getV4(qml->handle()); QV4::Scope scope(v4); varProperties.set(scope.engine, v4->newArrayObject(metaData->varPropertyCount)); diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index f3048d426a..a320163f23 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -63,7 +63,7 @@ #include <private/qv8engine_p.h> #include <private/qflagpointer_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmlwatcher.cpp b/src/qml/qml/qqmlwatcher.cpp deleted file mode 100644 index 9726b6f3b9..0000000000 --- a/src/qml/qml/qqmlwatcher.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlwatcher_p.h" - -#include "qqmlexpression.h" -#include "qqmlcontext.h" -#include "qqml.h" - -#include <private/qqmldebugservice_p.h> -#include "qqmlproperty_p.h" -#include "qqmlvaluetype_p.h" - -#include <QtCore/qmetaobject.h> -#include <QtCore/qdebug.h> - -QT_BEGIN_NAMESPACE - - -class QQmlWatchProxy : public QObject -{ - Q_OBJECT -public: - QQmlWatchProxy(int id, - QObject *object, - int debugId, - const QMetaProperty &prop, - QQmlWatcher *parent = 0); - - QQmlWatchProxy(int id, - QQmlExpression *exp, - int debugId, - QQmlWatcher *parent = 0); - -public slots: - void notifyValueChanged(); - -private: - friend class QQmlWatcher; - int m_id; - QQmlWatcher *m_watch; - QObject *m_object; - int m_debugId; - QMetaProperty m_property; - - QQmlExpression *m_expr; -}; - -QQmlWatchProxy::QQmlWatchProxy(int id, - QQmlExpression *exp, - int debugId, - QQmlWatcher *parent) -: QObject(parent), m_id(id), m_watch(parent), m_object(0), m_debugId(debugId), m_expr(exp) -{ - QObject::connect(m_expr, SIGNAL(valueChanged()), this, SLOT(notifyValueChanged())); -} - -QQmlWatchProxy::QQmlWatchProxy(int id, - QObject *object, - int debugId, - const QMetaProperty &prop, - QQmlWatcher *parent) -: QObject(parent), m_id(id), m_watch(parent), m_object(object), m_debugId(debugId), m_property(prop), m_expr(0) -{ - static int refreshIdx = -1; - if(refreshIdx == -1) - refreshIdx = QQmlWatchProxy::staticMetaObject.indexOfMethod("notifyValueChanged()"); - - if (prop.hasNotifySignal()) - QQmlPropertyPrivate::connect(m_object, prop.notifySignalIndex(), this, refreshIdx); -} - -void QQmlWatchProxy::notifyValueChanged() -{ - QVariant v; - if (m_expr) - v = m_expr->evaluate(); - else if (QQmlValueTypeFactory::isValueType(m_property.userType())) - v = m_property.read(m_object); - - emit m_watch->propertyChanged(m_id, m_debugId, m_property, v); -} - - -QQmlWatcher::QQmlWatcher(QObject *parent) - : QObject(parent) -{ -} - -bool QQmlWatcher::addWatch(int id, quint32 debugId) -{ - QObject *object = QQmlDebugService::objectForId(debugId); - if (object) { - int propCount = object->metaObject()->propertyCount(); - for (int ii=0; ii<propCount; ii++) - addPropertyWatch(id, object, debugId, object->metaObject()->property(ii)); - return true; - } - return false; -} - -bool QQmlWatcher::addWatch(int id, quint32 debugId, const QByteArray &property) -{ - QObject *object = QQmlDebugService::objectForId(debugId); - if (object) { - int index = object->metaObject()->indexOfProperty(property.constData()); - if (index >= 0) { - addPropertyWatch(id, object, debugId, object->metaObject()->property(index)); - return true; - } - } - return false; -} - -bool QQmlWatcher::addWatch(int id, quint32 objectId, const QString &expr) -{ - QObject *object = QQmlDebugService::objectForId(objectId); - QQmlContext *context = qmlContext(object); - if (context) { - QQmlExpression *exprObj = new QQmlExpression(context, object, expr); - exprObj->setNotifyOnValueChanged(true); - QQmlWatchProxy *proxy = new QQmlWatchProxy(id, exprObj, objectId, this); - exprObj->setParent(proxy); - m_proxies[id].append(proxy); - proxy->notifyValueChanged(); - return true; - } - return false; -} - -bool QQmlWatcher::removeWatch(int id) -{ - if (!m_proxies.contains(id)) - return false; - - QList<QPointer<QQmlWatchProxy> > proxies = m_proxies.take(id); - qDeleteAll(proxies); - return true; -} - -void QQmlWatcher::addPropertyWatch(int id, QObject *object, quint32 debugId, const QMetaProperty &property) -{ - QQmlWatchProxy *proxy = new QQmlWatchProxy(id, object, debugId, property, this); - m_proxies[id].append(proxy); - - proxy->notifyValueChanged(); -} - -QT_END_NAMESPACE - -#include <qqmlwatcher.moc> diff --git a/src/qml/qml/qqmlwatcher_p.h b/src/qml/qml/qqmlwatcher_p.h deleted file mode 100644 index a7bb3c3418..0000000000 --- a/src/qml/qml/qqmlwatcher_p.h +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLWATCHER_P_H -#define QQMLWATCHER_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. -// - -#include <QtCore/qobject.h> -#include <QtCore/qlist.h> -#include <QtCore/qpair.h> -#include <QtCore/qhash.h> -#include <QtCore/qset.h> -#include <QtCore/qpointer.h> - -QT_BEGIN_NAMESPACE - -class QQmlWatchProxy; -class QQmlExpression; -class QQmlContext; -class QMetaProperty; - -class QQmlWatcher : public QObject -{ - Q_OBJECT -public: - QQmlWatcher(QObject * = 0); - - bool addWatch(int id, quint32 objectId); - bool addWatch(int id, quint32 objectId, const QByteArray &property); - bool addWatch(int id, quint32 objectId, const QString &expr); - - bool removeWatch(int id); - -Q_SIGNALS: - void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value); - -private: - friend class QQmlWatchProxy; - void addPropertyWatch(int id, QObject *object, quint32 objectId, const QMetaProperty &property); - - QHash<int, QList<QPointer<QQmlWatchProxy> > > m_proxies; -}; - -QT_END_NAMESPACE - -#endif // QQMLWATCHER_P_H diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 2a3ede6a22..0edb672517 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -60,6 +60,7 @@ #include <private/qv4objectproto_p.h> #include <private/qv4scopedvalue_p.h> #include <private/qv4arraybuffer_p.h> +#include <private/qv4jsonobject_p.h> using namespace QV4; @@ -99,7 +100,7 @@ static ReturnedValue constructMeObject(const Value &thisObj, ExecutionEngine *v4 Scope scope(v4); ScopedObject meObj(scope, v4->newObject()); meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ThisObject"))), thisObj); - ScopedValue v(scope, QmlContextWrapper::qmlScope(v4, v4->v8Engine->callingContext(), 0)); + ScopedValue v(scope, QmlContextWrapper::qmlScope(v4, v4->callingQmlContext(), 0)); meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ActivationObject"))), v); return meObj.asReturnedValue(); } @@ -222,8 +223,8 @@ public: static ReturnedValue create(ExecutionEngine *, NodeImpl *, const QList<NodeImpl *> &); // JS API - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); }; Heap::NamedNodeMap::NamedNodeMap(ExecutionEngine *engine, NodeImpl *data, const QList<NodeImpl *> &list) @@ -244,8 +245,8 @@ public: V4_NEEDS_DESTROY // JS API - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); // C++ API static ReturnedValue create(ExecutionEngine *, NodeImpl *); @@ -273,6 +274,7 @@ public: static ReturnedValue method_get_nodeName(CallContext *ctx); static ReturnedValue method_get_nodeValue(CallContext *ctx); static ReturnedValue method_get_nodeType(CallContext *ctx); + static ReturnedValue method_get_namespaceUri(CallContext *ctx); static ReturnedValue method_get_parentNode(CallContext *ctx); static ReturnedValue method_get_childNodes(CallContext *ctx); @@ -302,6 +304,7 @@ Heap::NodePrototype::NodePrototype(ExecutionEngine *engine) o->defineAccessorProperty(QStringLiteral("nodeName"), QV4::NodePrototype::method_get_nodeName, 0); o->defineAccessorProperty(QStringLiteral("nodeValue"), QV4::NodePrototype::method_get_nodeValue, 0); o->defineAccessorProperty(QStringLiteral("nodeType"), QV4::NodePrototype::method_get_nodeType, 0); + o->defineAccessorProperty(QStringLiteral("namespaceUri"), QV4::NodePrototype::method_get_namespaceUri, 0); o->defineAccessorProperty(QStringLiteral("parentNode"), QV4::NodePrototype::method_get_parentNode, 0); o->defineAccessorProperty(QStringLiteral("childNodes"), QV4::NodePrototype::method_get_childNodes, 0); @@ -470,6 +473,16 @@ ReturnedValue NodePrototype::method_get_nodeType(CallContext *ctx) return Encode(r->d()->d->type); } +ReturnedValue NodePrototype::method_get_namespaceUri(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + if (!r) + return ctx->engine()->throwTypeError(); + + return Encode(ctx->d()->engine->newString(r->d()->d->namespaceUri)); +} + ReturnedValue NodePrototype::method_get_parentNode(CallContext *ctx) { Scope scope(ctx); @@ -871,10 +884,10 @@ bool Node::isNull() const return d()->d == 0; } -ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue NamedNodeMap::getIndexed(const Managed *m, uint index, bool *hasProperty) { Q_ASSERT(m->as<NamedNodeMap>()); - NamedNodeMap *r = static_cast<NamedNodeMap *>(m); + const NamedNodeMap *r = static_cast<const NamedNodeMap *>(m); QV4::ExecutionEngine *v4 = r->engine(); if ((int)index < r->d()->list.count()) { @@ -887,14 +900,14 @@ ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty return Encode::undefined(); } -ReturnedValue NamedNodeMap::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue NamedNodeMap::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<NamedNodeMap>()); - NamedNodeMap *r = static_cast<NamedNodeMap *>(m); + const NamedNodeMap *r = static_cast<const NamedNodeMap *>(m); QV4::ExecutionEngine *v4 = r->engine(); name->makeIdentifier(v4); - if (name->equals(v4->id_length)) + if (name->equals(v4->id_length())) return Primitive::fromInt32(r->d()->list.count()).asReturnedValue(); QString str = name->toQString(); @@ -916,10 +929,10 @@ ReturnedValue NamedNodeMap::create(ExecutionEngine *v4, NodeImpl *data, const QL return (v4->memoryManager->alloc<NamedNodeMap>(v4, data, list))->asReturnedValue(); } -ReturnedValue NodeList::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue NodeList::getIndexed(const Managed *m, uint index, bool *hasProperty) { Q_ASSERT(m->as<NodeList>()); - NodeList *r = static_cast<NodeList *>(m); + const NodeList *r = static_cast<const NodeList *>(m); QV4::ExecutionEngine *v4 = r->engine(); if ((int)index < r->d()->d->children.count()) { @@ -932,15 +945,15 @@ ReturnedValue NodeList::getIndexed(Managed *m, uint index, bool *hasProperty) return Encode::undefined(); } -ReturnedValue NodeList::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue NodeList::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<NodeList>()); - NodeList *r = static_cast<NodeList *>(m); + const NodeList *r = static_cast<const NodeList *>(m); QV4::ExecutionEngine *v4 = r->engine(); name->makeIdentifier(v4); - if (name->equals(v4->id_length)) + if (name->equals(v4->id_length())) return Primitive::fromInt32(r->d()->d->children.count()).asReturnedValue(); return Object::get(m, name, hasProperty); } @@ -1019,13 +1032,15 @@ public: QString header(const QString &name); QString headers(); - QString responseBody(); const QByteArray & rawResponseBody() const; bool receivedXml() const; const QString & responseType() const; void setResponseType(const QString &); + + QV4::ReturnedValue jsonResponseBody(QV4::ExecutionEngine*); + QV4::ReturnedValue xmlResponseBody(QV4::ExecutionEngine*); private slots: void readyRead(); void error(QNetworkReply::NetworkError); @@ -1076,6 +1091,7 @@ private: QNetworkAccessManager *networkAccessManager() { return m_nam; } QString m_responseType; + QV4::PersistentValue m_parsedDocument; }; QQmlXMLHttpRequest::QQmlXMLHttpRequest(ExecutionEngine *engine, QNetworkAccessManager *manager) @@ -1083,6 +1099,7 @@ QQmlXMLHttpRequest::QQmlXMLHttpRequest(ExecutionEngine *engine, QNetworkAccessMa , m_state(Unsent), m_errorFlag(false), m_sendFlag(false) , m_redirectCount(0), m_gotXml(false), m_textCodec(0), m_network(0), m_nam(manager) , m_responseType() + , m_parsedDocument() { } @@ -1233,11 +1250,12 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url) m_network = networkAccessManager()->put(request, m_data); } else if (m_method == QLatin1String("DELETE")) { m_network = networkAccessManager()->deleteResource(request); - } else if (m_method == QLatin1String("OPTIONS")) { + } else if ((m_method == QLatin1String("OPTIONS")) || + m_method == QLatin1String("PROPFIND")) { QBuffer *buffer = new QBuffer; buffer->setData(m_data); buffer->open(QIODevice::ReadOnly); - m_network = networkAccessManager()->sendCustomRequest(request, QByteArrayLiteral("OPTIONS"), buffer); + m_network = networkAccessManager()->sendCustomRequest(request, QByteArray(m_method.toUtf8().constData()), buffer); buffer->setParent(m_network); } @@ -1478,6 +1496,32 @@ void QQmlXMLHttpRequest::setResponseType(const QString &responseType) m_responseType = responseType; } +QV4::ReturnedValue QQmlXMLHttpRequest::jsonResponseBody(QV4::ExecutionEngine* engine) +{ + if (m_parsedDocument.isEmpty()) { + Scope scope(engine); + + QJsonParseError error; + const QString& jtext = responseBody(); + JsonParser parser(scope.engine, jtext.constData(), jtext.length()); + ScopedValue jsonObject(scope, parser.parse(&error)); + if (error.error != QJsonParseError::NoError) + return engine->throwSyntaxError(QStringLiteral("JSON.parse: Parse error")); + + m_parsedDocument.set(scope.engine, jsonObject); + } + + return m_parsedDocument.value(); +} + +QV4::ReturnedValue QQmlXMLHttpRequest::xmlResponseBody(QV4::ExecutionEngine* engine) +{ + if (m_parsedDocument.isEmpty()) { + m_parsedDocument.set(engine, Document::load(engine, rawResponseBody())); + } + + return m_parsedDocument.value(); +} #ifndef QT_NO_TEXTCODEC QTextCodec* QQmlXMLHttpRequest::findTextCodec() const @@ -1599,7 +1643,7 @@ struct QQmlXMLHttpRequestWrapper : Object { struct QQmlXMLHttpRequestCtor : FunctionObject { QQmlXMLHttpRequestCtor(ExecutionEngine *engine); - Object *proto; + Pointer<Object> proto; }; } @@ -1625,9 +1669,9 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject c->proto->mark(e); FunctionObject::markObjects(that, e); } - static ReturnedValue construct(Managed *that, QV4::CallData *) + static ReturnedValue construct(const Managed *that, QV4::CallData *) { - Scope scope(static_cast<QQmlXMLHttpRequestCtor *>(that)->engine()); + Scope scope(static_cast<const QQmlXMLHttpRequestCtor *>(that)->engine()); Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>()); if (!ctor) return scope.engine->throwTypeError(); @@ -1639,7 +1683,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject return w.asReturnedValue(); } - static ReturnedValue call(Managed *, QV4::CallData *) { + static ReturnedValue call(const Managed *, QV4::CallData *) { return Primitive::undefinedValue().asReturnedValue(); } @@ -1679,7 +1723,7 @@ Heap::QQmlXMLHttpRequestCtor::QQmlXMLHttpRequestCtor(ExecutionEngine *engine) ctor->defineReadonlyProperty(QStringLiteral("DONE"), Primitive::fromInt32(4)); if (!ctor->d()->proto) ctor->setupProto(); - ScopedString s(scope, engine->id_prototype); + ScopedString s(scope, engine->id_prototype()); ctor->defineDefaultProperty(s, ScopedObject(scope, ctor->d()->proto)); } @@ -1739,14 +1783,15 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx) method != QLatin1String("HEAD") && method != QLatin1String("POST") && method != QLatin1String("DELETE") && - method != QLatin1String("OPTIONS")) + method != QLatin1String("OPTIONS") && + method != QLatin1String("PROPFIND")) V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type"); // Argument 1 - URL QUrl url = QUrl(ctx->args()[1].toQStringNoThrow()); if (url.isRelative()) - url = scope.engine->v8Engine->callingContext()->resolvedUrl(url); + url = scope.engine->callingQmlContext()->resolvedUrl(url); bool async = true; // Argument 2 - async (optional) @@ -1965,7 +2010,9 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseXML(CallContext *ctx) r->readyState() != QQmlXMLHttpRequest::Done)) { return Encode::null(); } else { - return Document::load(scope.engine, r->rawResponseBody()); + if (r->responseType().isEmpty()) + r->setResponseType(QLatin1String("document")); + return r->xmlResponseBody(scope.engine); } } @@ -1986,6 +2033,10 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_response(CallContext *ctx) return QV4::Encode(scope.engine->newString(r->responseBody())); } else if (responseType.compare(QLatin1String("arraybuffer"), Qt::CaseInsensitive) == 0) { return QV4::Encode(scope.engine->newArrayBuffer(r->rawResponseBody())); + } else if (responseType.compare(QLatin1String("json"), Qt::CaseInsensitive) == 0) { + return r->jsonResponseBody(scope.engine); + } else if (responseType.compare(QLatin1String("document"), Qt::CaseInsensitive) == 0) { + return r->xmlResponseBody(scope.engine); } else { return QV4::Encode(scope.engine->newString(QString())); } @@ -2033,7 +2084,7 @@ void *qt_add_qmlxmlhttprequest(ExecutionEngine *v4) Scoped<QQmlXMLHttpRequestCtor> ctor(scope, v4->memoryManager->alloc<QQmlXMLHttpRequestCtor>(v4)); ScopedString s(scope, v4->newString(QStringLiteral("XMLHttpRequest"))); - v4->globalObject()->defineReadonlyProperty(s, ctor); + v4->globalObject->defineReadonlyProperty(s, ctor); QQmlXMLHttpRequestData *data = new QQmlXMLHttpRequestData; return data; diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index f53b9a0c7d..ce86fd3923 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -41,7 +41,8 @@ #include <private/qv8engine_p.h> #include <QFileInfo> -#include <private/qqmlprofilerservice_p.h> +#include <private/qqmldebugconnector_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> #include <private/qqmlglobal_p.h> #include <private/qqmlplatform_p.h> @@ -51,6 +52,7 @@ #include <private/qv4include_p.h> #include <private/qv4context_p.h> #include <private/qv4stringobject_p.h> +#include <private/qv4dateobject_p.h> #include <private/qv4mm_p.h> #include <private/qv4jsonobject_p.h> #include <private/qv4objectproto_p.h> @@ -669,7 +671,7 @@ ReturnedValue QtObject::method_formatTime(QV4::CallContext *ctx) QVariant argVariant = ctx->engine()->toVariant(ctx->args()[0], -1); QTime time; - if (ctx->args()[0].asDateObject() || (argVariant.type() == QVariant::String)) + if (ctx->args()[0].as<DateObject>() || (argVariant.type() == QVariant::String)) time = argVariant.toDateTime().time(); else // if (argVariant.type() == QVariant::Time), or invalid. time = argVariant.toTime(); @@ -839,21 +841,21 @@ ReturnedValue QtObject::method_openUrlExternally(QV4::CallContext *ctx) */ ReturnedValue QtObject::method_resolvedUrl(QV4::CallContext *ctx) { - QV8Engine *v8engine = ctx->d()->engine->v8Engine; + ExecutionEngine *v4 = ctx->engine(); - QUrl url = ctx->engine()->toVariant(ctx->args()[0], -1).toUrl(); - QQmlEngine *e = v8engine->engine(); + QUrl url = v4->toVariant(ctx->args()[0], -1).toUrl(); + QQmlEngine *e = v4->qmlEngine(); QQmlEnginePrivate *p = 0; if (e) p = QQmlEnginePrivate::get(e); if (p) { - QQmlContextData *ctxt = v8engine->callingContext(); + QQmlContextData *ctxt = v4->callingQmlContext(); if (ctxt) - return ctx->d()->engine->newString(ctxt->resolvedUrl(url).toString())->asReturnedValue(); + return v4->newString(ctxt->resolvedUrl(url).toString())->asReturnedValue(); else - return ctx->d()->engine->newString(url.toString())->asReturnedValue(); + return v4->newString(url.toString())->asReturnedValue(); } - return ctx->d()->engine->newString(e->baseUrl().resolved(url).toString())->asReturnedValue(); + return v4->newString(e->baseUrl().resolved(url).toString())->asReturnedValue(); } /*! @@ -983,7 +985,7 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) QV8Engine *v8engine = ctx->d()->engine->v8Engine; QQmlEngine *engine = v8engine->engine(); - QQmlContextData *context = v8engine->callingContext(); + QQmlContextData *context = scope.engine->callingQmlContext(); Q_ASSERT(context); QQmlContext *effectiveContext = 0; if (context->isPragmaLibraryContext) @@ -1090,7 +1092,7 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx) QV8Engine *v8engine = ctx->d()->engine->v8Engine; QQmlEngine *engine = v8engine->engine(); - QQmlContextData *context = v8engine->callingContext(); + QQmlContextData *context = scope.engine->callingQmlContext(); Q_ASSERT(context); QQmlContextData *effectiveContext = context; if (context->isPragmaLibraryContext) @@ -1178,7 +1180,7 @@ ReturnedValue QtObject::method_locale(CallContext *ctx) return QQmlLocale::locale(ctx->engine(), code); } -Heap::QQmlBindingFunction::QQmlBindingFunction(QV4::FunctionObject *originalFunction) +Heap::QQmlBindingFunction::QQmlBindingFunction(const QV4::FunctionObject *originalFunction) : QV4::Heap::FunctionObject(originalFunction->scope(), originalFunction->name()) , originalFunction(originalFunction->d()) { @@ -1191,10 +1193,10 @@ void QQmlBindingFunction::initBindingLocation() d()->bindingLocation.line = frame.line; } -ReturnedValue QQmlBindingFunction::call(Managed *that, CallData *callData) +ReturnedValue QQmlBindingFunction::call(const Managed *that, CallData *callData) { - Scope scope(static_cast<QQmlBindingFunction*>(that)->engine()); - ScopedFunctionObject function(scope, static_cast<QQmlBindingFunction*>(that)->d()->originalFunction); + Scope scope(static_cast<const QQmlBindingFunction*>(that)->engine()); + ScopedFunctionObject function(scope, static_cast<const QQmlBindingFunction*>(that)->d()->originalFunction); return function->call(callData); } @@ -1256,7 +1258,7 @@ ReturnedValue QtObject::method_binding(CallContext *ctx) { if (ctx->argc() != 1) V4THROW_ERROR("binding() requires 1 argument"); - QV4::FunctionObject *f = ctx->args()[0].asFunctionObject(); + const QV4::FunctionObject *f = ctx->args()[0].as<FunctionObject>(); if (!f) V4THROW_TYPE("binding(): argument (binding expression) must be a function"); @@ -1267,7 +1269,7 @@ ReturnedValue QtObject::method_binding(CallContext *ctx) ReturnedValue QtObject::method_get_platform(CallContext *ctx) { // ### inefficient. Should be just a value based getter - Object *o = ctx->thisObject().asObject(); + Object *o = ctx->thisObject().as<Object>(); if (!o) return ctx->engine()->throwTypeError(); QtObject *qt = o->as<QtObject>(); @@ -1284,7 +1286,7 @@ ReturnedValue QtObject::method_get_platform(CallContext *ctx) ReturnedValue QtObject::method_get_application(CallContext *ctx) { // ### inefficient. Should be just a value based getter - Object *o = ctx->thisObject().asObject(); + Object *o = ctx->thisObject().as<Object>(); if (!o) return ctx->engine()->throwTypeError(); QtObject *qt = o->as<QtObject>(); @@ -1353,12 +1355,12 @@ static QString jsStack(QV4::ExecutionEngine *engine) { QString stackFrame; if (frame.column >= 0) - stackFrame = QString::fromLatin1("%1 (%2:%3:%4)").arg(frame.function, + stackFrame = QStringLiteral("%1 (%2:%3:%4)").arg(frame.function, frame.source, QString::number(frame.line), QString::number(frame.column)); else - stackFrame = QString::fromLatin1("%1 (%2:%3)").arg(frame.function, + stackFrame = QStringLiteral("%1 (%2:%3)").arg(frame.function, frame.source, QString::number(frame.line)); @@ -1379,7 +1381,7 @@ static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *c if (i != 0) result.append(QLatin1Char(' ')); - if (ctx->args()[i].asArrayObject()) + if (ctx->args()[i].as<ArrayObject>()) result.append(QStringLiteral("[") + ctx->args()[i].toQStringNoThrow() + QStringLiteral("]")); else result.append(ctx->args()[i].toQStringNoThrow()); @@ -1446,10 +1448,11 @@ QV4::ReturnedValue ConsoleObject::method_profile(CallContext *ctx) const QByteArray baSource = frame.source.toUtf8(); const QByteArray baFunction = frame.function.toUtf8(); QMessageLogger logger(baSource.constData(), frame.line, baFunction.constData()); - if (!QQmlDebugService::isDebuggingEnabled()) { + QQmlProfilerService *service = QQmlDebugConnector::service<QQmlProfilerService>(); + if (!service) { logger.warning("Cannot start profiling because debug service is disabled. Start with -qmljsdebugger=port:XXXXX."); } else { - QQmlProfilerService::instance()->startProfiling(v4->qmlEngine()); + service->startProfiling(v4->qmlEngine()); logger.debug("Profiling started."); } @@ -1465,10 +1468,11 @@ QV4::ReturnedValue ConsoleObject::method_profileEnd(CallContext *ctx) const QByteArray baFunction = frame.function.toUtf8(); QMessageLogger logger(baSource.constData(), frame.line, baFunction.constData()); - if (!QQmlDebugService::isDebuggingEnabled()) { + QQmlProfilerService *service = QQmlDebugConnector::service<QQmlProfilerService>(); + if (!service) { logger.warning("Ignoring console.profileEnd(): the debug service is disabled."); } else { - QQmlProfilerService::instance()->stopProfiling(v4->qmlEngine()); + service->stopProfiling(v4->qmlEngine()); logger.debug("Profiling ended."); } @@ -1612,7 +1616,7 @@ void QV4::GlobalExtensions::init(QQmlEngine *qmlEngine, Object *globalObject) globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt); // string prototype extension - v4->stringPrototype.asObject()->defineDefaultProperty(QStringLiteral("arg"), method_string_arg); + v4->stringPrototype()->defineDefaultProperty(QStringLiteral("arg"), method_string_arg); } @@ -1726,9 +1730,8 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx) V4THROW_ERROR("qsTr(): third argument (n) must be a number"); Scope scope(ctx); - QV8Engine *v8engine = ctx->d()->engine->v8Engine; QString context; - if (QQmlContextData *ctxt = v8engine->callingContext()) { + if (QQmlContextData *ctxt = scope.engine->callingQmlContext()) { QString path = ctxt->urlString(); int lastSlash = path.lastIndexOf(QLatin1Char('/')); int lastDot = path.lastIndexOf(QLatin1Char('.')); diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index b78375118b..bdd53fe601 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -68,8 +68,8 @@ struct ConsoleObject : Object { }; struct QQmlBindingFunction : FunctionObject { - QQmlBindingFunction(QV4::FunctionObject *originalFunction); - FunctionObject *originalFunction; + QQmlBindingFunction(const QV4::FunctionObject *originalFunction); + Pointer<FunctionObject> originalFunction; // Set when the binding is created later QQmlSourceLocation bindingLocation; }; @@ -166,7 +166,7 @@ struct QQmlBindingFunction : public QV4::FunctionObject void initBindingLocation(); // from caller stack trace - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/qml/v8/qv4domerrors.cpp b/src/qml/qml/v8/qv4domerrors.cpp index c318e2e550..1baaa113aa 100644 --- a/src/qml/qml/v8/qv4domerrors.cpp +++ b/src/qml/qml/v8/qv4domerrors.cpp @@ -59,7 +59,7 @@ void qt_add_domexceptions(ExecutionEngine *e) domexception->defineReadonlyProperty(QStringLiteral("INVALID_ACCESS_ERR"), Primitive::fromInt32(DOMEXCEPTION_INVALID_ACCESS_ERR)); domexception->defineReadonlyProperty(QStringLiteral("VALIDATION_ERR"), Primitive::fromInt32(DOMEXCEPTION_VALIDATION_ERR)); domexception->defineReadonlyProperty(QStringLiteral("TYPE_MISMATCH_ERR"), Primitive::fromInt32(DOMEXCEPTION_TYPE_MISMATCH_ERR)); - e->globalObject()->defineDefaultProperty(QStringLiteral("DOMException"), domexception); + e->globalObject->defineDefaultProperty(QStringLiteral("DOMException"), domexception); } QT_END_NAMESPACE diff --git a/src/qml/qml/v8/qv4sqlerrors.cpp b/src/qml/qml/v8/qv4sqlerrors.cpp index b7a5b71540..c61e57560d 100644 --- a/src/qml/qml/v8/qv4sqlerrors.cpp +++ b/src/qml/qml/v8/qv4sqlerrors.cpp @@ -51,7 +51,7 @@ void qt_add_sqlexceptions(QV4::ExecutionEngine *engine) sqlexception->defineReadonlyProperty(QStringLiteral("SYNTAX_ERR"), Primitive::fromInt32(SQLEXCEPTION_SYNTAX_ERR)); sqlexception->defineReadonlyProperty(QStringLiteral("CONSTRAINT_ERR"), Primitive::fromInt32(SQLEXCEPTION_CONSTRAINT_ERR)); sqlexception->defineReadonlyProperty(QStringLiteral("TIMEOUT_ERR"), Primitive::fromInt32(SQLEXCEPTION_TIMEOUT_ERR)); - engine->globalObject()->defineDefaultProperty(QStringLiteral("SQLException"), sqlexception); + engine->globalObject->defineDefaultProperty(QStringLiteral("SQLException"), sqlexception); } QT_END_NAMESPACE diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index a7c63c9df1..6cb316ce9f 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -61,7 +61,7 @@ #include <QtCore/qdatastream.h> #include <private/qsimd_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4dateobject_p.h> #include <private/qv4objectiterator_p.h> #include <private/qv4mm_p.h> @@ -171,15 +171,10 @@ const QSet<QString> &QV8Engine::illegalNames() const return m_illegalNames; } -QQmlContextData *QV8Engine::callingContext() -{ - return QV4::QmlContextWrapper::callingContext(m_v4Engine); -} - void QV8Engine::initializeGlobal() { QV4::Scope scope(m_v4Engine); - QV4::GlobalExtensions::init(m_engine, m_v4Engine->globalObject()); + QV4::GlobalExtensions::init(m_engine, m_v4Engine->globalObject); QQmlLocale::registerStringLocaleCompare(m_v4Engine); QQmlDateExtension::registerExtension(m_v4Engine); @@ -191,9 +186,9 @@ void QV8Engine::initializeGlobal() qt_add_sqlexceptions(m_v4Engine); { - for (uint i = 0; i < m_v4Engine->globalObject()->internalClass()->size; ++i) { - if (m_v4Engine->globalObject()->internalClass()->nameMap.at(i)) - m_illegalNames.insert(m_v4Engine->globalObject()->internalClass()->nameMap.at(i)->string); + for (uint i = 0; i < m_v4Engine->globalObject->internalClass()->size; ++i) { + if (m_v4Engine->globalObject->internalClass()->nameMap.at(i)) + m_illegalNames.insert(m_v4Engine->globalObject->internalClass()->nameMap.at(i)->string); } } @@ -229,7 +224,7 @@ void QV8Engine::freezeObject(const QV4::Value &value) QV4::ScopedFunctionObject f(scope, m_freezeObject.value()); QV4::ScopedCallData callData(scope, 1); callData->args[0] = value; - callData->thisObject = m_v4Engine->globalObject(); + callData->thisObject = m_v4Engine->globalObject; f->call(callData); } @@ -266,9 +261,7 @@ void QV8Engine::setExtensionData(int index, Deletable *data) void QV8Engine::initQmlGlobalObject() { initializeGlobal(); - QV4::Scope scope(m_v4Engine); - QV4::ScopedValue v(scope, m_v4Engine->globalObject()); - freezeObject(v); + freezeObject(*m_v4Engine->globalObject); } void QV8Engine::setEngine(QQmlEngine *engine) @@ -279,7 +272,7 @@ void QV8Engine::setEngine(QQmlEngine *engine) QV4::ReturnedValue QV8Engine::global() { - return m_v4Engine->globalObject()->asReturnedValue(); + return m_v4Engine->globalObject->asReturnedValue(); } void QV8Engine::startTimer(const QString &timerName) diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h index fb538772d1..5d12244dcb 100644 --- a/src/qml/qml/v8/qv8engine_p.h +++ b/src/qml/qml/v8/qv8engine_p.h @@ -60,7 +60,7 @@ #include <private/qqmlpropertycache_p.h> #include <private/qv4qobjectwrapper_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> #include <private/qv4identifier_p.h> @@ -101,19 +101,19 @@ namespace QV4 { return rv; \ } \ -// Used to allow a QObject method take and return raw V8 handles without having to expose -// v8 in the public API. +// Used to allow a QObject method take and return raw V4 handles without having to expose +// 48 in the public API. // Use like this: // class MyClass : public QObject { // Q_OBJECT // ... -// Q_INVOKABLE void myMethod(QQmlV8Function*); +// Q_INVOKABLE void myMethod(QQmlV4Function*); // }; // The QQmlV8Function - and consequently the arguments and return value - only remains // valid during the call. If the return value isn't set within myMethod(), the will return // undefined. class QV8Engine; -// ### GC + class QQmlV4Function { public: @@ -133,7 +133,7 @@ private: const QV4::Value &global, QQmlContextData *c, QV4::ExecutionEngine *e) : callData(callData), retVal(retVal), ctx(c), e(e) { - callData->thisObject.val = global.asReturnedValue(); + callData->thisObject = QV4::Value::fromReturnedValue(global.asReturnedValue()); } QV4::CallData *callData; @@ -163,8 +163,6 @@ class QQmlContextData; class Q_QML_PRIVATE_EXPORT QV8Engine { friend class QJSEngine; - // ### GC - typedef QSet<QV4::Heap::Object *> V8ObjectSet; public: static QV8Engine* get(QJSEngine* q) { Q_ASSERT(q); return q->handle(); } // static QJSEngine* get(QV8Engine* d) { Q_ASSERT(d); return d->q; } @@ -192,8 +190,6 @@ public: Deletable *listModelData() { return m_listModelData; } void setListModelData(Deletable *d) { if (m_listModelData) delete m_listModelData; m_listModelData = d; } - QQmlContextData *callingContext(); - void freezeObject(const QV4::Value &value); // Return the network access manager for this engine. By default this returns the network diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp index 7814fa6d56..a154da8323 100644 --- a/src/qml/types/qqmlbind.cpp +++ b/src/qml/types/qqmlbind.cpp @@ -52,8 +52,8 @@ QT_BEGIN_NAMESPACE class QQmlBindPrivate : public QObjectPrivate { public: - QQmlBindPrivate() : componentComplete(true), obj(0), prevBind(0) {} - ~QQmlBindPrivate() { if (prevBind) prevBind->destroy(); } + QQmlBindPrivate() : componentComplete(true), obj(0) {} + ~QQmlBindPrivate() { } QQmlNullableValue<bool> when; bool componentComplete; @@ -61,7 +61,7 @@ public: QString propName; QQmlNullableValue<QVariant> value; QQmlProperty prop; - QQmlAbstractBinding *prevBind; + QQmlAbstractBinding::Ptr prevBind; }; @@ -70,65 +70,56 @@ public: \instantiates QQmlBind \inqmlmodule QtQml \ingroup qtquick-interceptors - \brief Enables the arbitrary creation of property bindings + \brief Enables the arbitrary creation of property bindings. - \section1 Binding to an Inaccessible Property + In QML, property bindings result in a dependency between the properties of + different objects. - Sometimes it is necessary to bind to a property of an object that wasn't - directly instantiated by QML - generally a property of a class exported - to QML by C++. In these cases, regular property binding doesn't work. Binding - allows you to bind any value to any property. + \section1 Binding to an inaccessible property + + Sometimes it is necessary to bind an object's property to + that of another object that isn't directly instantiated by QML, such as a + property of a class exported to QML by C++. You can use the Binding type + to establish this dependency; binding any value to any object's property. + + For example, in a C++ application that maps an "app.enteredText" property + into QML, you can use Binding to update the enteredText property. - For example, imagine a C++ application that maps an "app.enteredText" - property into QML. You could use Binding to update the enteredText property - like this. \code TextEdit { id: myTextField; text: "Please type here..." } Binding { target: app; property: "enteredText"; value: myTextField.text } \endcode - Whenever the text in the TextEdit is updated, the C++ property will be - updated also. - \section1 "Single-branch" conditional binding + When \c{text} changes, the C++ property \c{enteredText} will update + automatically. - In some circumstances you may want to control the value of a property - only when a certain condition is true (and relinquish control in all - other circumstances). This often isn't possible to accomplish with a direct - binding, as you need to supply values for all possible branches. + \section1 Conditional bindings - \code + In some cases you may want to modify the value of a property when a certain + condition is met but leave it unmodified otherwise. Often, it's not possible + to do this with direct bindings, as you have to supply values for all + possible branches. + + For example, the code snippet below results in a warning whenever you + release the mouse. This is because the value of the binding is undefined + when the mouse isn't pressed. + + \qml // produces warning: "Unable to assign [undefined] to double value" value: if (mouse.pressed) mouse.mouseX - \endcode + \endqml - The above example will produce a warning whenever we release the mouse, as the value - of the binding is undefined when the mouse isn't pressed. We can use the Binding - type to rewrite the above code and avoid the warning. + The Binding type can prevent this warning. - \code + \qml Binding on value { when: mouse.pressed value: mouse.mouseX } - \endcode - - The Binding type will also restore any previously set direct bindings on - the property. In that sense, it functions much like a simplified State. - - \qml - // this is equivalent to the above Binding - State { - name: "pressed" - when: mouse.pressed - PropertyChanges { - target: obj - value: mouse.mouseX - } - } \endqml - If the binding target or binding property is changed, the bound value is - immediately pushed onto the new target. + The Binding type restores any previously set direct bindings on the + property. \sa {Qt QML} */ @@ -277,22 +268,17 @@ void QQmlBind::eval() if (!d->when) { //restore any previous binding if (d->prevBind) { - QQmlAbstractBinding *tmp = d->prevBind; + QQmlAbstractBinding::Ptr p = d->prevBind; d->prevBind = 0; - tmp = QQmlPropertyPrivate::setBinding(d->prop, tmp); - if (tmp) //should this ever be true? - tmp->destroy(); + QQmlPropertyPrivate::setBinding(p.data()); } return; } //save any set binding for restoration - QQmlAbstractBinding *tmp; - tmp = QQmlPropertyPrivate::setBinding(d->prop, 0); - if (tmp && d->prevBind) - tmp->destroy(); - else if (!d->prevBind) - d->prevBind = tmp; + if (!d->prevBind) + d->prevBind = QQmlPropertyPrivate::binding(d->prop); + QQmlPropertyPrivate::removeBinding(d->prop); } d->prop.write(d->value.value); diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 0c81855e49..6a93410ecb 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -165,7 +165,7 @@ void QQmlConnections::setTarget(QObject *obj) foreach (QQmlBoundSignal *s, d->boundsignals) { // It is possible that target is being changed due to one of our signal // handlers -> use deleteLater(). - if (s->isEvaluating()) + if (s->isNotifying()) (new QQmlBoundSignalDeleter(s))->deleteLater(); else delete s; diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 201fd4572c..bc70e68904 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -44,7 +44,7 @@ #include <private/qqmlincubator_p.h> #include <private/qqmlcompiler_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> #include <qv4objectiterator_p.h> @@ -86,16 +86,11 @@ struct DelegateModelGroupFunction : QV4::FunctionObject return scope->engine()->memoryManager->alloc<DelegateModelGroupFunction>(scope, flag, code); } - static QV4::ReturnedValue construct(QV4::Managed *m, QV4::CallData *) + static QV4::ReturnedValue call(const QV4::Managed *that, QV4::CallData *callData) { - return static_cast<DelegateModelGroupFunction *>(m)->engine()->throwTypeError(); - } - - static QV4::ReturnedValue call(QV4::Managed *that, QV4::CallData *callData) - { - QV4::ExecutionEngine *v4 = static_cast<DelegateModelGroupFunction *>(that)->engine(); + QV4::ExecutionEngine *v4 = static_cast<const DelegateModelGroupFunction *>(that)->engine(); QV4::Scope scope(v4); - QV4::Scoped<DelegateModelGroupFunction> f(scope, static_cast<DelegateModelGroupFunction *>(that)); + QV4::Scoped<DelegateModelGroupFunction> f(scope, static_cast<const DelegateModelGroupFunction *>(that)); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject); if (!o) return v4->throwTypeError(QStringLiteral("Not a valid VisualData object")); @@ -1062,7 +1057,7 @@ int QQmlDelegateModel::indexOf(QObject *item, QObject *) const return -1; } -void QQmlDelegateModel::setWatchedRoles(QList<QByteArray> roles) +void QQmlDelegateModel::setWatchedRoles(const QList<QByteArray> &roles) { Q_D(QQmlDelegateModel); d->m_adaptorModel.replaceWatchedRoles(d->m_watchedRoles, roles); @@ -1637,7 +1632,7 @@ bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const if (!object.isObject()) return false; - QV4::ExecutionEngine *v4 = object.asObject()->engine(); + QV4::ExecutionEngine *v4 = object.as<QV4::Object>()->engine(); QV4::Scope scope(v4); QV4::ScopedObject o(scope, object); if (!o) @@ -2511,7 +2506,7 @@ bool QQmlDelegateModelGroupPrivate::parseIndex(const QV4::Value &value, int *ind if (!value.isObject()) return false; - QV4::ExecutionEngine *v4 = value.asObject()->engine(); + QV4::ExecutionEngine *v4 = value.as<QV4::Object>()->engine(); QV4::Scope scope(v4); QV4::Scoped<QQmlDelegateModelItemObject> object(scope, value); @@ -2579,9 +2574,9 @@ void QQmlDelegateModelGroup::insert(QQmlV4Function *args) groups |= model->m_cacheMetaType->parseGroups(val); } - if (v->asArrayObject()) { + if (v->as<QV4::ArrayObject>()) { return; - } else if (v->asObject()) { + } else if (v->as<QV4::Object>()) { model->insert(before, v, groups); model->emitChanges(); } @@ -2626,7 +2621,7 @@ void QQmlDelegateModelGroup::create(QQmlV4Function *args) if (i < args->length() && index >= 0 && index <= model->m_compositor.count(group)) { v = (*args)[i]; - if (v->asObject()) { + if (v->as<QV4::Object>()) { int groups = 1 << d->group; if (++i < args->length()) { QV4::ScopedValue val(scope, (*args)[i]); @@ -3190,7 +3185,7 @@ QString QQmlPartsModel::stringValue(int index, const QString &role) return QQmlDelegateModelPrivate::get(m_model)->stringValue(m_compositorGroup, index, role); } -void QQmlPartsModel::setWatchedRoles(QList<QByteArray> roles) +void QQmlPartsModel::setWatchedRoles(const QList<QByteArray> &roles) { QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model); model->m_adaptorModel.replaceWatchedRoles(m_watchedRoles, roles); @@ -3286,12 +3281,12 @@ public: quint32 count() const { return d()->changes.count(); } const QQmlChangeSet::Change &at(int index) const { return d()->changes.at(index); } - static QV4::ReturnedValue getIndexed(QV4::Managed *m, uint index, bool *hasProperty) + static QV4::ReturnedValue getIndexed(const QV4::Managed *m, uint index, bool *hasProperty) { Q_ASSERT(m->as<QQmlDelegateModelGroupChangeArray>()); - QV4::ExecutionEngine *v4 = static_cast<QQmlDelegateModelGroupChangeArray *>(m)->engine(); + QV4::ExecutionEngine *v4 = static_cast<const QQmlDelegateModelGroupChangeArray *>(m)->engine(); QV4::Scope scope(v4); - QV4::Scoped<QQmlDelegateModelGroupChangeArray> array(scope, static_cast<QQmlDelegateModelGroupChangeArray *>(m)); + QV4::Scoped<QQmlDelegateModelGroupChangeArray> array(scope, static_cast<const QQmlDelegateModelGroupChangeArray *>(m)); if (index >= array->count()) { if (hasProperty) @@ -3311,12 +3306,12 @@ public: return object.asReturnedValue(); } - static QV4::ReturnedValue get(QV4::Managed *m, QV4::String *name, bool *hasProperty) + static QV4::ReturnedValue get(const QV4::Managed *m, QV4::String *name, bool *hasProperty) { Q_ASSERT(m->as<QQmlDelegateModelGroupChangeArray>()); - QQmlDelegateModelGroupChangeArray *array = static_cast<QQmlDelegateModelGroupChangeArray *>(m); + const QQmlDelegateModelGroupChangeArray *array = static_cast<const QQmlDelegateModelGroupChangeArray *>(m); - if (name->equals(array->engine()->id_length)) { + if (name->equals(array->engine()->id_length())) { if (hasProperty) *hasProperty = true; return QV4::Encode(array->count()); diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h index 5ebffd5b9d..e222fadec2 100644 --- a/src/qml/types/qqmldelegatemodel_p.h +++ b/src/qml/types/qqmldelegatemodel_p.h @@ -96,7 +96,7 @@ public: ReleaseFlags release(QObject *object); void cancel(int index); virtual QString stringValue(int index, const QString &role); - virtual void setWatchedRoles(QList<QByteArray> roles); + virtual void setWatchedRoles(const QList<QByteArray> &roles); int indexOf(QObject *object, QObject *objectContext) const; diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h index dc289eb35e..5c28021c0e 100644 --- a/src/qml/types/qqmldelegatemodel_p_p.h +++ b/src/qml/types/qqmldelegatemodel_p_p.h @@ -356,7 +356,7 @@ public: ReleaseFlags release(QObject *item); QString stringValue(int index, const QString &role); QList<QByteArray> watchedRoles() const { return m_watchedRoles; } - void setWatchedRoles(QList<QByteArray> roles); + void setWatchedRoles(const QList<QByteArray> &roles); int indexOf(QObject *item, QObject *objectContext) const; diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index ed97690adb..de46020ad8 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -88,7 +88,7 @@ const ListLayout::Role &ListLayout::getRoleOrCreate(const QString &key, Role::Da if (node) { const Role &r = *node->value; if (type != r.type) - qmlInfo(0) << QString::fromLatin1("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); + qmlInfo(0) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); return r; } @@ -101,7 +101,7 @@ const ListLayout::Role &ListLayout::getRoleOrCreate(QV4::String *key, Role::Data if (node) { const Role &r = *node->value; if (type != r.type) - qmlInfo(0) << QString::fromLatin1("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); + qmlInfo(0) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); return r; } @@ -150,7 +150,9 @@ const ListLayout::Role &ListLayout::createRole(const QString &key, ListLayout::R ListLayout::ListLayout(const ListLayout *other) : currentBlock(0), currentBlockOffset(0) { - for (int i=0 ; i < other->roles.count() ; ++i) { + const int otherRolesCount = other->roles.count(); + roles.reserve(otherRolesCount); + for (int i=0 ; i < otherRolesCount; ++i) { Role *role = new Role(other->roles[i]); roles.append(role); roleHash.insert(role->name, role); @@ -421,13 +423,13 @@ void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles) int roleIndex = -1; // Add the value now - if (QV4::String *s = propertyValue->asString()) { + if (const QV4::String *s = propertyValue->as<QV4::String>()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String); roleIndex = e->setStringProperty(r, s->toQString()); } else if (propertyValue->isNumber()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number); roleIndex = e->setDoubleProperty(r, propertyValue->asDouble()); - } else if (QV4::ArrayObject *a = propertyValue->asArrayObject()) { + } else if (QV4::ArrayObject *a = propertyValue->as<QV4::ArrayObject>()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List); ListModel *subModel = new ListModel(r.subLayout, 0, -1); @@ -441,11 +443,11 @@ void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles) } else if (propertyValue->isBoolean()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool); roleIndex = e->setBoolProperty(r, propertyValue->booleanValue()); - } else if (QV4::DateObject *dd = propertyValue->asDateObject()) { + } else if (QV4::DateObject *dd = propertyValue->as<QV4::DateObject>()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::DateTime); QDateTime dt = dd->toQDateTime(); roleIndex = e->setDateTimeProperty(r, dt); - } else if (QV4::Object *o = propertyValue->asObject()) { + } else if (QV4::Object *o = propertyValue->as<QV4::Object>()) { if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) { QObject *o = wrapper->object(); const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject); @@ -502,7 +504,7 @@ void ListModel::set(int elementIndex, QV4::Object *object) if (r.type == ListLayout::Role::Number) { e->setDoublePropertyFast(r, propertyValue->asDouble()); } - } else if (QV4::ArrayObject *a = propertyValue->asArrayObject()) { + } else if (QV4::ArrayObject *a = propertyValue->as<QV4::ArrayObject>()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List); if (r.type == ListLayout::Role::List) { ListModel *subModel = new ListModel(r.subLayout, 0, -1); @@ -520,13 +522,13 @@ void ListModel::set(int elementIndex, QV4::Object *object) if (r.type == ListLayout::Role::Bool) { e->setBoolPropertyFast(r, propertyValue->booleanValue()); } - } else if (QV4::DateObject *date = propertyValue->asDateObject()) { + } else if (QV4::DateObject *date = propertyValue->as<QV4::DateObject>()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::DateTime); if (r.type == ListLayout::Role::DateTime) { QDateTime dt = date->toQDateTime();; e->setDateTimePropertyFast(r, dt); } - } else if (QV4::Object *o = propertyValue->asObject()) { + } else if (QV4::Object *o = propertyValue->as<QV4::Object>()) { if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) { QObject *o = wrapper->object(); const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject); @@ -1169,7 +1171,7 @@ int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::Value &d roleIndex = setStringProperty(role, qstr); } else if (d.isNumber()) { roleIndex = setDoubleProperty(role, d.asDouble()); - } else if (d.asArrayObject()) { + } else if (d.as<QV4::ArrayObject>()) { QV4::ScopedArrayObject a(scope, d); if (role.type == ListLayout::Role::List) { QV4::Scope scope(a->engine()); @@ -1183,11 +1185,11 @@ int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::Value &d } roleIndex = setListProperty(role, subModel); } else { - qmlInfo(0) << QString::fromLatin1("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(role.name).arg(roleTypeName(role.type)).arg(roleTypeName(ListLayout::Role::List)); + qmlInfo(0) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(role.name).arg(roleTypeName(role.type)).arg(roleTypeName(ListLayout::Role::List)); } } else if (d.isBoolean()) { roleIndex = setBoolProperty(role, d.booleanValue()); - } else if (d.asDateObject()) { + } else if (d.as<QV4::DateObject>()) { QV4::Scoped<QV4::DateObject> dd(scope, d); QDateTime dt = dd->toQDateTime(); roleIndex = setDateTimeProperty(role, dt); @@ -1330,8 +1332,8 @@ void DynamicRoleModelNode::updateValues(const QVariantMap &object, QVector<int> QQmlListModel *subModel = QQmlListModel::createWithOwner(m_owner); QVariantList subArray = value.toList(); - QVariantList::const_iterator subIt = subArray.begin(); - QVariantList::const_iterator subEnd = subArray.end(); + QVariantList::const_iterator subIt = subArray.cbegin(); + QVariantList::const_iterator subEnd = subArray.cend(); while (subIt != subEnd) { const QVariantMap &subObject = subIt->toMap(); subModel->m_modelObjects.append(DynamicRoleModelNode::create(subObject, subModel)); @@ -1398,8 +1400,8 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index) QQmlListModel *subModel = QQmlListModel::createWithOwner(parentModel); QVariantList subArray = v.toList(); - QVariantList::const_iterator subIt = subArray.begin(); - QVariantList::const_iterator subEnd = subArray.end(); + QVariantList::const_iterator subIt = subArray.cbegin(); + QVariantList::const_iterator subEnd = subArray.cend(); while (subIt != subEnd) { const QVariantMap &subObject = subIt->toMap(); subModel->m_modelObjects.append(DynamicRoleModelNode::create(subObject, subModel)); diff --git a/src/qml/types/qqmlmodelsmodule.cpp b/src/qml/types/qqmlmodelsmodule.cpp index 3e53efd8b9..062d30c252 100644 --- a/src/qml/types/qqmlmodelsmodule.cpp +++ b/src/qml/types/qqmlmodelsmodule.cpp @@ -48,6 +48,7 @@ void QQmlModelsModule::defineModule() qmlRegisterType<QQmlDelegateModel>(uri, 2, 1, "DelegateModel"); qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 1, "DelegateModelGroup"); qmlRegisterType<QQmlObjectModel>(uri, 2, 1, "ObjectModel"); + qmlRegisterType<QQmlObjectModel,3>(uri, 2, 3, "ObjectModel"); qmlRegisterType<QItemSelectionModel>(uri, 2, 2, "ItemSelectionModel"); } diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp index 1d892beabf..0076c26950 100644 --- a/src/qml/types/qqmlobjectmodel.cpp +++ b/src/qml/types/qqmlobjectmodel.cpp @@ -36,10 +36,12 @@ #include <QtCore/qcoreapplication.h> #include <QtQml/qqmlcontext.h> #include <QtQml/qqmlengine.h> +#include <QtQml/qqmlinfo.h> #include <private/qqmlchangeset_p.h> #include <private/qqmlglobal_p.h> #include <private/qobject_p.h> +#include <private/qpodvector_p.h> #include <QtCore/qhash.h> #include <QtCore/qlist.h> @@ -67,9 +69,8 @@ public: QQmlObjectModelPrivate() : QObjectPrivate() {} static void children_append(QQmlListProperty<QObject> *prop, QObject *item) { - static_cast<QQmlObjectModelPrivate *>(prop->data)->children.append(Item(item)); - static_cast<QQmlObjectModelPrivate *>(prop->data)->itemAppended(); - static_cast<QQmlObjectModelPrivate *>(prop->data)->emitChildrenChanged(); + int index = static_cast<QQmlObjectModelPrivate *>(prop->data)->children.count(); + static_cast<QQmlObjectModelPrivate *>(prop->data)->insert(index, item); } static int children_count(QQmlListProperty<QObject> *prop) { @@ -81,33 +82,77 @@ public: } static void children_clear(QQmlListProperty<QObject> *prop) { - static_cast<QQmlObjectModelPrivate *>(prop->data)->itemCleared(static_cast<QQmlObjectModelPrivate *>(prop->data)->children); - static_cast<QQmlObjectModelPrivate *>(prop->data)->children.clear(); - static_cast<QQmlObjectModelPrivate *>(prop->data)->emitChildrenChanged(); + static_cast<QQmlObjectModelPrivate *>(prop->data)->clear(); } - void itemAppended() { + void insert(int index, QObject *item) { Q_Q(QQmlObjectModel); - QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.last().item); - attached->setIndex(children.count()-1); + children.insert(index, Item(item)); + for (int i = index; i < children.count(); ++i) { + QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item); + attached->setIndex(i); + } QQmlChangeSet changeSet; - changeSet.insert(children.count() - 1, 1); + changeSet.insert(index, 1); emit q->modelUpdated(changeSet, false); emit q->countChanged(); + emit q->childrenChanged(); } - void itemCleared(const QList<Item> &children) { + void move(int from, int to, int n) { Q_Q(QQmlObjectModel); - foreach (const Item &child, children) - emit q->destroyingItem(child.item); - emit q->countChanged(); + if (from > to) { + // Only move forwards - flip if backwards moving + int tfrom = from; + int tto = to; + from = tto; + to = tto+n; + n = tfrom-tto; + } + + QPODVector<QQmlObjectModelPrivate::Item, 4> store; + for (int i = 0; i < to - from; ++i) + store.append(children[from + n + i]); + for (int i = 0; i < n; ++i) + store.append(children[from + i]); + + for (int i = 0; i < store.count(); ++i) { + children[from + i] = store[i]; + QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(from + i).item); + attached->setIndex(from + i); + } + + QQmlChangeSet changeSet; + changeSet.move(from, to, n, -1); + emit q->modelUpdated(changeSet, false); + emit q->childrenChanged(); } - void emitChildrenChanged() { + void remove(int index, int n) { Q_Q(QQmlObjectModel); + for (int i = index; i < index + n; ++i) { + QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item); + attached->setIndex(-1); + } + children.erase(children.begin() + index, children.begin() + index + n); + for (int i = index; i < children.count(); ++i) { + QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item); + attached->setIndex(i); + } + QQmlChangeSet changeSet; + changeSet.remove(index, n); + emit q->modelUpdated(changeSet, false); + emit q->countChanged(); emit q->childrenChanged(); } + void clear() { + Q_Q(QQmlObjectModel); + foreach (const Item &child, children) + emit q->destroyingItem(child.item); + remove(0, children.count()); + } + int indexOf(QObject *item) const { for (int i = 0; i < children.count(); ++i) if (children.at(i).item == item) @@ -258,4 +303,133 @@ QQmlObjectModelAttached *QQmlObjectModel::qmlAttachedProperties(QObject *obj) return QQmlObjectModelAttached::properties(obj); } +/*! + \qmlmethod object QtQml.Models::ObjectModel::get(int index) + \since 5.6 + + Returns the item at \a index in the model. This allows the item + to be accessed or modified from JavaScript: + + \code + Component.onCompleted: { + objectModel.append(objectComponent.createObject()) + console.log(objectModel.get(0).objectName); + objectModel.get(0).objectName = "first"; + } + \endcode + + The \a index must be an element in the list. + + \sa append() +*/ +QObject *QQmlObjectModel::get(int index) const +{ + Q_D(const QQmlObjectModel); + if (index < 0 || index >= d->children.count()) + return 0; + return d->children.at(index).item; +} + +/*! + \qmlmethod QtQml.Models::ObjectModel::append(object item) + \since 5.6 + + Appends a new item to the end of the model. + + \code + objectModel.append(objectComponent.createObject()) + \endcode + + \sa insert(), remove() +*/ +void QQmlObjectModel::append(QObject *object) +{ + Q_D(QQmlObjectModel); + d->insert(count(), object); +} + +/*! + \qmlmethod QtQml.Models::ObjectModel::insert(int index, object item) + \since 5.6 + + Inserts a new item to the model at position \a index. + + \code + objectModel.insert(2, objectComponent.createObject()) + \endcode + + The \a index must be to an existing item in the list, or one past + the end of the list (equivalent to append). + + \sa append(), remove() +*/ +void QQmlObjectModel::insert(int index, QObject *object) +{ + Q_D(QQmlObjectModel); + if (index < 0 || index > count()) { + qmlInfo(this) << tr("insert: index %1 out of range").arg(index); + return; + } + d->insert(index, object); +} + +/*! + \qmlmethod QtQml.Models::ObjectModel::move(int from, int to, int n = 1) + \since 5.6 + + Moves \a n items \a from one position \a to another. + + The from and to ranges must exist; for example, to move the first 3 items + to the end of the model: + + \code + objectModel.move(0, objectModel.count - 3, 3) + \endcode + + \sa append() +*/ +void QQmlObjectModel::move(int from, int to, int n) +{ + Q_D(QQmlObjectModel); + if (n <= 0 || from == to) + return; + if (from < 0 || to < 0 || from + n > count() || to + n > count()) { + qmlInfo(this) << tr("move: out of range"); + return; + } + d->move(from, to, n); +} + +/*! + \qmlmethod QtQml.Models::ObjectModel::remove(int index, int n = 1) + \since 5.6 + + Removes the items at \a index from the model. + + \sa clear() +*/ +void QQmlObjectModel::remove(int index, int n) +{ + Q_D(QQmlObjectModel); + if (index < 0 || n <= 0 || index + n > count()) { + qmlInfo(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+n).arg(count()); + return; + } + d->remove(index, n); +} + +/*! + \qmlmethod QtQml.Models::ObjectModel::clear() + \since 5.6 + + Clears all items from the model. + + \sa append(), remove() +*/ +void QQmlObjectModel::clear() +{ + Q_D(QQmlObjectModel); + d->clear(); +} + QT_END_NAMESPACE diff --git a/src/qml/types/qqmlobjectmodel_p.h b/src/qml/types/qqmlobjectmodel_p.h index 4c37a5ac30..f6ab2a19e2 100644 --- a/src/qml/types/qqmlobjectmodel_p.h +++ b/src/qml/types/qqmlobjectmodel_p.h @@ -61,7 +61,7 @@ public: virtual ReleaseFlags release(QObject *object) = 0; virtual void cancel(int) {} virtual QString stringValue(int, const QString &) = 0; - virtual void setWatchedRoles(QList<QByteArray> roles) = 0; + virtual void setWatchedRoles(const QList<QByteArray> &roles) = 0; virtual int indexOf(QObject *object, QObject *objectContext) const = 0; @@ -99,7 +99,7 @@ public: virtual QObject *object(int index, bool asynchronous=false); virtual ReleaseFlags release(QObject *object); virtual QString stringValue(int index, const QString &role); - virtual void setWatchedRoles(QList<QByteArray>) {} + virtual void setWatchedRoles(const QList<QByteArray> &) {} virtual int indexOf(QObject *object, QObject *objectContext) const; @@ -107,6 +107,15 @@ public: static QQmlObjectModelAttached *qmlAttachedProperties(QObject *obj); + Q_REVISION(3) Q_INVOKABLE QObject *get(int index) const; + Q_REVISION(3) Q_INVOKABLE void append(QObject *object); + Q_REVISION(3) Q_INVOKABLE void insert(int index, QObject *object); + Q_REVISION(3) Q_INVOKABLE void move(int from, int to, int n = 1); + Q_REVISION(3) Q_INVOKABLE void remove(int index, int n = 1); + +public Q_SLOTS: + Q_REVISION(3) void clear(); + Q_SIGNALS: void childrenChanged(); @@ -120,7 +129,7 @@ class QQmlObjectModelAttached : public QObject public: QQmlObjectModelAttached(QObject *parent) - : QObject(parent), m_index(0) {} + : QObject(parent), m_index(-1) {} ~QQmlObjectModelAttached() { attachedProperties.remove(parent()); } diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp index c2c6e5ef5c..0aa5dc4ef6 100644 --- a/src/qml/types/qquickworkerscript.cpp +++ b/src/qml/types/qquickworkerscript.cpp @@ -54,7 +54,7 @@ #include <private/qv8engine_p.h> #include <private/qv4serialize_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4script_p.h> #include <private/qv4scopedvalue_p.h> diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp index 356970eef0..17f4ffd62b 100644 --- a/src/qml/util/qqmladaptormodel.cpp +++ b/src/qml/util/qqmladaptormodel.cpp @@ -38,7 +38,7 @@ #include <private/qqmlproperty_p.h> #include <private/qv8engine_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> QT_BEGIN_NAMESPACE @@ -159,7 +159,9 @@ public: signalIndexes.append(propertyId + signalOffset); } if (roles.isEmpty()) { - for (int propertyId = 0; propertyId < propertyRoles.count(); ++propertyId) + const int propertyRolesCount = propertyRoles.count(); + signalIndexes.reserve(propertyRolesCount); + for (int propertyId = 0; propertyId < propertyRolesCount; ++propertyId) signalIndexes.append(propertyId + signalOffset); } |