aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-11-07 10:38:09 +0100
committerJani Heikkinen <jani.heikkinen@qt.io>2018-11-16 12:56:22 +0000
commitae6f850ab50bfe07625df4f810c7bf975c224877 (patch)
tree8cf317a283220b7270135c246489cb4e7667c3c2 /src/qml/compiler
parente3948955c961972d34483e7da9c2908f5cb84420 (diff)
Generate lookups into the global object more aggressively
Since change 9333ea8649838d7e0400b0e94c8cbd4fa5d216b0, we lookup properties in the QML context object before the global object to have proper scoping rules for QML. Unfortunately this lead to a performance regression when using global properties such as Math in imported script files, as the lookup would always go through the qml context first. This can be fixed, as we know that the global object is frozen in qml mode, and the standard names of properties in the global object are illegal to use in QML. So simply check for those names in the code generator and create lookups into the global object for those. Change-Id: I4b2089178c9e5f9440abdfd834cf7d92c3c0e2c3 Fixes: QTBUG-71591 Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
Diffstat (limited to 'src/qml/compiler')
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp10
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h1
-rw-r--r--src/qml/compiler/qv4codegen.cpp70
-rw-r--r--src/qml/compiler/qv4codegen_p.h6
4 files changed, 79 insertions, 8 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 9021fd0284..2421e8c1ea 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1835,8 +1835,9 @@ JSCodeGen::JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *
, _scopeObject(nullptr)
, _qmlContextSlot(-1)
, _importedScriptsSlot(-1)
- , m_globalNames(globalNames)
{
+ m_globalNames = globalNames;
+
_module = jsModule;
_fileNameIsUrl = true;
}
@@ -2306,15 +2307,10 @@ QV4::Compiler::Codegen::Reference JSCodeGen::fallbackNameLookup(const QString &n
return Reference::fromQmlContextObject(base, data->coreIndex(), data->notifyIndex(), capturePolicy);
}
}
-
- Reference r = Reference::fromName(this, name);
- if (m_globalNames.contains(name))
- r.global = true;
- return r;
#else
Q_UNUSED(name)
- return Reference();
#endif // V4_BOOTSTRAP
+ return Reference();
}
#ifndef V4_BOOTSTRAP
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index d1e2b17bb7..3dde929cc4 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -640,7 +640,6 @@ private:
QQmlPropertyCache *_scopeObject;
int _qmlContextSlot;
int _importedScriptsSlot;
- QSet<QString> m_globalNames;
};
struct Q_QML_PRIVATE_EXPORT IRLoader {
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 54aef16970..21fb03c1a4 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -102,6 +102,62 @@ Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict)
jsUnitGenerator->codeGeneratorName = QStringLiteral("moth");
}
+const char *globalNames[] = {
+ "isNaN",
+ "parseFloat",
+ "String",
+ "EvalError",
+ "URIError",
+ "Math",
+ "encodeURIComponent",
+ "RangeError",
+ "eval",
+ "isFinite",
+ "ReferenceError",
+ "Infinity",
+ "Function",
+ "RegExp",
+ "Number",
+ "parseInt",
+ "Object",
+ "decodeURI",
+ "TypeError",
+ "Boolean",
+ "encodeURI",
+ "NaN",
+ "Error",
+ "decodeURIComponent",
+ "Date",
+ "Array",
+ "Symbol",
+ "escape",
+ "unescape",
+ "SyntaxError",
+ "undefined",
+ "JSON",
+ "ArrayBuffer",
+ "SharedArrayBuffer",
+ "DataView",
+ "Int8Array",
+ "Uint8Array",
+ "Uint8ClampedArray",
+ "Int16Array",
+ "Uint16Array",
+ "Int32Array",
+ "Uint32Array",
+ "Float32Array",
+ "Float64Array",
+ "WeakSet",
+ "Set",
+ "WeakMap",
+ "Map",
+ "Reflect",
+ "Proxy",
+ "Atomics",
+ "Promise",
+ nullptr
+};
+
void Codegen::generateFromProgram(const QString &fileName,
const QString &finalUrl,
const QString &sourceCode,
@@ -118,6 +174,18 @@ void Codegen::generateFromProgram(const QString &fileName,
_module->fileName = fileName;
_module->finalUrl = finalUrl;
+ if (contextType == ContextType::ScriptImportedByQML) {
+ // the global object is frozen, so we know that members of it are
+ // pointing to the global object. This is important so that references
+ // to Math etc. do not go through the expensive path in the context wrapper
+ // that tries to see whether we have a matching type
+ //
+ // Since this can be called from the loader thread we can't get the list
+ // directly from the engine, so let's hardcode the most important ones here
+ for (const char **g = globalNames; *g != nullptr; ++g)
+ m_globalNames << QString::fromLatin1(*g);
+ }
+
ScanFunctions scan(this, sourceCode, contextType);
scan(node);
@@ -2350,6 +2418,8 @@ Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs, co
Reference r = Reference::fromName(this, name);
r.global = useFastLookups && (resolved.type == Context::ResolvedName::Global);
+ if (!r.global && m_globalNames.contains(name))
+ r.global = true;
return r;
}
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index e6e7d2e9fb..7630a1f71d 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -708,6 +708,11 @@ public:
return *_returnLabel;
}
+ void setGlobalNames(const QSet<QString>& globalNames) {
+ m_globalNames = globalNames;
+ }
+
+
protected:
friend class ScanFunctions;
friend struct ControlFlow;
@@ -730,6 +735,7 @@ protected:
bool inFormalParameterList = false;
bool functionEndsWithReturn = false;
bool _tailCallsAreAllowed = true;
+ QSet<QString> m_globalNames;
ControlFlow *controlFlow = nullptr;