From d77765125331fec4ad4b0529e3beab3ebc16ffc2 Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Tue, 12 Jan 2016 17:35:00 +0200 Subject: [PATCH] fix QScriptContextInfo::functionMetaIndex() for overloaded slots patch applies by hand upstream commits: https://github.com/qtproject/qtscript/commit/d08de20171c0df99513514af050372fc1aee8720 Signed-off-by: Ivailo Monev --- src/script/api/qscriptcontextinfo.cpp | 3 +- src/script/bridge/qscriptqobject.cpp | 202 +++++++++++++++++--------- src/script/bridge/qscriptqobject_p.h | 1 + 3 files changed, 138 insertions(+), 68 deletions(-) diff --git a/src/script/api/qscriptcontextinfo.cpp b/src/script/api/qscriptcontextinfo.cpp index 28dccb545..590aeb4ed 100644 --- a/src/script/api/qscriptcontextinfo.cpp +++ b/src/script/api/qscriptcontextinfo.cpp @@ -199,8 +199,7 @@ QScriptContextInfoPrivate::QScriptContextInfoPrivate(const QScriptContext *conte // ### get the function name from the AST } else if (callee && callee->inherits(&QScript::QtFunction::info)) { functionType = QScriptContextInfo::QtFunction; - // ### the slot can be overloaded -- need to get the particular overload from the context - functionMetaIndex = static_cast(callee)->initialIndex(); + functionMetaIndex = static_cast(callee)->specificIndex(context); const QMetaObject *meta = static_cast(callee)->metaObject(); if (meta != 0) { QMetaMethod method = meta->method(functionMetaIndex); diff --git a/src/script/bridge/qscriptqobject.cpp b/src/script/bridge/qscriptqobject.cpp index ffdefa230..fa36a20d6 100644 --- a/src/script/bridge/qscriptqobject.cpp +++ b/src/script/bridge/qscriptqobject.cpp @@ -485,10 +485,15 @@ static QMetaMethod metaMethod(const QMetaObject *meta, return meta->constructor(index); } -static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType callType, - QObject *thisQObject, const JSC::ArgList &scriptArgs, - const QMetaObject *meta, int initialIndex, - bool maybeOverloaded) +/*! + \internal + Derives the actual method to call based on the script arguments, + \a scriptArgs, and delegates it to the given \a delegate. +*/ +template +static JSC::JSValue delegateQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType callType, + const JSC::ArgList &scriptArgs, const QMetaObject *meta, + int initialIndex, bool maybeOverloaded, Delegate &delegate) { QScriptMetaMethod chosenMethod; int chosenIndex = -1; @@ -501,7 +506,6 @@ static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType c 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); @@ -891,72 +895,99 @@ static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType c } } - if (chosenIndex != -1) { - // call it -// context->calleeMetaIndex = chosenIndex; - - QVarLengthArray array(args.count()); - void **params = array.data(); - for (int i = 0; i < args.count(); ++i) { - const QVariant &v = args[i]; - switch (chosenMethod.type(i).kind()) { - case QScriptMetaType::Variant: - params[i] = const_cast(&v); - break; - case QScriptMetaType::MetaType: - case QScriptMetaType::MetaEnum: - case QScriptMetaType::Unresolved: - params[i] = const_cast(v.constData()); - break; - default: - Q_ASSERT(0); - } - } - - QScriptable *scriptable = 0; - if (thisQObject) - scriptable = scriptableFromQObject(thisQObject); - QScriptEngine *oldEngine = 0; - if (scriptable) { - oldEngine = QScriptablePrivate::get(scriptable)->engine; - QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(engine); - } - -// ### fixme -//#ifndef Q_SCRIPT_NO_EVENT_NOTIFY -// engine->notifyFunctionEntry(context); -//#endif - - if (callType == QMetaMethod::Constructor) { - Q_ASSERT(meta != 0); - meta->static_metacall(QMetaObject::CreateInstance, chosenIndex, params); - } else { - QMetaObject::metacall(thisQObject, QMetaObject::InvokeMetaMethod, chosenIndex, params); - } - - if (scriptable) - QScriptablePrivate::get(scriptable)->engine = oldEngine; - - if (exec->hadException()) { - result = exec->exception() ; // propagate - } else { - QScriptMetaType retType = chosenMethod.returnType(); - if (retType.isVariant()) { - result = QScriptEnginePrivate::jscValueFromVariant(exec, *(QVariant *)params[0]); - } else if (retType.typeId() != 0) { - result = QScriptEnginePrivate::create(exec, retType.typeId(), params[0]); - if (!result) - result = engine->newVariant(QVariant(retType.typeId(), params[0])); - } else { - result = JSC::jsUndefined(); - } - } - } + if (chosenIndex != -1) + result = delegate(exec, callType, meta, chosenMethod, chosenIndex, args); } return result; } +struct QtMethodCaller +{ + QtMethodCaller(QObject *o) + : thisQObject(o) + {} + JSC::JSValue operator()(JSC::ExecState *exec, QMetaMethod::MethodType callType, + const QMetaObject *meta, const QScriptMetaMethod &chosenMethod, + int chosenIndex, const QVarLengthArray &args) + { + JSC::JSValue result; + + QVarLengthArray array(args.count()); + void **params = array.data(); + for (int i = 0; i < args.count(); ++i) { + const QVariant &v = args[i]; + switch (chosenMethod.type(i).kind()) { + case QScriptMetaType::Variant: + params[i] = const_cast(&v); + break; + case QScriptMetaType::MetaType: + case QScriptMetaType::MetaEnum: + case QScriptMetaType::Unresolved: + params[i] = const_cast(v.constData()); + break; + default: + Q_ASSERT(0); + } + } + + QScriptable *scriptable = 0; + if (thisQObject) + scriptable = scriptableFromQObject(thisQObject); + QScriptEngine *oldEngine = 0; + QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(exec); + if (scriptable) { + oldEngine = QScriptablePrivate::get(scriptable)->engine; + QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(engine); + } + + // ### fixme + //#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + // engine->notifyFunctionEntry(context); + //#endif + + if (callType == QMetaMethod::Constructor) { + Q_ASSERT(meta != 0); + meta->static_metacall(QMetaObject::CreateInstance, chosenIndex, params); + } else { + QMetaObject::metacall(thisQObject, QMetaObject::InvokeMetaMethod, chosenIndex, params); + } + + if (scriptable) + QScriptablePrivate::get(scriptable)->engine = oldEngine; + + if (exec->hadException()) { + result = exec->exception() ; // propagate + } else { + QScriptMetaType retType = chosenMethod.returnType(); + if (retType.isVariant()) { + result = QScriptEnginePrivate::jscValueFromVariant(exec, *(QVariant *)params[0]); + } else if (retType.typeId() != QMetaType::Void) { + result = QScriptEnginePrivate::create(exec, retType.typeId(), params[0]); + if (!result) + result = engine->newVariant(QVariant(retType.typeId(), params[0])); + } else { + result = JSC::jsUndefined(); + } + } + + return result; + } + +private: + QObject *thisQObject; +}; + +static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType callType, + QObject *thisQObject, const JSC::ArgList &scriptArgs, + const QMetaObject *meta, int initialIndex, + bool maybeOverloaded) +{ + QtMethodCaller caller(thisQObject); + return delegateQtMethod(exec, callType, scriptArgs, meta, + initialIndex, maybeOverloaded, caller); +} + JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue, const JSC::ArgList &scriptArgs) { @@ -1007,6 +1038,45 @@ JSC::JSValue JSC_HOST_CALL QtFunction::call(JSC::ExecState *exec, JSC::JSObject return result; } +struct QtMethodIndexReturner +{ + JSC::JSValue operator()(JSC::ExecState *exec, QMetaMethod::MethodType, + const QMetaObject *, const QScriptMetaMethod &, + int chosenIndex, const QVarLengthArray &) + { + return JSC::jsNumber(exec, chosenIndex); + } +}; + +/*! + \internal + Returns the specific index of the meta-method that was used in the + function call represented by the given \a context. If the method is + overloaded, the actual parameters that were passed to the function + are used to derive the selected index, matching the behavior of + callQtMethod(). +*/ +int QtFunction::specificIndex(const QScriptContext *context) const +{ + if (!maybeOverloaded()) + return initialIndex(); + JSC::ExecState *exec = const_cast(QScriptEnginePrivate::frameForContext(context)); + int argCount = exec->argumentCount(); + + // Create arguments list wrapper; this logic must match + // JITStubs.cpp op_call_NotJSFunction, and Interpreter.cpp op_call + JSC::Register* argv = exec->registers() - JSC::RegisterFile::CallFrameHeaderSize - argCount; + JSC::ArgList args(argv + 1, argCount - 1); + + QtMethodIndexReturner returner; + JSC::JSValue result = delegateQtMethod( + exec, QMetaMethod::Method, args, metaObject(), + initialIndex(), maybeOverloaded(), returner); + if (exec->hadException() || !result || !result.isInt32()) + return initialIndex(); + return result.asInt32(); +} + const JSC::ClassInfo QtPropertyFunction::info = { "QtPropertyFunction", &InternalFunction::info, 0, 0 }; QtPropertyFunction::QtPropertyFunction(const QMetaObject *meta, int index, diff --git a/src/script/bridge/qscriptqobject_p.h b/src/script/bridge/qscriptqobject_p.h index 2e119f9b7..c635c91e0 100644 --- a/src/script/bridge/qscriptqobject_p.h +++ b/src/script/bridge/qscriptqobject_p.h @@ -205,6 +205,7 @@ public: QObject *qobject() const; const QMetaObject *metaObject() const; int initialIndex() const; + int specificIndex(const QScriptContext *context) const; bool maybeOverloaded() const; int mostGeneralMethod(QMetaMethod *out = 0) const; QList overloadedIndexes() const;