From 4070bb1daafafabebb3c893a472a22fab413e4de Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Fri, 5 Mar 2010 13:24:29 +0100 Subject: Prevent a freeze of QFileSystemWatcher on Mac. On Mac when the FSEvents backend is used and a file is added or removed from a file system watcher, we need to wait until the thread is finished, otherwise it is possible that the thread already exited from the run() function but hasn't fully terminated, meaning when we restart the thread by calling start() it won't start because QThread thinks it's already running. A better fix might be to avoid stopping and starting threads - to just stop the FSEvents loop and notify the thread that a file set has changed. Task-number: QTBUG-8524 Reviewed-by: Morten --- src/corelib/io/qfilesystemwatcher_fsevents.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/corelib/io/qfilesystemwatcher_fsevents.cpp b/src/corelib/io/qfilesystemwatcher_fsevents.cpp index efbc290..d3276bd 100644 --- a/src/corelib/io/qfilesystemwatcher_fsevents.cpp +++ b/src/corelib/io/qfilesystemwatcher_fsevents.cpp @@ -171,6 +171,7 @@ QStringList QFSEventsFileSystemWatcherEngine::addPaths(const QStringList &paths, { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 stop(); + wait(); QMutexLocker locker(&mutex); QStringList failedToAdd; // if we have a running FSStreamEvent, we have to kill it, we'll re-add the stream soon. @@ -268,6 +269,7 @@ QStringList QFSEventsFileSystemWatcherEngine::removePaths(const QStringList &pat { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 stop(); + wait(); QMutexLocker locker(&mutex); // short circuit for smarties that call remove before add and we have nothing. if (pathsToWatch == 0) -- cgit v0.12 From 12308db7663679e42c87aa72c564ec3f9f1a457f Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Fri, 5 Mar 2010 14:15:54 +0100 Subject: Change behavior of applicationShouldTerminate. We now terminate the application as long as Qt says we can. If not, then we cancel the termination. Task-number: QTBUG-6296 Reviewed-by: Morten Sorvig --- src/gui/kernel/qcocoaapplicationdelegate_mac.mm | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm index ab71a05..5dcf613 100644 --- a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm +++ b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm @@ -179,7 +179,7 @@ static void cleanupCocoaApplicationDelegate() } // This function will only be called when NSApp is actually running. Before -// that, the kAEQuitApplication apple event will be sendt to +// that, the kAEQuitApplication Apple event will be sent to // QApplicationPrivate::globalAppleEventProcessor in qapplication_mac.mm - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { @@ -196,21 +196,18 @@ static void cleanupCocoaApplicationDelegate() qAppInstance()->quit(); startedQuit = false; } + return NSTerminateNow; } if (qtPrivate->threadData->eventLoops.size() == 0) { // INVARIANT: No event loop is executing. This probably // means that Qt is used as a plugin, or as a part of a native - // Cocoa application. In any case it should be fine to + // Cocoa application. In any case it should be fine to // terminate now: return NSTerminateNow; - } else { - // Prevent Cocoa from terminating the application, since this simply - // exits the program whithout allowing QApplication::exec() to return. - // The call to QApplication::quit() above will instead quit the - // application from the Qt side. - return NSTerminateCancel; } + + return NSTerminateCancel; } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification -- cgit v0.12 From 88e9515cc4300d841b16f17fe6b5c8c0d6de3562 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 5 Mar 2010 13:12:24 +0100 Subject: QMetaType::type(): return immediately if the typename is empty No need to look up / lock data structures if we know that the comparisons will all fail. This was encountered because QMetaMethod::typeName() returns an empty string if the return type is void (even though there is a QMetaType::Void (value 0) with name "void"). This was causing the QtScript meta-object binding to spend a lot of its time looking up the type for an empty string when invoking slots that return void. Rather than having these checks in QtScript and who knows where else, it's better that QMetaType::type() does it itself. No regressions in the qmetatype benchmark. Reviewed-by: Olivier Goffart Reviewed-by: Harald Fernengel --- src/corelib/kernel/qmetatype.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 8f2d025..30af6fa 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -590,6 +590,8 @@ bool QMetaType::isRegistered(int type) int QMetaType::type(const char *typeName) { int length = qstrlen(typeName); + if (!length) + return 0; int type = qMetaTypeStaticType(typeName, length); if (!type) { QReadLocker locker(customTypesLock()); -- cgit v0.12 From 8a9a160c8f509511b7e44b66a20d60fb37d614cc Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 5 Mar 2010 12:23:09 +0100 Subject: QtScript: Don't needlessly make deep copies of function names The QObject binding uses the function name to determine whether a meta-method is an overload. This was implemented quite naively by copying the name from the signature into another array before comparing it. This could cause several unnecessary memory allocations, since storing the name is really only needed when there is an exception (e.g. ambiguous call). Instead, use strncmp to compare only the relevant characters of the original (non-copied) method signature. This makes normal slot invocation from QtScript up to 15% faster. Reviewed-by: Jedrzej Nowacki --- src/script/bridge/qscriptqobject.cpp | 89 ++++++++++++++++++++++-------------- src/script/bridge/qscriptqobject_p.h | 1 - 2 files changed, 55 insertions(+), 35 deletions(-) diff --git a/src/script/bridge/qscriptqobject.cpp b/src/script/bridge/qscriptqobject.cpp index 91636da..fbb29f5 100644 --- a/src/script/bridge/qscriptqobject.cpp +++ b/src/script/bridge/qscriptqobject.cpp @@ -163,10 +163,40 @@ static bool isEnumerableMetaProperty(const QMetaProperty &prop, && (mo->indexOfProperty(prop.name()) == index); } -static inline QByteArray methodName(const QMetaMethod &method) +/*! \internal + Calculates the length of the name of the given \a method by looking + for the first '(' character. +*/ +static inline int methodNameLength(const QMetaMethod &method) { - QByteArray signature = method.signature(); - return signature.left(signature.indexOf('(')); + const char *signature = method.signature(); + const char *s = signature; + while (*s && (*s != '(')) + ++s; + return s - signature; +} + +/*! \internal + Makes a deep copy of the first \a nameLength characters of the given + method \a signature and returns the copy. +*/ +static inline QByteArray methodName(const char *signature, int nameLength) +{ + return QByteArray(signature, nameLength); +} + +/*! \internal + + Returns true if the name of the given \a method is the same as that + specified by the (signature, nameLength) pair, otherwise returns + false. +*/ +static inline bool methodNameEquals(const QMetaMethod &method, + const char *signature, int nameLength) +{ + const char *otherSignature = method.signature(); + return !qstrncmp(otherSignature, signature, nameLength) + && (otherSignature[nameLength] == '('); } static QVariant variantFromValue(JSC::ExecState *exec, int targetType, JSC::JSValue value) @@ -310,25 +340,16 @@ QList QScript::QtFunction::overloadedIndexes() const if (!maybeOverloaded()) return QList(); QList result; - QString name = functionName(); const QMetaObject *meta = metaObject(); + QMetaMethod method = meta->method(initialIndex()); + int nameLength = methodNameLength(method); for (int index = mostGeneralMethod() - 1; index >= 0; --index) { - QString otherName = QString::fromLatin1(methodName(meta->method(index))); - if (otherName == name) + if (methodNameEquals(meta->method(index), method.signature(), nameLength)) result.append(index); } return result; } -QString QtFunction::functionName() const -{ - const QMetaObject *meta = metaObject(); - if (!meta) - return QString(); - QMetaMethod method = meta->method(initialIndex()); - return QLatin1String(methodName(method)); -} - class QScriptMetaType { public: @@ -415,8 +436,8 @@ class QScriptMetaMethod public: inline QScriptMetaMethod() { } - inline QScriptMetaMethod(const QByteArray &name, const QVector &types) - : m_name(name), m_types(types), m_firstUnresolvedIndex(-1) + inline QScriptMetaMethod(const QVector &types) + : m_types(types), m_firstUnresolvedIndex(-1) { QVector::const_iterator it; for (it = m_types.constBegin(); it != m_types.constEnd(); ++it) { @@ -429,9 +450,6 @@ public: inline bool isValid() const { return !m_types.isEmpty(); } - QByteArray name() const - { return m_name; } - inline QScriptMetaType returnType() const { return m_types.at(0); } @@ -460,7 +478,6 @@ public: { return m_types; } private: - QByteArray m_name; QVector m_types; int m_firstUnresolvedIndex; }; @@ -497,7 +514,6 @@ static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType c const QMetaObject *meta, int initialIndex, bool maybeOverloaded) { - QByteArray funName; QScriptMetaMethod chosenMethod; int chosenIndex = -1; QVarLengthArray args; @@ -506,15 +522,18 @@ static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType c QVector tooFewArgs; QVector conversionFailed; int index; + int nameLength = 0; + const char *initialMethodSignature = 0; exec->clearException(); QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(exec); for (index = initialIndex; index >= 0; --index) { QMetaMethod method = metaMethod(meta, callType, index); - if (index == initialIndex) - funName = methodName(method); - else { - if (methodName(method) != funName) + if (index == initialIndex) { + initialMethodSignature = method.signature(); + nameLength = methodNameLength(method); + } else { + if (!methodNameEquals(method, initialMethodSignature, nameLength)) continue; } @@ -555,7 +574,7 @@ static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType c } } - QScriptMetaMethod mtd = QScriptMetaMethod(methodName(method), types); + QScriptMetaMethod mtd = QScriptMetaMethod(types); if (int(scriptArgs.size()) < mtd.argumentCount()) { tooFewArgs.append(index); @@ -830,9 +849,10 @@ static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType c //#ifndef Q_SCRIPT_NO_EVENT_NOTIFY // engine->notifyFunctionEntry(context); //#endif + QString funName = QString::fromLatin1(methodName(initialMethodSignature, nameLength)); if (!conversionFailed.isEmpty()) { QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n") - .arg(QLatin1String(funName)); + .arg(funName); for (int i = 0; i < conversionFailed.size(); ++i) { if (i > 0) message += QLatin1String("\n"); @@ -847,7 +867,7 @@ static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType c QScriptMetaType unresolvedType = argsInstance.method.type(unresolvedIndex); QString unresolvedTypeName = QString::fromLatin1(unresolvedType.name()); QString message = QString::fromLatin1("cannot call %0(): ") - .arg(QString::fromLatin1(funName)); + .arg(funName); if (unresolvedIndex > 0) { message.append(QString::fromLatin1("argument %0 has unknown type `%1'"). arg(unresolvedIndex).arg(unresolvedTypeName)); @@ -859,7 +879,7 @@ static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType c result = JSC::throwError(exec, JSC::TypeError, message); } else { QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n") - .arg(QLatin1String(funName)); + .arg(funName); for (int i = 0; i < tooFewArgs.size(); ++i) { if (i > 0) message += QLatin1String("\n"); @@ -875,6 +895,7 @@ static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType c && (metaArgs.args.count() == candidates.at(1).args.count()) && (metaArgs.matchDistance == candidates.at(1).matchDistance)) { // ambiguous call + QByteArray funName = methodName(initialMethodSignature, nameLength); QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n") .arg(QLatin1String(funName)); for (int i = 0; i < candidates.size(); ++i) { @@ -1240,7 +1261,7 @@ bool QObjectDelegate::getOwnPropertySlot(QScriptObject *object, JSC::ExecState * for (index = meta->methodCount() - 1; index >= offset; --index) { QMetaMethod method = meta->method(index); if (hasMethodAccess(method, index, opt) - && (methodName(method) == name)) { + && methodNameEquals(method, name.constData(), name.length())) { QtFunction *fun = new (exec)QtFunction( object, index, /*maybeOverloaded=*/true, &exec->globalData(), eng->originalGlobalObject()->functionStructure(), @@ -1372,7 +1393,7 @@ bool QObjectDelegate::getOwnPropertyDescriptor(QScriptObject *object, JSC::ExecS for (index = meta->methodCount() - 1; index >= offset; --index) { QMetaMethod method = meta->method(index); if (hasMethodAccess(method, index, opt) - && (methodName(method) == name)) { + && methodNameEquals(method, name.constData(), name.length())) { QtFunction *fun = new (exec)QtFunction( object, index, /*maybeOverloaded=*/true, &exec->globalData(), eng->originalGlobalObject()->functionStructure(), @@ -1486,7 +1507,7 @@ void QObjectDelegate::put(QScriptObject *object, JSC::ExecState* exec, for (index = meta->methodCount() - 1; index >= offset; --index) { QMetaMethod method = meta->method(index); if (hasMethodAccess(method, index, opt) - && (methodName(method) == name)) { + && methodNameEquals(method, name.constData(), name.length())) { data->cachedMembers.insert(name, value); return; } @@ -1605,7 +1626,7 @@ bool QObjectDelegate::getPropertyAttributes(const QScriptObject *object, for (index = meta->methodCount() - 1; index >= offset; --index) { QMetaMethod method = meta->method(index); if (hasMethodAccess(method, index, opt) - && (methodName(method) == name)) { + && methodNameEquals(method, name.constData(), name.length())) { attributes = QObjectMemberAttribute; if (opt & QScriptEngine::SkipMethodsInEnumeration) attributes |= JSC::DontEnum; diff --git a/src/script/bridge/qscriptqobject_p.h b/src/script/bridge/qscriptqobject_p.h index 448fa99..8b05d6b 100644 --- a/src/script/bridge/qscriptqobject_p.h +++ b/src/script/bridge/qscriptqobject_p.h @@ -212,7 +212,6 @@ public: bool maybeOverloaded() const; int mostGeneralMethod(QMetaMethod *out = 0) const; QList overloadedIndexes() const; - QString functionName() const; private: Data *data; -- cgit v0.12 From e10c1fe03fbfd3c8bdca7a68d4dc568715db4176 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 5 Mar 2010 14:31:25 +0100 Subject: Don't needlessly call pushContext() when reading properties It's only necessary to push a QScriptContext when properties are read from an object that inherits QScriptable. Postpone the decision of pushing a context until we know whether the object is a QScriptable. --- src/script/bridge/qscriptqobject.cpp | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/script/bridge/qscriptqobject.cpp b/src/script/bridge/qscriptqobject.cpp index fbb29f5..6c401f8 100644 --- a/src/script/bridge/qscriptqobject.cpp +++ b/src/script/bridge/qscriptqobject.cpp @@ -1057,14 +1057,7 @@ JSC::JSValue JSC_HOST_CALL QtPropertyFunction::call( if (!callee->inherits(&QtPropertyFunction::info)) return throwError(exec, JSC::TypeError, "callee is not a QtPropertyFunction object"); QtPropertyFunction *qfun = static_cast(callee); - QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec); - JSC::ExecState *previousFrame = eng_p->currentFrame; - eng_p->currentFrame = exec; - eng_p->pushContext(exec, thisValue, args, callee); - JSC::JSValue result = qfun->execute(eng_p->currentFrame, thisValue, args); - eng_p->popContext(); - eng_p->currentFrame = previousFrame; - return result; + return qfun->execute(exec, thisValue, args); } JSC::JSValue QtPropertyFunction::execute(JSC::ExecState *exec, @@ -1074,12 +1067,15 @@ JSC::JSValue QtPropertyFunction::execute(JSC::ExecState *exec, JSC::JSValue result = JSC::jsUndefined(); QScriptEnginePrivate *engine = scriptEngineFromExec(exec); - thisValue = engine->toUsableValue(thisValue); - QObject *qobject = QScriptEnginePrivate::toQObject(exec, thisValue); + JSC::ExecState *previousFrame = engine->currentFrame; + engine->currentFrame = exec; + + JSC::JSValue qobjectValue = engine->toUsableValue(thisValue); + QObject *qobject = QScriptEnginePrivate::toQObject(exec, qobjectValue); while ((!qobject || (qobject->metaObject() != data->meta)) - && JSC::asObject(thisValue)->prototype().isObject()) { - thisValue = JSC::asObject(thisValue)->prototype(); - qobject = QScriptEnginePrivate::toQObject(exec, thisValue); + && JSC::asObject(qobjectValue)->prototype().isObject()) { + qobjectValue = JSC::asObject(qobjectValue)->prototype(); + qobject = QScriptEnginePrivate::toQObject(exec, qobjectValue); } Q_ASSERT_X(qobject, Q_FUNC_INFO, "this-object must be a QObject"); @@ -1091,14 +1087,17 @@ JSC::JSValue QtPropertyFunction::execute(JSC::ExecState *exec, QScriptable *scriptable = scriptableFromQObject(qobject); QScriptEngine *oldEngine = 0; if (scriptable) { + engine->pushContext(exec, thisValue, args, this); oldEngine = QScriptablePrivate::get(scriptable)->engine; QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(engine); } QVariant v = prop.read(qobject); - if (scriptable) + if (scriptable) { QScriptablePrivate::get(scriptable)->engine = oldEngine; + engine->popContext(); + } result = QScriptEnginePrivate::jscValueFromVariant(exec, v); } @@ -1118,17 +1117,21 @@ JSC::JSValue QtPropertyFunction::execute(JSC::ExecState *exec, QScriptable *scriptable = scriptableFromQObject(qobject); QScriptEngine *oldEngine = 0; if (scriptable) { + engine->pushContext(exec, thisValue, args, this); oldEngine = QScriptablePrivate::get(scriptable)->engine; QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(engine); } prop.write(qobject, v); - if (scriptable) + if (scriptable) { QScriptablePrivate::get(scriptable)->engine = oldEngine; + engine->popContext(); + } result = arg; } + engine->currentFrame = previousFrame; return result; } -- cgit v0.12