diff options
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 10 | ||||
-rw-r--r-- | src/qml/compiler/qqmlirbuilder_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 70 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4alloca_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script.cpp | 1 | ||||
-rw-r--r-- | src/qml/parser/qqmljslexer.cpp | 2 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 9 |
8 files changed, 91 insertions, 10 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 8ec730a33d..f570af4819 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); @@ -2336,6 +2404,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 289728f505..3f96afc7c2 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; 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; }; diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index f80db86be5..7bbef3335e 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, /*parseAsBinding*/false, sourceCode, originalUrl.toString()); + result->contextType = QV4::Compiler::ContextType::ScriptImportedByQML; result->parse(); return result; } diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp index e5b8894fb1..c53b13f64d 100644 --- a/src/qml/parser/qqmljslexer.cpp +++ b/src/qml/parser/qqmljslexer.cpp @@ -884,7 +884,7 @@ int Lexer::scanString(ScanStringMode mode) scanChar(); while (_codePtr <= _endPtr) { - if (_char == mode) { + if (_char == quote) { scanChar(); if (_engine) { diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 71c4e03812..254a6bc878 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -360,6 +360,7 @@ private slots: void importLexicalVariables_data(); void importLexicalVariables(); void hugeObject(); + void templateStringTerminator(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); @@ -8858,6 +8859,14 @@ void tst_qqmlecmascript::hugeObject() QVERIFY(!v.isError()); } +void tst_qqmlecmascript::templateStringTerminator() +{ + QJSEngine engine; + const QJSValue value = engine.evaluate("let a = 123; let b = `x${a}\ny^`; b;"); + QVERIFY(!value.isError()); + QCOMPARE(value.toString(), QLatin1String("x123\ny^")); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" |