summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Hansen <kent.hansen@nokia.com>2012-07-13 13:15:09 +0200
committerQt by Nokia <qt-info@nokia.com>2012-07-13 19:47:34 +0200
commitd08de20171c0df99513514af050372fc1aee8720 (patch)
treec6a9e62706fac3f40539d2f183d3d5b8e105fc14
parentdb17c14cace450e20745839014075c0263f8618f (diff)
downloadqtscript-d08de20171c0df99513514af050372fc1aee8720.tar.gz
Fix QScriptContextInfo::functionMetaIndex() for overloaded slots
This was a regression against the pre-JavaScriptCore implementation, where we used to store the selected method index as an internal member of the QScriptContext(Private). But in the JSC-based implementation, QScriptContext is implemented as a pointer to a JSC::CallFrame, and there are no unused fields in CallFrame where the method index can be stashed. Refactor the Qt method call logic so that the method selection is separate from the actual processing of the target method. This way, QScriptContextInfo can compute the method index the same way that the actual method call did. Task-number: QTBUG-6133 Change-Id: I619fa8b91542d0b6ab5a44b00266cc0705c95823 Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
-rw-r--r--src/script/api/qscriptcontextinfo.cpp3
-rw-r--r--src/script/bridge/qscriptqobject.cpp186
-rw-r--r--src/script/bridge/qscriptqobject_p.h1
-rw-r--r--tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp6
4 files changed, 130 insertions, 66 deletions
diff --git a/src/script/api/qscriptcontextinfo.cpp b/src/script/api/qscriptcontextinfo.cpp
index 31e7cfc..0e7884f 100644
--- a/src/script/api/qscriptcontextinfo.cpp
+++ b/src/script/api/qscriptcontextinfo.cpp
@@ -197,8 +197,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<QScript::QtFunction*>(callee)->initialIndex();
+ functionMetaIndex = static_cast<QScript::QtFunction*>(callee)->specificIndex(context);
const QMetaObject *meta = static_cast<QScript::QtFunction*>(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 15288a7..3e82dbb 100644
--- a/src/script/bridge/qscriptqobject.cpp
+++ b/src/script/bridge/qscriptqobject.cpp
@@ -441,10 +441,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 <class Delegate>
+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;
@@ -456,7 +461,6 @@ static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType c
int index;
QByteArray methodName;
exec->clearException();
- QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(exec);
for (index = initialIndex; index >= 0; --index) {
QMetaMethod method = metaMethod(meta, callType, index);
@@ -844,70 +848,97 @@ static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType c
}
}
- if (chosenIndex != -1) {
- // call it
-// context->calleeMetaIndex = chosenIndex;
-
- QVarLengthArray<void*, 9> 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<QVariant*>(&v);
- break;
- case QScriptMetaType::MetaType:
- case QScriptMetaType::MetaEnum:
- case QScriptMetaType::Unresolved:
- params[i] = const_cast<void*>(v.constData());
- break;
- default:
- Q_ASSERT(0);
- }
- }
+ if (chosenIndex != -1)
+ result = delegate(exec, callType, meta, chosenMethod, chosenIndex, args);
+ }
- 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);
+ 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<QVariant, 9> &args)
+ {
+ JSC::JSValue result;
+
+ QVarLengthArray<void*, 9> 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<QVariant*>(&v);
+ break;
+ case QScriptMetaType::MetaType:
+ case QScriptMetaType::MetaEnum:
+ case QScriptMetaType::Unresolved:
+ params[i] = const_cast<void*>(v.constData());
+ break;
+ default:
+ Q_ASSERT(0);
}
+ }
-// ### fixme
-//#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
-// engine->notifyFunctionEntry(context);
-//#endif
+ 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);
+ }
- if (callType == QMetaMethod::Constructor) {
- Q_ASSERT(meta != 0);
- meta->static_metacall(QMetaObject::CreateInstance, chosenIndex, params);
- } else {
- QMetaObject::metacall(thisQObject, QMetaObject::InvokeMetaMethod, chosenIndex, params);
- }
+ // ### fixme
+ //#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
+ // engine->notifyFunctionEntry(context);
+ //#endif
- if (scriptable)
- QScriptablePrivate::get(scriptable)->engine = oldEngine;
+ if (callType == QMetaMethod::Constructor) {
+ Q_ASSERT(meta != 0);
+ meta->static_metacall(QMetaObject::CreateInstance, chosenIndex, params);
+ } else {
+ QMetaObject::metacall(thisQObject, QMetaObject::InvokeMetaMethod, chosenIndex, params);
+ }
- if (exec->hadException()) {
- result = exec->exception() ; // propagate
+ 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 {
- 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();
- }
+ result = JSC::jsUndefined();
}
}
+
+ return result;
}
- 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<QtMethodCaller>(exec, callType, scriptArgs, meta,
+ initialIndex, maybeOverloaded, caller);
}
JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
@@ -960,6 +991,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<QVariant, 9> &)
+ {
+ 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<JSC::ExecState *>(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<QtMethodIndexReturner>(
+ 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 c6ebc8a..55ed0f7 100644
--- a/src/script/bridge/qscriptqobject_p.h
+++ b/src/script/bridge/qscriptqobject_p.h
@@ -225,6 +225,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<int> overloadedIndexes() const;
diff --git a/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp b/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp
index 1dea062..7816e52 100644
--- a/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp
+++ b/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp
@@ -246,14 +246,8 @@ void tst_QScriptContextInfo::qtFunction()
QCOMPARE(info.functionName(), QString::fromLatin1("testSlot"));
QCOMPARE(info.functionEndLineNumber(), -1);
QCOMPARE(info.functionStartLineNumber(), -1);
- if (x == 0)
- QEXPECT_FAIL("", "QTBUG-6133: QScriptContextInfo doesn't pick the correct meta-index for overloaded slots", Continue);
QCOMPARE(info.functionParameterNames().size(), pnames.size());
- if (x == 0)
- QEXPECT_FAIL("", "QTBUG-6133: QScriptContextInfo doesn't pick the correct meta-index for overloaded slots", Continue);
QCOMPARE(info.functionParameterNames(), pnames);
- if (x == 0)
- QEXPECT_FAIL("", "QTBUG-6133: QScriptContextInfo doesn't pick the correct meta-index for overloaded slots", Continue);
QCOMPARE(info.functionMetaIndex(), metaObject()->indexOfMethod(sig));
}