aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@theqtcompany.com>2015-08-14 13:56:18 +0200
committerLars Knoll <lars.knoll@theqtcompany.com>2015-09-08 18:34:02 +0000
commitf770cebdd3d6a7f31c21e1bf04d386178122bc84 (patch)
tree2100b0010eacdca66881a0f01df6ade52468bff7
parent948bcdbc01a2c4a2df3eed187908b006f199ecc9 (diff)
Refactor the way we declare signal parameter names
Qml Connection objects where using an awkward way to make the parameter names of signals available to the signal handler. This now uses an approach that is equivalent to what we do with other functions. The main difference is that we can't know the parameter names at type compile time, so we have to rewrite the internal class of the QV4::Function at connect time. Change-Id: I5e538ac840b5a46ccb14ff71684404d947948324 Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
-rw-r--r--src/qml/jsruntime/qv4context.cpp6
-rw-r--r--src/qml/jsruntime/qv4context_p.h1
-rw-r--r--src/qml/jsruntime/qv4function.cpp31
-rw-r--r--src/qml/jsruntime/qv4function_p.h7
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp22
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h2
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp3
7 files changed, 48 insertions, 24 deletions
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index f50c5ab017..d5e2a57b20 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -98,6 +98,12 @@ Heap::QmlContext *ExecutionContext::newQmlContext(QmlContextWrapper *qml)
return d()->engine->memoryManager->alloc<QmlContext>(this, qml);
}
+Heap::QmlContext *ExecutionContext::newQmlContext(QQmlContextData *context, QObject *scopeObject)
+{
+ Scope scope(this);
+ Scoped<QmlContextWrapper> qml(scope, QmlContextWrapper::qmlScope(scope.engine, context, scopeObject));
+ return d()->engine->memoryManager->alloc<QmlContext>(this, qml);
+}
void ExecutionContext::createMutableBinding(String *name, bool deletable)
{
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 2667bbe0b2..63f8cbaac4 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -153,6 +153,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
Heap::WithContext *newWithContext(Object *with);
Heap::CatchContext *newCatchContext(String *exceptionVarName, const Value &exceptionValue);
Heap::QmlContext *newQmlContext(QmlContextWrapper *qml);
+ Heap::QmlContext *newQmlContext(QQmlContextData *context, QObject *scopeObject);
void createMutableBinding(String *name, bool deletable);
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 98a4490211..66b2125a4f 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -70,14 +70,45 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
arg = mm->alloc<String>(mm, arg->d(), engine->newString(QString(0xfffe)));
}
}
+ nFormals = compiledFunction->nFormals;
const quint32 *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable);
+
+ activationRequired = compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject));
}
Function::~Function()
{
}
+void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> &parameters)
+{
+ internalClass = engine->emptyClass;
+
+ // iterate backwards, so we get the right ordering for duplicate names
+ Scope scope(engine);
+ ScopedString arg(scope);
+ for (int i = parameters.size() - 1; i >= 0; --i) {
+ arg = engine->newString(QString::fromUtf8(parameters.at(i)));
+ while (1) {
+ InternalClass *newClass = internalClass->addMember(arg, Attr_NotConfigurable);
+ if (newClass != internalClass) {
+ internalClass = newClass;
+ break;
+ }
+ // duplicate arguments, need some trick to store them
+ arg = engine->memoryManager->alloc<String>(engine->memoryManager, arg->d(), engine->newString(QString(0xfffe)));
+ }
+ }
+ nFormals = parameters.size();
+
+ const quint32 *localsIndices = compiledFunction->localsTable();
+ for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
+ internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable);
+
+ activationRequired = true;
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 10a03bca94..534aa1b750 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -49,11 +49,16 @@ struct Q_QML_EXPORT Function {
// first nArguments names in internalClass are the actual arguments
InternalClass *internalClass;
+ uint nFormals;
+ bool activationRequired;
Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function,
ReturnedValue (*codePtr)(ExecutionEngine *, const uchar *));
~Function();
+ // used when dynamically assigning signal handlers (QQmlConnection)
+ void updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> &parameters);
+
inline Heap::String *name() {
return compilationUnit->runtimeStrings[compiledFunction->nameIndex];
}
@@ -64,7 +69,7 @@ struct Q_QML_EXPORT Function {
inline bool isNamedExpression() const { return compiledFunction->flags & CompiledData::Function::IsNamedExpression; }
inline bool needsActivation() const
- { return compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject)); }
+ { return activationRequired; }
};
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 329ecd70fc..525f806d7a 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -206,36 +206,18 @@ Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *sco
return scope->d()->engine->memoryManager->alloc<SimpleScriptFunction>(scope, function, createProto);
}
-static ReturnedValue signalParameterGetter(QV4::CallContext *ctx, uint parameterIndex)
-{
- QV4::Scope scope(ctx);
- 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);
-}
-
Heap::FunctionObject *FunctionObject::createQmlFunction(QQmlContextData *qmlContext, QObject *scopeObject, Function *runtimeFunction, const QList<QByteArray> &signalParameters, QString *error)
{
ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(qmlContext->engine);
QV4::Scope valueScope(engine);
- QV4::Scoped<QmlContextWrapper> qmlScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(engine, qmlContext, scopeObject));
ScopedContext global(valueScope, valueScope.engine->rootContext());
- QV4::Scoped<QmlContext> wrapperContext(valueScope, global->newQmlContext(qmlScopeObject));
+ QV4::Scoped<QmlContext> wrapperContext(valueScope, global->newQmlContext(qmlContext, scopeObject));
engine->popContext();
if (!signalParameters.isEmpty()) {
if (error)
QQmlPropertyCache::signalParameterStringForJS(engine, signalParameters, error);
- QV4::ScopedProperty p(valueScope);
- QV4::ScopedString s(valueScope);
- int index = 0;
- foreach (const QByteArray &param, signalParameters) {
- QV4::ScopedFunctionObject g(valueScope, engine->memoryManager->alloc<QV4::IndexedBuiltinFunction>(wrapperContext, index++, signalParameterGetter));
- p->setGetter(g);
- p->setSetter(0);
- s = engine->newString(QString::fromUtf8(param));
- qmlScopeObject->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
- }
+ runtimeFunction->updateInternalClass(engine, signalParameters);
}
QV4::ScopedFunctionObject function(valueScope, QV4::FunctionObject::createScriptFunction(wrapperContext, runtimeFunction));
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 4509923bde..d903db65a4 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -61,7 +61,7 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object {
FunctionObject(InternalClass *ic, QV4::Object *prototype);
~FunctionObject();
- unsigned int formalParameterCount() { return function ? function->compiledFunction->nFormals : 0; }
+ unsigned int formalParameterCount() { return function ? function->nFormals : 0; }
unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; }
bool needsActivation() const { return function ? function->needsActivation() : false; }
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index b55973cdc8..12415e1583 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -989,9 +989,8 @@ QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext()
{
if (!_qmlContext->objectValue()) {
QV4::Scope valueScope(v4);
- QV4::Scoped<QV4::QmlContextWrapper> qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(v4, context, _scopeObject));
QV4::ScopedContext global(valueScope, v4->rootContext());
- _qmlContext->setM(global->newQmlContext(qmlScope));
+ _qmlContext->setM(global->newQmlContext(context, _scopeObject));
v4->popContext();
}
return _qmlContext->d();