aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@qt.io>2018-04-10 15:23:30 +0200
committerErik Verbruggen <erik.verbruggen@qt.io>2018-04-10 14:15:24 +0000
commitf2633df1be25acdf1a5444bbd301955ae3412297 (patch)
treec55cb9973368cbf1eb06839d139a801c2891dea4
parent51b73e0bb68812d78315af032546750d04656c02 (diff)
Fix leak of compiler contexts
Repeatedly entering a context that was entered before would result in leaking the previously entered context. This can happen when compiling child objects in a QML file, which is done recursively. So before compiling the bindings/function in the child object, first the global context and then the QML context are entered. The fix is to re-use the global context, as it's the same anyway for all objects in the same module. And we can remove entering the QML context, because nothing is in there, and we don't put anything in it ever. Change-Id: Ib1c4259d2dec22df46e96edb65bc3d377e52e671 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp4
-rw-r--r--src/qml/compiler/qv4compilercontext.cpp2
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp21
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions_p.h7
4 files changed, 21 insertions, 13 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index a9d86b24f5..4a1b27d7aa 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1809,8 +1809,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
QVector<int> runtimeFunctionIndices(functions.size());
QV4::Compiler::ScanFunctions scan(this, sourceCode, QV4::Compiler::GlobalCode);
- scan.enterEnvironment(nullptr, QV4::Compiler::QmlBinding);
- scan.enterQmlScope(qmlRoot, QStringLiteral("context scope"));
+ scan.enterGlobalEnvironment(QV4::Compiler::QmlBinding);
for (const CompiledFunctionOrExpression &f : functions) {
Q_ASSERT(f.node != qmlRoot);
QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(f.node);
@@ -1824,7 +1823,6 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
scan.leaveEnvironment();
}
scan.leaveEnvironment();
- scan.leaveEnvironment();
_context = nullptr;
diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp
index 3293dc53c8..0a9d3d8efe 100644
--- a/src/qml/compiler/qv4compilercontext.cpp
+++ b/src/qml/compiler/qv4compilercontext.cpp
@@ -49,6 +49,8 @@ QT_BEGIN_NAMESPACE
Context *Module::newContext(Node *node, Context *parent, CompilationMode compilationMode)
{
+ Q_ASSERT(!contextMap.contains(node));
+
Context *c = new Context(parent, compilationMode);
if (node) {
SourceLocation loc = node->firstSourceLocation();
diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp
index 89f602b409..92df98f201 100644
--- a/src/qml/compiler/qv4compilerscanfunctions.cpp
+++ b/src/qml/compiler/qv4compilerscanfunctions.cpp
@@ -73,13 +73,20 @@ void ScanFunctions::operator()(Node *node)
calcEscapingVariables();
}
+void ScanFunctions::enterGlobalEnvironment(CompilationMode compilationMode)
+{
+ enterEnvironment(astNodeForGlobalEnvironment, compilationMode);
+}
+
void ScanFunctions::enterEnvironment(Node *node, CompilationMode compilationMode)
{
- Context *e = _cg->_module->newContext(node, _context, compilationMode);
- if (!e->isStrict)
- e->isStrict = _cg->_strictMode;
- _contextStack.append(e);
- _context = e;
+ Context *c = _cg->_module->contextMap.value(node);
+ if (!c)
+ c = _cg->_module->newContext(node, _context, compilationMode);
+ if (!c->isStrict)
+ c->isStrict = _cg->_strictMode;
+ _contextStack.append(c);
+ _context = c;
}
void ScanFunctions::leaveEnvironment()
@@ -440,7 +447,7 @@ void ScanFunctions::calcEscapingVariables()
{
Module *m = _cg->_module;
- for (Context *inner : m->contextMap) {
+ for (Context *inner : qAsConst(m->contextMap)) {
for (const QString &var : qAsConst(inner->usedVariables)) {
Context *c = inner;
while (c) {
@@ -468,7 +475,7 @@ void ScanFunctions::calcEscapingVariables()
static const bool showEscapingVars = qEnvironmentVariableIsSet("QV4_SHOW_ESCAPING_VARS");
if (showEscapingVars) {
qDebug() << "==== escaping variables ====";
- for (Context *c : m->contextMap) {
+ for (Context *c : qAsConst(m->contextMap)) {
qDebug() << "Context" << c->name << ":";
qDebug() << " Arguments escape" << c->argumentsCanEscape;
for (auto it = c->members.constBegin(); it != c->members.constEnd(); ++it) {
diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h
index 745e9f8a73..87b7210879 100644
--- a/src/qml/compiler/qv4compilerscanfunctions_p.h
+++ b/src/qml/compiler/qv4compilerscanfunctions_p.h
@@ -84,12 +84,10 @@ public:
ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode);
void operator()(AST::Node *node);
+ void enterGlobalEnvironment(CompilationMode compilationMode);
void enterEnvironment(AST::Node *node, CompilationMode compilationMode);
void leaveEnvironment();
- void enterQmlScope(AST::Node *ast, const QString &name)
- { enterFunction(ast, name, /*formals*/nullptr, /*body*/nullptr, /*expr*/nullptr); }
-
void enterQmlFunction(AST::FunctionDeclaration *ast)
{ enterFunction(ast, false); }
@@ -149,6 +147,9 @@ protected:
bool _allowFuncDecls;
CompilationMode defaultProgramMode;
+
+private:
+ static constexpr AST::Node *astNodeForGlobalEnvironment = nullptr;
};
}