From ae6f850ab50bfe07625df4f810c7bf975c224877 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 7 Nov 2018 10:38:09 +0100 Subject: 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 --- src/qml/compiler/qqmlirbuilder.cpp | 10 ++---- src/qml/compiler/qqmlirbuilder_p.h | 1 - src/qml/compiler/qv4codegen.cpp | 70 ++++++++++++++++++++++++++++++++++++++ src/qml/compiler/qv4codegen_p.h | 6 ++++ src/qml/jsruntime/qv4script.cpp | 1 + 5 files changed, 80 insertions(+), 8 deletions(-) (limited to 'src') 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 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& 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 m_globalNames; ControlFlow *controlFlow = nullptr; diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 951675b468..3d8c037910 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -241,6 +241,7 @@ Script *Script::createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlCo QmlIR::Document::removeScriptPragmas(sourceCode); auto result = new QV4::Script(engine, qmlContext, sourceCode, originalUrl.toString()); + result->contextType = QV4::Compiler::ContextType::ScriptImportedByQML; result->parse(); return result; } -- cgit v1.2.3 From 78745e5e778665f3a015e9cae109e77974d7fbe4 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 12 Nov 2018 09:27:33 +0100 Subject: masm: Don't call fclose(nullptr) and initialize statics Otherwise our disassembler crashes on QV4_SHOW_ASM. Change-Id: I63b20c0932452fe852773f91ebecaa7f31dd040d Reviewed-by: Erik Verbruggen (cherry picked from commit 89a1d4ff3f829635d80a90112f6b2d44cc274b1b) Reviewed-by: Lars Knoll --- src/3rdparty/masm/stubs/WTFStubs.cpp | 2 +- src/3rdparty/masm/wtf/FilePrintStream.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/3rdparty/masm/stubs/WTFStubs.cpp b/src/3rdparty/masm/stubs/WTFStubs.cpp index b26d10b3ab..f408b355f5 100644 --- a/src/3rdparty/masm/stubs/WTFStubs.cpp +++ b/src/3rdparty/masm/stubs/WTFStubs.cpp @@ -66,7 +66,7 @@ uint32_t cryptographicallyRandomNumber() return 0; } -static FilePrintStream* s_dataFile; +static FilePrintStream* s_dataFile = nullptr; void setDataFile(FilePrintStream *ps) { diff --git a/src/3rdparty/masm/wtf/FilePrintStream.cpp b/src/3rdparty/masm/wtf/FilePrintStream.cpp index a56b36526e..8ddf8487bd 100644 --- a/src/3rdparty/masm/wtf/FilePrintStream.cpp +++ b/src/3rdparty/masm/wtf/FilePrintStream.cpp @@ -39,7 +39,8 @@ FilePrintStream::~FilePrintStream() { if (m_adoptionMode == Borrow) return; - fclose(m_file); + if (m_file) + fclose(m_file); } std::unique_ptr FilePrintStream::open(const char* filename, const char* mode) -- cgit v1.2.3 From ec290770ff56791a62fde6f532e1b38e80f5b9bd Mon Sep 17 00:00:00 2001 From: Janne Koskinen Date: Fri, 16 Nov 2018 14:43:48 +0100 Subject: Initialize Qt_AllocaWrapper allocation with zeroes YarrJIT generated ASM assumes the data to be zeroed. In the wrapper we allocate from heap where there can be random data. It needs to be initialized to zero. Task-number: QTBUG-71663 Change-Id: I67c04e7b6d4bf4b92124aedc4f7bcfdc1a43c833 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4alloca_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4alloca_p.h b/src/qml/jsruntime/qv4alloca_p.h index 1e9f83a90e..65c3e4d65a 100644 --- a/src/qml/jsruntime/qv4alloca_p.h +++ b/src/qml/jsruntime/qv4alloca_p.h @@ -89,7 +89,7 @@ public: Qt_AllocaWrapper() { m_data = 0; } ~Qt_AllocaWrapper() { free(m_data); } void *data() { return m_data; } - void allocate(int size) { m_data = malloc(size); } + void allocate(int size) { m_data = malloc(size); memset(m_data, 0, size); } private: void *m_data; }; -- cgit v1.2.3 From 64ee4968b46019b8e4cb7523a6e41833fc4cf665 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 19 Nov 2018 13:52:08 +0100 Subject: QML Lexer: Stop scanning template literals on closing '`' Fixes: QTBUG-71812 Change-Id: I93b99496a7572c0f5128c69b865bb2b4f87d29af Reviewed-by: Lars Knoll Reviewed-by: Erik Verbruggen --- src/qml/parser/qqmljslexer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp index b98bb8bac5..71885c533d 100644 --- a/src/qml/parser/qqmljslexer.cpp +++ b/src/qml/parser/qqmljslexer.cpp @@ -866,7 +866,7 @@ int Lexer::scanString(ScanStringMode mode) if (sequenceLength == 2) _tokenText += *_codePtr; scanChar(); - } else if (_char == mode) { + } else if (_char == quote) { scanChar(); if (_engine) -- cgit v1.2.3