From 00f283cf54068ec55ead07df44c424c629894749 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 22 Feb 2019 13:24:14 +0100 Subject: Update plugins.qmltypes for Qt.labs.settings Update got necessary after b7b384658b21e741f9a1fde60b1c1ee69a83e278 went in. Task-number: QTBUG-73239 Change-Id: Ic93bbcf5be7f0f33d36b254b3ca30526b86c858c Reviewed-by: Paolo Angelelli Reviewed-by: Shawn Rutledge --- src/imports/settings/plugins.qmltypes | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/imports/settings/plugins.qmltypes b/src/imports/settings/plugins.qmltypes index 3c9685fe10..d6cd1c6635 100644 --- a/src/imports/settings/plugins.qmltypes +++ b/src/imports/settings/plugins.qmltypes @@ -11,13 +11,10 @@ Module { Component { name: "QQmlSettings" prototype: "QObject" - exports: [ - "Qt.labs.settings/Settings 1.0", - "Qt.labs.settings/Settings 1.1" - ] - exportMetaObjectRevisions: [0, 1] + exports: ["Qt.labs.settings/Settings 1.0"] + exportMetaObjectRevisions: [0] Property { name: "category"; type: "string" } - Property { name: "fileName"; revision: 1; type: "string" } + Property { name: "fileName"; type: "string" } Method { name: "value" type: "QVariant" -- cgit v1.2.3 From cd7ce85ff0b8f9a5163c7dc276dc7751c3f51f0f Mon Sep 17 00:00:00 2001 From: Antti Kokko Date: Wed, 20 Feb 2019 15:21:31 +0200 Subject: Add changes file for Qt 5.12.2 + 0999c78ea33d71ba211b7fa90a5d88dd5b29b3fd Avoid crash in property requirements test + 52727146db11d3f7f454e15865655d03496a3300 Fix build with -c++std=c++11 + 7bcc5242c1543785ae4d6a54b9096874a421582f Make sure JIT is disabled when building for ILP32 ABI + bcc55604d9371ea6fb6f223a5897ab44b3bc9665 quicktest: winrt: Use qml files from resource system by default + 3795904e3831722e222fa32a1e52aeb6b3e6ba87 V4: Fix stack alignment in JITted code + c0e16b469f1bce8fc96d751656a43d7396ce4276 Fix build error when building with -no-feature-translation + 0924e03e245c1d628bc7f864d6b194b137116b6e Bump version + cfdb483613494d982a574c9334f2b21621024b1b Fix crash with qt.qml.binding.removal.info=true + 4aa7fe666be35b5699b0e201c3a963777f874e4d tst_qquickapplication: Don't assume app activation is tied to window activation + f0a9c1efe36b952dfe3e802f3ceeee6ed10a65f5 Stabilize tst_QQuickPathView::package() + aca0351c7ce933503b042fd8d745d220c7dd331d QQmlMetaType: Erase attached properties in dtor + 8396dc86f28e89a920d85f59518fac79da8480eb StorageModel manual test: use DelegateChoices to show data graphically + 8fd3cfe7d0f39a731c585334299f5160ad952df9 Annotate stack traces when frames are elided through tail calls + 9e3c46961a5f48c3a704b0147e1f073f7516da9c Remove reference to OpenGL from distance field cache superclass + 84e15a609b37a64baf82ed20f8d4f79474989226 Documentation: Start using the \nullptr macro + dfb3ccddfce6376cf8028ad31d6933b8fdfd1a47 TestLib: Remove outdated note from TestCase.mouseDrag + 84a1cac0baf2e089989ef1cba31437e7c3917d95 Skip shadersource-dynamic-shadersource test on XCB platform + 8380e4c4a4f3f49a74a8bc0ff330e1c9e14dbafc Add handlers declared as Flickable children to its contentItem + feb9ace3de30170f785217fdb7c454e92ca6d525 QQmlNotifier: Always keep the isNotifying flag when updating senderPtr + ba6371fb2ae3ad0096ec672f61a7a989c297d8fc MemoryManager: Only clear weak values once + 8ad8a5ddec05832c34f0cab3c8cf6530ea6c66c8 Canvas: Guard context pointer against external deletion + f4ab0ab62496e63db72592845b285bab3d8388b9 Silent -Wdouble-promotion warning + cf04d5ee18344d45da538810654690bd3936f46a Bring behavior of String.replace() in line with other engines + 84b47be6c79761e274454d437b73a1ac2c6789c9 Add *.pro.user.* to .gitignore + 63bbaf837976bae45fdd2766da0ed4cc808cc0ac PinchHandler: Avoid unwanted translations when axes are disabled + dea0f1b1e69cd313f81dc998e973428161d411e9 PinchHandler: fix pedantic warnings + 454676a8745a7334539449562a5fda47db2fc2ca Fix byte code register dump output + 679a9972b46b0ebd03444f3c08ce7d3424c494f9 TextInput: Stop leaking password values to process memory + 729b1ceb8904a857ba4c804e8a58b9ef4ef7b193 Correctly scope unwind handlers for try blocks + b7b384658b21e741f9a1fde60b1c1ee69a83e278 Remove revisions from Qt.labs.settings methods and properties + a8729cf143a79b274c002166476c54dc152c6679 TapHander: do not "want" an eventPoint that is outside parent bounds + 205f836e5d976a983638dd2969077a9e24c1c4fd V4: Fix unwind handler reset after for-in loop + 5d8d0d7068bc8498ea2a6a4c9bc16e0eeb92836c doc: Two class members can not have the same name + d27d896d8cb9d240138fe8ea69f1051f74ce1945 Improve error message + 5de48ee56a5afb0045d40851a4a1dd79db82c772 QMLJS: Have ScanFunctions iterate over ArrayPattern nodes + 78c1fcbc49f56463064eef738a475d9018357b24 QQuickWindow: don't give exclusive grab to invisible or disabled Items + 8ab6ded97633bf7f74e7ca4de35ed56d07f358d8 Fix bug where QQMPH kept an exclusive grab when no buttons were pressed + 895302829b46e00cde8eef13eb7c630af5d771e2 Try to stabilize tst_qquickwindow::defaultSurfaceFormat + 612ac8749782af9c58a0e823b7180e0018a42be8 Doc: explain when the move velocity and duration properties are used + bb2dce1d902405acfd5aaf997860c0f0318bce77 Try to fix flakiness in flickableinterop test + 734f5a31c7a72d87a99103051ed327addae0ab99 Remove blacklisting of several tests that are passing + 24a686077579b04874f956a1dbb212a91836b64e Un-blacklist tst_qquickflickable::rebound + f2cc7c8580f2a25554cf37426096935c62a5b7af Un-blacklist tst_qquickanimations + a804f31ee2665501c1894cbae8302db181090bd5 Move initView() to tests/auto/quick/shared + eeedd26f35369a61d66283b8e2994a6e87c314fe Fix background color of some QML lancelot test scenes + 91a71bce9c633934540e9f06fb081e3b89259ff3 Defer QML testing until event loop has started + 01f9c623ed2dc1645ac022d69062f720e3b50132 Don't optimize global lookups if fast QML lookups are disabled + 1e3ed172f35abaa0e0af43ee22259bc3cd188ad8 Connect quit() and exit() signals with queued connections + 68d0377736a541fa29d1aaba6b7aa4a4cf8781ef Make test more robust in case we have interleaved update events + 0148243a77a42de1ba6170a1da3977b3026c1927 Canvas: Handle switching between object and string based colors + dbc811e164019b5f9ce371cb7b49d695644f6a90 DelegateModel: Zero foreign context objects when they are deleted + 9343fbc478e42c7aec3247486b25b34f1908e93b PropertCache: Don't pass Q_GADGET value types as integers + 8df1afa89558ddb608ff0df792d2015dd5e2e6ac V4: Fix JS tail call crashes on win32/linux32 + d96a700cc3611480ff76023287cb06f455a37b02 V4: Fix failing assert on all 32bit platforms + 94d30df911dccd830a18d7c2e75397505ef9a600 Check parameter types when invoking C++ functions from QML + 885e4af1f4ba3f047c3d932a1a780ddbba481170 QML: Don't crash the parser on certain kinds of bad input + 2131ec383b588e2160cb72247e61f7eab71cc0b1 QQuickTableView: use correct WRITE function for contentHeight + 06ec6340d0eff763e52135afabc13662b3892c43 Avoid unnecessary re-generation qml cache files in some circumstances + 56d6d905c23607a610b8af142016108063a48e3a Doc: elaborate on default values for Layout.alignment + 407e2769c7b7909fdb2979090e71fa636f109a04 Fix PropertyKey::isArrayIndex Change-Id: I47b6bb6d315c8a3306845efc01abd6f7f6c74ec2 Reviewed-by: Shawn Rutledge --- dist/changes-5.12.2 | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 dist/changes-5.12.2 diff --git a/dist/changes-5.12.2 b/dist/changes-5.12.2 new file mode 100644 index 0000000000..b092aed80d --- /dev/null +++ b/dist/changes-5.12.2 @@ -0,0 +1,101 @@ +Qt 5.12.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.0 through 5.12.1. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* QtQml * +**************************************************************************** + + - Important Behavior Changes: + * The parameters passed to C++ functions from QML are now checked for + compatibility with the expected arguments. If they cannot be + converted, a warning is printed. In future versions of Qt a type error + will be thrown in JavaScript and the function will not be invoked. + + * [QTBUG-73239] Removed revisions from the new Qt.labs.settings methods + and properties that were introduced in 5.12. Qt.labs plugins are + intended to always have revision 1.0 until they graduate. + + - QQmlApplicationEngine: + * [QTBUG-73649] QQmlApplicationEngine connects quit() and exit() signals + with queued connections to avoid problems with AutoConnection, when + connecting to QCoreApplication slots. + + - [QTBUG-69340] QML cache files are not unnecessarily re-generated. + - [QTBUG-71325] Fixed a crash in V4 string to number conversion on 32-bit + platforms. + - [QTBUG-72137] Fixed a crash in QML garbage collector when accessing + other items from Component.onDestruction. + - [QTBUG-72352] QML can be built with -no-feature-translation. + - [QTBUG-72407] We now annotate stack traces when frames are elided + through tail calls. + - [QTBUG-72734] Fixed a crash in the parser on certain kinds of bad input. + - [QTBUG-72858] Exception handlers are correctly scoped for try blocks and + for "for ... in" loops. + - [QTBUG-72908] QML can be built with -c++std=c++11 again. + - [QTBUG-72972] QQmlMetaType deletes attached properties in its destructor + to avoid a crash. + - [QTBUG-73009] Fixed a crash with qt.qml.binding.removal.info=true. + - [QTBUG-73013] If a signal sender is deleted during the handling of the + signal in QML, the QML engine won't crash anymore. + - [QTBUG-73152] Brought behavior of String.replace() in line with other + JS engines: "x".replace("x", "$1") gives "$1" in both JSC and V8, as there + are no captures that could be used as a replacement for $1. Two-digit + captures ($nm) get applied if $nm captures exist. If there are less than nm + but more than n captures available $n is replaced by the n'th capture and m + is copied over verbatim. + - [QTBUG-73425] Fixed allocation of large arrays at startup. + - [QTBUG-73733] Fixed an access-after-delete crash in DelegateModel. + - [QTBUG-73734] When a Q_GADGET type, marked as a primitive type with + Q_DECLARE_METATYPE, is emitted with a signal, it can now be accessed in QML. + - [QTBUG-73750] Fixed undefined Q_ENUM value in QML Connections object. + - [QTBUG-73821] Fixed a failing assert on 32bit platforms. + - The JIT compiler is disabled for the IPL32 (or X32) ABI. It did not work + before. + - The tail call optimization correctly counts method arguments on 32bit + platforms now. + - The JavaScript engine now tolerates UINT_MAX as array index. + +**************************************************************************** +* QtQuick * +**************************************************************************** + + - TextInput/security: + * When the TextInput is used for password input, preallocate a buffer + for the string that stores the entered value and zero-out the string + on TextInput destruction to avoid leaking sensitive data to process + memory + + - [QTBUG-63271] If a MouseArea sets itself invisible or disabled while + handling a mouse press, it does not acquire the exclusive grab + - [QTBUG-71887] TapHandler now consistently forgets touchpoints that occur + outside its parent's bounds. This eliminates the warning "pointId is + missing from current event, but was neither canceled nor released" when + tapping quickly and having some of the taps fall out of bounds. + (The warning still exists though, in case there are other scenarios where + Handlers remember "wanting" certain touchpoints and then they go missing.) + - [QTBUG-72822] PinchHandler now correctly holds its target in place when + axes are disabled. + - [QTBUG-71918] PointerHandlers are declared as direct children of + Flickable (ListView, TableView etc.) now get the pointer events properly. + - [QTBUG-42155] Canvas now handles switching between object and string + based colors + - [QTBUG-73113] Fixed a crash when reparenting QML Canvas items + - [QTBUG-73013] Fixed a crash in QuickView on setSource while deleting + the sender. + - [QT3DS-1419] Improved quality of Qt 3D Studio text labels. -- cgit v1.2.3 From 744fe84d890479962ccb85d0ed6c4515a6ea11f4 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 28 Feb 2019 15:11:36 +0100 Subject: Save some stack space during code generation Result objects are rather large, 96 bytes here. In a recursive algorithm such as our parser, we should not keep too many of them on the stack. Also, the size of Reference can be reduced by employing a bit field rather than a number of booleans. Also, try to convince the compiler to inline the accept() functions. The extra stack frames those create are unnecessary. Task-number: QTBUG-74087 Change-Id: I5c064491172366bb0abef99ffe9314080401a7d1 Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmlirbuilder.cpp | 2 +- src/qml/compiler/qv4codegen.cpp | 221 +++++++++++++++++-------------------- src/qml/compiler/qv4codegen_p.h | 88 ++++++++++++--- src/qml/parser/qqmljsast.cpp | 15 --- src/qml/parser/qqmljsast_p.h | 19 +++- 5 files changed, 192 insertions(+), 153 deletions(-) diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 2421e8c1ea..59b9968bf6 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -566,7 +566,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiQualifiedId *id) void IRBuilder::accept(QQmlJS::AST::Node *node) { - QQmlJS::AST::Node::acceptChild(node, this); + QQmlJS::AST::Node::accept(node, this); } bool IRBuilder::defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifiedId *qualifiedTypeNameId, const QQmlJS::AST::SourceLocation &location, QQmlJS::AST::UiObjectInitializer *initializer, Object *declarationsOverride) diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 256ab6e0be..b4da05eb9a 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -100,6 +100,7 @@ Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict) , hasError(false) { jsUnitGenerator->codeGeneratorName = QStringLiteral("moth"); + pushExpr(); } const char *globalNames[] = { @@ -264,7 +265,7 @@ Context *Codegen::enterBlock(Node *node) Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr) { if (hasError) - return _expr.result(); + return exprResult(); if (expr.isConstant()) { auto v = Value::fromReturnedValue(expr.constant); @@ -310,7 +311,7 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr) return Reference::fromAccumulator(this); } case PostIncrement: - if (!_expr.accept(nx) || requiresReturnValue) { + if (!exprAccept(nx) || requiresReturnValue) { Reference e = expr.asLValue(); e.loadInAccumulator(); Instruction::UPlus uplus; @@ -330,13 +331,13 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr) e.loadInAccumulator(); Instruction::Increment inc; bytecodeGenerator->addInstruction(inc); - if (_expr.accept(nx)) + if (exprAccept(nx)) return e.storeConsumeAccumulator(); else return e.storeRetainAccumulator(); } case PostDecrement: - if (!_expr.accept(nx) || requiresReturnValue) { + if (!exprAccept(nx) || requiresReturnValue) { Reference e = expr.asLValue(); e.loadInAccumulator(); Instruction::UPlus uplus; @@ -356,7 +357,7 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr) e.loadInAccumulator(); Instruction::Decrement dec; bytecodeGenerator->addInstruction(dec); - if (_expr.accept(nx)) + if (exprAccept(nx)) return e.storeConsumeAccumulator(); else return e.storeRetainAccumulator(); @@ -368,17 +369,9 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr) void Codegen::addCJump() { - bytecodeGenerator->addCJumpInstruction(_expr.trueBlockFollowsCondition(), - _expr.iftrue(), _expr.iffalse()); -} - -void Codegen::accept(Node *node) -{ - if (hasError) - return; - - if (node) - node->accept(this); + const Result &expression = currentExpr(); + bytecodeGenerator->addCJumpInstruction(expression.trueBlockFollowsCondition(), + expression.iftrue(), expression.iffalse()); } void Codegen::statement(Statement *ast) @@ -402,20 +395,19 @@ void Codegen::statement(ExpressionNode *ast) RecursionDepthCheck depthCheck(this, ast->lastSourceLocation()); RegisterScope scope(this); - Result r(nx); - qSwap(_expr, r); + pushExpr(Result(nx)); VolatileMemoryLocations vLocs = scanVolatileMemoryLocations(ast); qSwap(_volatileMemoryLocations, vLocs); accept(ast); qSwap(_volatileMemoryLocations, vLocs); - qSwap(_expr, r); + Reference result = popResult(); if (hasError) return; - if (r.result().loadTriggersSideEffect()) - r.result().loadInAccumulator(); // triggers side effects + if (result.loadTriggersSideEffect()) + result.loadInAccumulator(); // triggers side effects } } @@ -429,10 +421,9 @@ void Codegen::condition(ExpressionNode *ast, const BytecodeGenerator::Label *ift return; RecursionDepthCheck depthCheck(this, ast->lastSourceLocation()); - Result r(iftrue, iffalse, trueBlockFollowsCondition); - qSwap(_expr, r); + pushExpr(Result(iftrue, iffalse, trueBlockFollowsCondition)); accept(ast); - qSwap(_expr, r); + Result r = popExpr(); if (hasError) return; @@ -450,18 +441,6 @@ void Codegen::condition(ExpressionNode *ast, const BytecodeGenerator::Label *ift } } -Codegen::Reference Codegen::expression(ExpressionNode *ast) -{ - RecursionDepthCheck depthCheck(this, ast->lastSourceLocation()); - Result r; - if (ast) { - qSwap(_expr, r); - accept(ast); - qSwap(_expr, r); - } - return r.result(); -} - void Codegen::program(Program *ast) { if (ast) { @@ -875,17 +854,13 @@ bool Codegen::visit(ExportDeclaration *ast) Reference exportedValue; if (auto *fdecl = AST::cast(ast->variableStatementOrDeclaration)) { - Result r; - qSwap(_expr, r); + pushExpr(); visit(static_cast(fdecl)); - qSwap(_expr, r); - exportedValue = r.result(); + exportedValue = popResult(); } else if (auto *classDecl = AST::cast(ast->variableStatementOrDeclaration)) { - Result r; - qSwap(_expr, r); + pushExpr(); visit(static_cast(classDecl)); - qSwap(_expr, r); - exportedValue = r.result(); + exportedValue = popResult(); } else if (ExpressionNode *expr = ast->variableStatementOrDeclaration->expressionCast()) { exportedValue = expression(expr); } @@ -1068,7 +1043,7 @@ bool Codegen::visit(ClassExpression *ast) (void) ctor.storeRetainAccumulator(); } - _expr.setResult(Reference::fromAccumulator(this)); + setExprResult(Reference::fromAccumulator(this)); return false; } @@ -1151,7 +1126,7 @@ bool Codegen::visit(ArrayPattern *ast) } if (!it) { - _expr.setResult(Reference::fromAccumulator(this)); + setExprResult(Reference::fromAccumulator(this)); return false; } Q_ASSERT(it->element && it->element->type == PatternElement::SpreadElement); @@ -1245,7 +1220,7 @@ bool Codegen::visit(ArrayPattern *ast) } array.loadInAccumulator(); - _expr.setResult(Reference::fromAccumulator(this)); + setExprResult(Reference::fromAccumulator(this)); return false; } @@ -1261,7 +1236,7 @@ bool Codegen::visit(ArrayMemberExpression *ast) return false; if (base.isSuper()) { Reference index = expression(ast->expression).storeOnStack(); - _expr.setResult(Reference::fromSuperProperty(index)); + setExprResult(Reference::fromSuperProperty(index)); return false; } base = base.storeOnStack(); @@ -1271,17 +1246,17 @@ bool Codegen::visit(ArrayMemberExpression *ast) QString s = str->value.toString(); uint arrayIndex = QV4::String::toArrayIndex(s); if (arrayIndex == UINT_MAX) { - _expr.setResult(Reference::fromMember(base, str->value.toString())); + setExprResult(Reference::fromMember(base, str->value.toString())); return false; } Reference index = Reference::fromConst(this, QV4::Encode(arrayIndex)); - _expr.setResult(Reference::fromSubscript(base, index)); + setExprResult(Reference::fromSubscript(base, index)); return false; } Reference index = expression(ast->expression); if (hasError) return false; - _expr.setResult(Reference::fromSubscript(base, index)); + setExprResult(Reference::fromSubscript(base, index)); return false; } @@ -1312,12 +1287,13 @@ bool Codegen::visit(BinaryExpression *ast) TailCallBlocker blockTailCalls(this); if (ast->op == QSOperator::And) { - if (_expr.accept(cx)) { + if (exprAccept(cx)) { auto iftrue = bytecodeGenerator->newLabel(); - condition(ast->left, &iftrue, _expr.iffalse(), true); + condition(ast->left, &iftrue, currentExpr().iffalse(), true); iftrue.link(); blockTailCalls.unblock(); - condition(ast->right, _expr.iftrue(), _expr.iffalse(), _expr.trueBlockFollowsCondition()); + const Result &expr = currentExpr(); + condition(ast->right, expr.iftrue(), expr.iffalse(), expr.trueBlockFollowsCondition()); } else { auto iftrue = bytecodeGenerator->newLabel(); auto endif = bytecodeGenerator->newLabel(); @@ -1339,15 +1315,16 @@ bool Codegen::visit(BinaryExpression *ast) endif.link(); - _expr.setResult(Reference::fromAccumulator(this)); + setExprResult(Reference::fromAccumulator(this)); } return false; } else if (ast->op == QSOperator::Or) { - if (_expr.accept(cx)) { + if (exprAccept(cx)) { auto iffalse = bytecodeGenerator->newLabel(); - condition(ast->left, _expr.iftrue(), &iffalse, false); + condition(ast->left, currentExpr().iftrue(), &iffalse, false); iffalse.link(); - condition(ast->right, _expr.iftrue(), _expr.iffalse(), _expr.trueBlockFollowsCondition()); + const Result &expr = currentExpr(); + condition(ast->right, expr.iftrue(), expr.iffalse(), expr.trueBlockFollowsCondition()); } else { auto iffalse = bytecodeGenerator->newLabel(); auto endif = bytecodeGenerator->newLabel(); @@ -1369,7 +1346,7 @@ bool Codegen::visit(BinaryExpression *ast) endif.link(); - _expr.setResult(Reference::fromAccumulator(this)); + setExprResult(Reference::fromAccumulator(this)); } return false; } else if (ast->op == QSOperator::Assign) { @@ -1380,9 +1357,9 @@ bool Codegen::visit(BinaryExpression *ast) return false; right = right.storeOnStack(); destructurePattern(p, right); - if (!_expr.accept(nx)) { + if (!exprAccept(nx)) { right.loadInAccumulator(); - _expr.setResult(Reference::fromAccumulator(this)); + setExprResult(Reference::fromAccumulator(this)); } return false; } @@ -1402,10 +1379,10 @@ bool Codegen::visit(BinaryExpression *ast) if (hasError) return false; r.loadInAccumulator(); - if (_expr.accept(nx)) - _expr.setResult(left.storeConsumeAccumulator()); + if (exprAccept(nx)) + setExprResult(left.storeConsumeAccumulator()); else - _expr.setResult(left.storeRetainAccumulator()); + setExprResult(left.storeRetainAccumulator()); return false; } @@ -1448,7 +1425,7 @@ bool Codegen::visit(BinaryExpression *ast) return false; binopHelper(baseOp(ast->op), tempLeft, right).loadInAccumulator(); - _expr.setResult(left.storeRetainAccumulator()); + setExprResult(left.storeRetainAccumulator()); break; } @@ -1460,7 +1437,7 @@ bool Codegen::visit(BinaryExpression *ast) Reference right = expression(ast->right); if (hasError) return false; - _expr.setResult(binopHelper(static_cast(ast->op), right, left)); + setExprResult(binopHelper(static_cast(ast->op), right, left)); break; } // intentional fall-through! @@ -1486,7 +1463,7 @@ bool Codegen::visit(BinaryExpression *ast) Reference right; if (AST::NumericLiteral *rhs = AST::cast(ast->right)) { visit(rhs); - right = _expr.result(); + right = exprResult(); } else { left = left.storeOnStack(); // force any loads of the lhs, so the rhs won't clobber it right = expression(ast->right); @@ -1494,7 +1471,7 @@ bool Codegen::visit(BinaryExpression *ast) if (hasError) return false; - _expr.setResult(binopHelper(static_cast(ast->op), left, right)); + setExprResult(binopHelper(static_cast(ast->op), left, right)); break; } @@ -1671,7 +1648,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re break; } case QSOperator::StrictEqual: { - if (_expr.accept(cx)) + if (exprAccept(cx)) return jumpBinop(oper, left, right); Instruction::CmpStrictEqual cmp; @@ -1682,7 +1659,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re break; } case QSOperator::StrictNotEqual: { - if (_expr.accept(cx)) + if (exprAccept(cx)) return jumpBinop(oper, left, right); Instruction::CmpStrictNotEqual cmp; @@ -1693,7 +1670,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re break; } case QSOperator::Equal: { - if (_expr.accept(cx)) + if (exprAccept(cx)) return jumpBinop(oper, left, right); Instruction::CmpEq cmp; @@ -1704,7 +1681,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re break; } case QSOperator::NotEqual: { - if (_expr.accept(cx)) + if (exprAccept(cx)) return jumpBinop(oper, left, right); Instruction::CmpNe cmp; @@ -1715,7 +1692,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re break; } case QSOperator::Gt: { - if (_expr.accept(cx)) + if (exprAccept(cx)) return jumpBinop(oper, left, right); Instruction::CmpGt cmp; @@ -1726,7 +1703,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re break; } case QSOperator::Ge: { - if (_expr.accept(cx)) + if (exprAccept(cx)) return jumpBinop(oper, left, right); Instruction::CmpGe cmp; @@ -1737,7 +1714,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re break; } case QSOperator::Lt: { - if (_expr.accept(cx)) + if (exprAccept(cx)) return jumpBinop(oper, left, right); Instruction::CmpLt cmp; @@ -1748,7 +1725,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re break; } case QSOperator::Le: - if (_expr.accept(cx)) + if (exprAccept(cx)) return jumpBinop(oper, left, right); Instruction::CmpLe cmp; @@ -1952,7 +1929,7 @@ bool Codegen::visit(CallExpression *ast) bytecodeGenerator->addInstruction(call); } - _expr.setResult(Reference::fromAccumulator(this)); + setExprResult(Reference::fromAccumulator(this)); return false; } @@ -2045,7 +2022,7 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio bytecodeGenerator->addInstruction(call); } - _expr.setResult(Reference::fromAccumulator(this)); + setExprResult(Reference::fromAccumulator(this)); } Codegen::Arguments Codegen::pushArgs(ArgumentList *args) @@ -2141,7 +2118,7 @@ bool Codegen::visit(ConditionalExpression *ast) ko.loadInAccumulator(); jump_endif.link(); - _expr.setResult(Reference::fromAccumulator(this)); + setExprResult(Reference::fromAccumulator(this)); return false; } @@ -2171,7 +2148,7 @@ bool Codegen::visit(DeleteExpression *ast) throwSyntaxError(ast->deleteToken, QStringLiteral("Delete of an unqualified identifier in strict mode.")); return false; } - _expr.setResult(Reference::fromConst(this, QV4::Encode(false))); + setExprResult(Reference::fromConst(this, QV4::Encode(false))); return false; case Reference::Name: { if (_context->isStrict) { @@ -2181,7 +2158,7 @@ bool Codegen::visit(DeleteExpression *ast) Instruction::DeleteName del; del.name = expr.nameAsIndex(); bytecodeGenerator->addInstruction(del); - _expr.setResult(Reference::fromAccumulator(this)); + setExprResult(Reference::fromAccumulator(this)); return false; } case Reference::Member: { @@ -2196,7 +2173,7 @@ bool Codegen::visit(DeleteExpression *ast) del.base = expr.propertyBase.stackSlot(); del.index = index.stackSlot(); bytecodeGenerator->addInstruction(del); - _expr.setResult(Reference::fromAccumulator(this)); + setExprResult(Reference::fromAccumulator(this)); return false; } case Reference::Subscript: { @@ -2206,14 +2183,14 @@ bool Codegen::visit(DeleteExpression *ast) del.base = expr.elementBase; del.index = expr.elementSubscript.stackSlot(); bytecodeGenerator->addInstruction(del); - _expr.setResult(Reference::fromAccumulator(this)); + setExprResult(Reference::fromAccumulator(this)); return false; } default: break; } // [[11.4.1]] Return true if it's not a reference - _expr.setResult(Reference::fromConst(this, QV4::Encode(true))); + setExprResult(Reference::fromConst(this, QV4::Encode(true))); return false; } @@ -2222,7 +2199,7 @@ bool Codegen::visit(FalseLiteral *) if (hasError) return false; - _expr.setResult(Reference::fromConst(this, QV4::Encode(false))); + setExprResult(Reference::fromConst(this, QV4::Encode(false))); return false; } @@ -2231,7 +2208,7 @@ bool Codegen::visit(SuperLiteral *) if (hasError) return false; - _expr.setResult(Reference::fromSuper(this)); + setExprResult(Reference::fromSuper(this)); return false; } @@ -2249,12 +2226,12 @@ bool Codegen::visit(FieldMemberExpression *ast) if (_context->isArrowFunction || _context->contextType == ContextType::Eval) { Reference r = referenceForName(QStringLiteral("new.target"), false); r.isReadonly = true; - _expr.setResult(r); + setExprResult(r); return false; } Reference r = Reference::fromStackSlot(this, CallData::NewTarget); - _expr.setResult(r); + setExprResult(r); return false; } } @@ -2267,10 +2244,10 @@ bool Codegen::visit(FieldMemberExpression *ast) load.stringId = registerString(ast->name.toString()); bytecodeGenerator->addInstruction(load); Reference property = Reference::fromAccumulator(this).storeOnStack(); - _expr.setResult(Reference::fromSuperProperty(property)); + setExprResult(Reference::fromSuperProperty(property)); return false; } - _expr.setResult(Reference::fromMember(base, ast->name.toString())); + setExprResult(Reference::fromMember(base, ast->name.toString())); return false; } @@ -2280,12 +2257,15 @@ bool Codegen::visit(TaggedTemplate *ast) return false; RegisterScope scope(this); + return handleTaggedTemplate(expression(ast->base), ast); +} - int functionObject = -1, thisObject = -1; - - Reference base = expression(ast->base); +bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast) +{ if (hasError) return false; + + int functionObject = -1, thisObject = -1; switch (base.type) { case Reference::Member: case Reference::Subscript: @@ -2346,7 +2326,7 @@ bool Codegen::visit(FunctionExpression *ast) if (hasError) return false; loadClosure(function); - _expr.setResult(Reference::fromAccumulator(this)); + setExprResult(Reference::fromAccumulator(this)); return false; } @@ -2412,7 +2392,7 @@ bool Codegen::visit(IdentifierExpression *ast) if (hasError) return false; - _expr.setResult(referenceForName(ast->name.toString(), false, ast->firstSourceLocation())); + setExprResult(referenceForName(ast->name.toString(), false, ast->firstSourceLocation())); return false; } @@ -2462,7 +2442,7 @@ void Codegen::handleConstruct(const Reference &base, ArgumentList *arguments) // set the result up as the thisObject Reference::fromAccumulator(this).storeOnStack(CallData::This); - _expr.setResult(Reference::fromAccumulator(this)); + setExprResult(Reference::fromAccumulator(this)); } bool Codegen::visit(NewExpression *ast) @@ -2511,7 +2491,7 @@ bool Codegen::visit(NotExpression *ast) return false; TailCallBlocker blockTailCalls(this); - _expr.setResult(unop(Not, expression(ast->expression))); + setExprResult(unop(Not, expression(ast->expression))); return false; } @@ -2520,10 +2500,10 @@ bool Codegen::visit(NullExpression *) if (hasError) return false; - if (_expr.accept(cx)) - bytecodeGenerator->jump().link(*_expr.iffalse()); + if (exprAccept(cx)) + bytecodeGenerator->jump().link(*currentExpr().iffalse()); else - _expr.setResult(Reference::fromConst(this, Encode::null())); + setExprResult(Reference::fromConst(this, Encode::null())); return false; } @@ -2533,7 +2513,7 @@ bool Codegen::visit(NumericLiteral *ast) if (hasError) return false; - _expr.setResult(Reference::fromConst(this, QV4::Encode::smallestNumber(ast->value))); + setExprResult(Reference::fromConst(this, QV4::Encode::smallestNumber(ast->value))); return false; } @@ -2648,8 +2628,7 @@ bool Codegen::visit(ObjectPattern *ast) call.argc = argc; call.args = Moth::StackSlot::createRegister(args); bytecodeGenerator->addInstruction(call); - Reference result = Reference::fromAccumulator(this); - _expr.setResult(result); + setExprResult(Reference::fromAccumulator(this)); return false; } @@ -2668,7 +2647,7 @@ bool Codegen::visit(PostDecrementExpression *ast) if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken)) return false; - _expr.setResult(unop(PostDecrement, expr)); + setExprResult(unop(PostDecrement, expr)); return false; } @@ -2688,7 +2667,7 @@ bool Codegen::visit(PostIncrementExpression *ast) if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken)) return false; - _expr.setResult(unop(PostIncrement, expr)); + setExprResult(unop(PostIncrement, expr)); return false; } @@ -2706,7 +2685,7 @@ bool Codegen::visit(PreDecrementExpression *ast) if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken)) return false; - _expr.setResult(unop(PreDecrement, expr)); + setExprResult(unop(PreDecrement, expr)); return false; } @@ -2725,7 +2704,7 @@ bool Codegen::visit(PreIncrementExpression *ast) if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken)) return false; - _expr.setResult(unop(PreIncrement, expr)); + setExprResult(unop(PreIncrement, expr)); return false; } @@ -2736,7 +2715,7 @@ bool Codegen::visit(RegExpLiteral *ast) auto r = Reference::fromStackSlot(this); r.isReadonly = true; - _expr.setResult(r); + setExprResult(r); Instruction::MoveRegExp instr; instr.regExpId = jsUnitGenerator->registerRegExp(ast); @@ -2752,7 +2731,7 @@ bool Codegen::visit(StringLiteral *ast) auto r = Reference::fromAccumulator(this); r.isReadonly = true; - _expr.setResult(r); + setExprResult(r); Instruction::LoadRuntimeString instr; instr.stringId = registerString(ast->value.toString()); @@ -2802,7 +2781,7 @@ bool Codegen::visit(TemplateLiteral *ast) auto r = Reference::fromAccumulator(this); r.isReadonly = true; - _expr.setResult(r); + setExprResult(r); return false; } @@ -2815,10 +2794,10 @@ bool Codegen::visit(ThisExpression *) if (_context->isArrowFunction) { Reference r = referenceForName(QStringLiteral("this"), false); r.isReadonly = true; - _expr.setResult(r); + setExprResult(r); return false; } - _expr.setResult(Reference::fromThis(this)); + setExprResult(Reference::fromThis(this)); return false; } @@ -2828,7 +2807,7 @@ bool Codegen::visit(TildeExpression *ast) return false; TailCallBlocker blockTailCalls(this); - _expr.setResult(unop(Compl, expression(ast->expression))); + setExprResult(unop(Compl, expression(ast->expression))); return false; } @@ -2837,7 +2816,7 @@ bool Codegen::visit(TrueLiteral *) if (hasError) return false; - _expr.setResult(Reference::fromConst(this, QV4::Encode(true))); + setExprResult(Reference::fromConst(this, QV4::Encode(true))); return false; } @@ -2863,7 +2842,7 @@ bool Codegen::visit(TypeOfExpression *ast) Instruction::TypeofValue instr; bytecodeGenerator->addInstruction(instr); } - _expr.setResult(Reference::fromAccumulator(this)); + setExprResult(Reference::fromAccumulator(this)); return false; } @@ -2874,7 +2853,7 @@ bool Codegen::visit(UnaryMinusExpression *ast) return false; TailCallBlocker blockTailCalls(this); - _expr.setResult(unop(UMinus, expression(ast->expression))); + setExprResult(unop(UMinus, expression(ast->expression))); return false; } @@ -2884,7 +2863,7 @@ bool Codegen::visit(UnaryPlusExpression *ast) return false; TailCallBlocker blockTailCalls(this); - _expr.setResult(unop(UPlus, expression(ast->expression))); + setExprResult(unop(UPlus, expression(ast->expression))); return false; } @@ -2897,7 +2876,7 @@ bool Codegen::visit(VoidExpression *ast) TailCallBlocker blockTailCalls(this); statement(ast->expression); - _expr.setResult(Reference::fromConst(this, Encode::undefined())); + setExprResult(Reference::fromConst(this, Encode::undefined())); return false; } @@ -2911,7 +2890,7 @@ bool Codegen::visit(FunctionDeclaration * ast) if (_functionContext->contextType == ContextType::Binding) referenceForName(ast->name.toString(), true).loadInAccumulator(); - _expr.accept(nx); + exprAccept(nx); return false; } @@ -2967,7 +2946,7 @@ bool Codegen::visit(YieldExpression *ast) done.link(); lhsValue.loadInAccumulator(); - _expr.setResult(acc); + setExprResult(acc); return false; } @@ -2978,7 +2957,7 @@ bool Codegen::visit(YieldExpression *ast) BytecodeGenerator::Jump jump = bytecodeGenerator->addJumpInstruction(resume); emitReturn(acc); jump.link(); - _expr.setResult(acc); + setExprResult(acc); return false; } diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 4d7001fe64..c1063bc0d0 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -192,8 +192,24 @@ public: bool isLValue() const { return !isReadonly && type > Accumulator; } - Reference(Codegen *cg, Type type = Invalid) : type(type), constant(0), codegen(cg) {} - Reference(): constant(0) {} + Reference(Codegen *cg, Type t = Invalid) : Reference() + { + type = t; + codegen = cg; + } + + Reference() : + constant(0), + isArgOrEval(false), + isReadonly(false), + isReferenceToConst(false), + requiresTDZCheck(false), + subscriptRequiresTDZCheck(false), + stackSlotIsLocalOrArgument(false), + isVolatile(false), + global(false) + {} + Reference(const Reference &) = default; Reference(Reference &&) = default; Reference &operator =(const Reference &) = default; @@ -395,16 +411,17 @@ public: Moth::StackSlot property; // super property }; QString name; - mutable bool isArgOrEval = false; - bool isReadonly = false; - bool isReferenceToConst = false; - bool requiresTDZCheck = false; - bool subscriptRequiresTDZCheck = false; - bool stackSlotIsLocalOrArgument = false; - bool isVolatile = false; - bool global = false; Codegen *codegen = nullptr; + quint32 isArgOrEval:1; + quint32 isReadonly:1; + quint32 isReferenceToConst:1; + quint32 requiresTDZCheck:1; + quint32 subscriptRequiresTDZCheck:1; + quint32 stackSlotIsLocalOrArgument:1; + quint32 isVolatile:1; + quint32 global:1; + private: void storeAccumulator() const; Reference doStoreOnStack(int tempIndex) const; @@ -499,6 +516,10 @@ protected: void setResult(const Reference &result) { _result = result; } + + void setResult(Reference &&result) { + _result = std::move(result); + } }; void enterContext(AST::Node *node); @@ -544,9 +565,23 @@ protected: void condition(AST::ExpressionNode *ast, const BytecodeGenerator::Label *iftrue, const BytecodeGenerator::Label *iffalse, bool trueBlockFollowsCondition); - Reference expression(AST::ExpressionNode *ast); - void accept(AST::Node *node); + inline Reference expression(AST::ExpressionNode *ast) + { + if (!ast || hasError) + return Reference(); + + RecursionDepthCheck depthCheck(this, ast->lastSourceLocation()); + pushExpr(); + ast->accept(this); + return popResult(); + } + + inline void accept(AST::Node *node) + { + if (!hasError && node) + node->accept(this); + } void program(AST::Program *ast); void statementList(AST::StatementList *ast); @@ -684,6 +719,7 @@ public: void handleCall(Reference &base, Arguments calldata, int slotForFunction, int slotForThisObject); Arguments pushTemplateArgs(AST::TemplateLiteral *args); + bool handleTaggedTemplate(Reference base, AST::TaggedTemplate *ast); void createTemplateObject(AST::TemplateLiteral *t); void setUseFastLookups(bool b) { useFastLookups = b; } @@ -720,7 +756,33 @@ protected: friend struct ControlFlow; friend struct ControlFlowCatch; friend struct ControlFlowFinally; - Result _expr; + + inline void setExprResult(const Reference &result) { m_expressions.back().setResult(result); } + inline void setExprResult(Reference &&result) { m_expressions.back().setResult(std::move(result)); } + inline Reference exprResult() const { return m_expressions.back().result(); } + + inline bool exprAccept(Format f) { return m_expressions.back().accept(f); } + + inline const Result ¤tExpr() const { return m_expressions.back(); } + + inline void pushExpr(Result &&expr) { m_expressions.push_back(std::move(expr)); } + inline void pushExpr(const Result &expr) { m_expressions.push_back(expr); } + inline void pushExpr() { m_expressions.emplace_back(); } + + inline Result popExpr() + { + const Result result = m_expressions.back(); + m_expressions.pop_back(); + return result; + } + + inline Reference popResult() { + const Reference result = m_expressions.back().result(); + m_expressions.pop_back(); + return result; + } + + std::vector m_expressions; VolatileMemoryLocations _volatileMemoryLocations; Module *_module; int _returnAddress; diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp index 4ebb2d3b5c..54a1200493 100644 --- a/src/qml/parser/qqmljsast.cpp +++ b/src/qml/parser/qqmljsast.cpp @@ -65,21 +65,6 @@ ClassExpression *asAnonymousClassDefinition(Node *n) return c; } - -void Node::accept(Visitor *visitor) -{ - if (visitor->preVisit(this)) { - accept0(visitor); - } - visitor->postVisit(this); -} - -void Node::accept(Node *node, Visitor *visitor) -{ - if (node) - node->accept(visitor); -} - ExpressionNode *Node::expressionCast() { return nullptr; diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index 43aeec6525..0978ab523a 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -271,11 +271,24 @@ public: virtual FunctionExpression *asFunctionDefinition(); virtual ClassExpression *asClassDefinition(); - void accept(Visitor *visitor); - static void accept(Node *node, Visitor *visitor); + inline void accept(Visitor *visitor) + { + if (visitor->preVisit(this)) + accept0(visitor); + visitor->postVisit(this); + } + inline static void accept(Node *node, Visitor *visitor) + { + if (node) + node->accept(visitor); + } + + // ### Remove when we can. This is part of the qmldevtools library, though. inline static void acceptChild(Node *node, Visitor *visitor) - { return accept(node, visitor); } // ### remove + { + return accept(node, visitor); + } virtual void accept0(Visitor *visitor) = 0; virtual SourceLocation firstSourceLocation() const = 0; -- cgit v1.2.3 From 7e32be87c0f53ce2e5d3c1e351a559d6c600f1bf Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 4 Mar 2019 15:36:57 +0100 Subject: Don't keep raw pointers to SparseArrayNode The nodes are owned by the SparseArrayData and will be freed whenever an item is deleted from the array. Therefore, we have to look up the node for each iteration. This is slightly slower, but at least it doesn't crash. Fixes: QTBUG-74188 Change-Id: Id24324a8c83b00b3ad1212cdaabccabd6c8a999f Reviewed-by: Simon Hausmann Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4object.cpp | 8 +++++--- src/qml/jsruntime/qv4object_p.h | 1 - src/qml/jsruntime/qv4stringobject.cpp | 2 +- .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 22 ++++++++++++++++++++++ 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 3d2d54f651..9d6cb730a9 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -320,8 +320,11 @@ bool Object::virtualDeleteProperty(Managed *m, PropertyKey id) PropertyKey ObjectOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs) { if (arrayIndex != UINT_MAX && o->arrayData()) { - if (!arrayIndex) - arrayNode = o->sparseBegin(); + SparseArrayNode *arrayNode = nullptr; + if (o->arrayType() == Heap::ArrayData::Sparse) { + SparseArray *sparse = o->arrayData()->sparse; + arrayNode = arrayIndex ? sparse->lowerBound(arrayIndex) : sparse->begin(); + } // sparse arrays if (arrayNode) { @@ -339,7 +342,6 @@ PropertyKey ObjectOwnPropertyKeyIterator::next(const Object *o, Property *pd, Pr *attrs = a; return PropertyKey::fromArrayIndex(k); } - arrayNode = nullptr; arrayIndex = UINT_MAX; } // dense arrays diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index ff47810994..9f24449c91 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -408,7 +408,6 @@ struct ObjectOwnPropertyKeyIterator : OwnPropertyKeyIterator uint arrayIndex = 0; uint memberIndex = 0; bool iterateOverSymbols = false; - SparseArrayNode *arrayNode = nullptr; ~ObjectOwnPropertyKeyIterator() override = default; PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override; diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 8186153ba4..dee6a67792 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -130,7 +130,7 @@ PropertyKey StringObjectOwnPropertyKeyIterator::next(const QV4::Object *o, Prope return PropertyKey::fromArrayIndex(index); } else if (arrayIndex == slen) { if (s->arrayData()) { - arrayNode = s->sparseBegin(); + SparseArrayNode *arrayNode = s->sparseBegin(); // iterate until we're past the end of the string while (arrayNode && arrayNode->key() < slen) arrayNode = arrayNode->nextNode(); diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index eb9b05e764..a67a503f82 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -364,6 +364,7 @@ private slots: void arrayAndException(); void numberToStringWithRadix(); void tailCallWithArguments(); + void deleteSparseInIteration(); private: // static void propertyVarWeakRefCallback(v8::Persistent object, void* parameter); @@ -8907,6 +8908,27 @@ void tst_qqmlecmascript::tailCallWithArguments() QCOMPARE(value.toInt(), 1); } +void tst_qqmlecmascript::deleteSparseInIteration() +{ + QJSEngine engine; + const QJSValue value = engine.evaluate( + "(function() {\n" + " var obj = { 1: null, 2: null, 4096: null };\n" + " var iterated = [];\n" + " for (var t in obj) {\n" + " if (t == 2)\n" + " delete obj[t];\n" + " iterated.push(t);\n" + " }\n" + " return iterated;" + "})()"); + QVERIFY(value.isArray()); + QCOMPARE(value.property("length").toInt(), 3); + QCOMPARE(value.property("0").toInt(), 1); + QCOMPARE(value.property("1").toInt(), 2); + QCOMPARE(value.property("2").toInt(), 4096); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" -- cgit v1.2.3 From 93601b1fd4aae326562c6e7cfe16d5ecf2532a6a Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Thu, 14 Mar 2019 13:07:01 +0100 Subject: Doc: Link to the correct example in Qt Quick States topic While there is no dedicated example for states and transitions for Qt Quick, the Animation example covers these concepts. Fixes: QTBUG-74428 Change-Id: I00f6ca54123011599ebbb6b7bc53d3104b1586ca Reviewed-by: Mitch Curtis --- src/quick/doc/src/concepts/statesanimations/states.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/doc/src/concepts/statesanimations/states.qdoc b/src/quick/doc/src/concepts/statesanimations/states.qdoc index b695713091..5592ccd25d 100644 --- a/src/quick/doc/src/concepts/statesanimations/states.qdoc +++ b/src/quick/doc/src/concepts/statesanimations/states.qdoc @@ -120,7 +120,7 @@ interpolation behaviors are definable. The {Animation and Transitions} article has more information about creating state animations. -The \l {animation/states}{States and Transitions example} +The \l {Qt Quick Examples - Animation}{Animation} example demonstrates how to declare a basic set of states and apply animated transitions between them. -- cgit v1.2.3 From 73231fe953145ac0df4e62f173e1a90076466012 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 27 Feb 2019 16:01:54 +0100 Subject: Unify the JavaScript parsing recursion checks We only need to check in one central location and we can allow for more recursion. 4k recursions seem tolerable. A common default for stack sizes is 8MB. Each recursion step takes up to 1k stack space in debug mode. So, exhausting this would burn about half of the available stack size. We don't report the exact source location in this case as finding the source location may itself trigger a deep recursion. Fixes: QTBUG-74087 Change-Id: I43e6e20b322f6035c7136a6f381230ec285c30ae Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmlirbuilder_p.h | 6 +++++ src/qml/compiler/qv4codegen.cpp | 37 ++++++++++++++++++++------- src/qml/compiler/qv4codegen_p.h | 33 +++++------------------- src/qml/compiler/qv4compilerscanfunctions.cpp | 27 +++++-------------- src/qml/compiler/qv4compilerscanfunctions_p.h | 7 ++--- src/qml/jsruntime/qv4runtimecodegen_p.h | 1 + src/qml/parser/qqmljs.g | 10 +------- src/qml/parser/qqmljsast_p.h | 11 +++++--- src/qml/parser/qqmljsastvisitor.cpp | 2 +- src/qml/parser/qqmljsastvisitor_p.h | 36 +++++++++++++++++++++++++- tests/auto/qml/qqmlparser/tst_qqmlparser.cpp | 5 ++++ 11 files changed, 100 insertions(+), 75 deletions(-) diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 1a3ca4163e..6affca3ca6 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -498,6 +498,12 @@ public: bool visit(QQmlJS::AST::UiScriptBinding *ast) override; bool visit(QQmlJS::AST::UiSourceElement *ast) override; + void throwRecursionDepthError() override + { + recordError(AST::SourceLocation(), + QStringLiteral("Maximum statement or expression depth exceeded")); + } + void accept(QQmlJS::AST::Node *node); // returns index in _objects diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index b4da05eb9a..0ca452b93e 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -376,7 +376,6 @@ void Codegen::addCJump() void Codegen::statement(Statement *ast) { - RecursionDepthCheck depthCheck(this, ast->lastSourceLocation()); RegisterScope scope(this); bytecodeGenerator->setLocation(ast->firstSourceLocation()); @@ -392,7 +391,6 @@ void Codegen::statement(ExpressionNode *ast) if (! ast) { return; } else { - RecursionDepthCheck depthCheck(this, ast->lastSourceLocation()); RegisterScope scope(this); pushExpr(Result(nx)); @@ -420,7 +418,6 @@ void Codegen::condition(ExpressionNode *ast, const BytecodeGenerator::Label *ift if (!ast) return; - RecursionDepthCheck depthCheck(this, ast->lastSourceLocation()); pushExpr(Result(iftrue, iffalse, trueBlockFollowsCondition)); accept(ast); Result r = popExpr(); @@ -3825,8 +3822,14 @@ QQmlRefPointer Codegen::createUnitForLoading() class Codegen::VolatileMemoryLocationScanner: protected QQmlJS::AST::Visitor { VolatileMemoryLocations locs; + Codegen *parent; public: + VolatileMemoryLocationScanner(Codegen *parent) : + QQmlJS::AST::Visitor(parent->recursionDepth()), + parent(parent) + {} + Codegen::VolatileMemoryLocations scan(AST::Node *s) { s->accept(this); @@ -3891,25 +3894,41 @@ public: } } + void throwRecursionDepthError() override + { + parent->throwRecursionDepthError(); + } + private: - void collectIdentifiers(QVector &ids, AST::Node *node) const { + void collectIdentifiers(QVector &ids, AST::Node *node) { class Collector: public QQmlJS::AST::Visitor { + private: QVector &ids; + VolatileMemoryLocationScanner *parent; + public: - Collector(QVector &ids): ids(ids) {} - virtual bool visit(IdentifierExpression *ie) { + Collector(QVector &ids, VolatileMemoryLocationScanner *parent) : + QQmlJS::AST::Visitor(parent->recursionDepth()), ids(ids), parent(parent) + {} + + bool visit(IdentifierExpression *ie) final { ids.append(ie->name); return false; } + + void throwRecursionDepthError() final + { + parent->throwRecursionDepthError(); + } }; - Collector collector(ids); + Collector collector(ids, this); node->accept(&collector); } }; -Codegen::VolatileMemoryLocations Codegen::scanVolatileMemoryLocations(AST::Node *ast) const +Codegen::VolatileMemoryLocations Codegen::scanVolatileMemoryLocations(AST::Node *ast) { - VolatileMemoryLocationScanner scanner; + VolatileMemoryLocationScanner scanner(this); return scanner.scan(ast); } diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index c1063bc0d0..a6355bf93a 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -571,7 +571,6 @@ protected: if (!ast || hasError) return Reference(); - RecursionDepthCheck depthCheck(this, ast->lastSourceLocation()); pushExpr(); ast->accept(this); return popResult(); @@ -705,6 +704,11 @@ protected: bool throwSyntaxErrorOnEvalOrArgumentsInStrictMode(const Reference &r, const AST::SourceLocation &loc); virtual void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail); virtual void throwReferenceError(const AST::SourceLocation &loc, const QString &detail); + void throwRecursionDepthError() override + { + throwSyntaxError(AST::SourceLocation(), + QStringLiteral("Maximum statement or expression depth exceeded")); + } public: QList errors() const; @@ -831,33 +835,8 @@ protected: bool _onoff; }; - class RecursionDepthCheck { - public: - RecursionDepthCheck(Codegen *cg, const AST::SourceLocation &loc) - : _cg(cg) - { -#ifdef QT_NO_DEBUG - const int depthLimit = 4000; // limit to ~1000 deep -#else - const int depthLimit = 1000; // limit to ~250 deep -#endif // QT_NO_DEBUG - - ++_cg->_recursionDepth; - if (_cg->_recursionDepth > depthLimit) - _cg->throwSyntaxError(loc, QStringLiteral("Maximum statement or expression depth exceeded")); - } - - ~RecursionDepthCheck() - { --_cg->_recursionDepth; } - - private: - Codegen *_cg; - }; - int _recursionDepth = 0; - friend class RecursionDepthCheck; - private: - VolatileMemoryLocations scanVolatileMemoryLocations(AST::Node *ast) const; + VolatileMemoryLocations scanVolatileMemoryLocations(AST::Node *ast); void handleConstruct(const Reference &base, AST::ArgumentList *args); }; diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp index e0eaa8867b..04593f202a 100644 --- a/src/qml/compiler/qv4compilerscanfunctions.cpp +++ b/src/qml/compiler/qv4compilerscanfunctions.cpp @@ -57,7 +57,8 @@ using namespace QV4::Compiler; using namespace QQmlJS::AST; ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, ContextType defaultProgramType) - : _cg(cg) + : QQmlJS::AST::Visitor(cg->recursionDepth()) + , _cg(cg) , _sourceCode(sourceCode) , _context(nullptr) , _allowFuncDecls(true) @@ -96,25 +97,6 @@ void ScanFunctions::leaveEnvironment() _context = _contextStack.isEmpty() ? nullptr : _contextStack.top(); } -bool ScanFunctions::preVisit(Node *ast) -{ - if (_cg->hasError) - return false; - ++_recursionDepth; - - if (_recursionDepth > 1000) { - _cg->throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Maximum statement or expression depth exceeded")); - return false; - } - - return true; -} - -void ScanFunctions::postVisit(Node *) -{ - --_recursionDepth; -} - void ScanFunctions::checkDirectivePrologue(StatementList *ast) { for (StatementList *it = ast; it; it = it->next) { @@ -893,3 +875,8 @@ void ScanFunctions::calcEscapingVariables() } } } + +void ScanFunctions::throwRecursionDepthError() +{ + _cg->throwRecursionDepthError(); +} diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h index 28ad846bcd..0f7bf1818a 100644 --- a/src/qml/compiler/qv4compilerscanfunctions_p.h +++ b/src/qml/compiler/qv4compilerscanfunctions_p.h @@ -96,9 +96,6 @@ protected: using Visitor::visit; using Visitor::endVisit; - bool preVisit(AST::Node *ast) override; - void postVisit(AST::Node *) override; - void checkDirectivePrologue(AST::StatementList *ast); void checkName(const QStringRef &name, const AST::SourceLocation &loc); @@ -160,6 +157,8 @@ protected: bool visit(AST::WithStatement *ast) override; void endVisit(AST::WithStatement *ast) override; + void throwRecursionDepthError() override; + protected: bool enterFunction(AST::Node *ast, const QString &name, AST::FormalParameterList *formals, AST::StatementList *body, bool enterName); @@ -173,8 +172,6 @@ protected: bool _allowFuncDecls; ContextType defaultProgramType; - unsigned _recursionDepth = 0; - private: static constexpr AST::Node *astNodeForGlobalEnvironment = nullptr; }; diff --git a/src/qml/jsruntime/qv4runtimecodegen_p.h b/src/qml/jsruntime/qv4runtimecodegen_p.h index be66dc57ca..006a6a3cde 100644 --- a/src/qml/jsruntime/qv4runtimecodegen_p.h +++ b/src/qml/jsruntime/qv4runtimecodegen_p.h @@ -71,6 +71,7 @@ public: void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail) override; void throwReferenceError(const AST::SourceLocation &loc, const QString &detail) override; + private: ExecutionEngine *engine; }; diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index b86dba6daa..8ae51a795f 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -614,16 +614,8 @@ bool Parser::parse(int startToken) program = 0; do { - if (++tos == stack_size) { + if (++tos == stack_size) reallocateStack(); - if (stack_size > 10000) { - // We're now in some serious right-recursive stuff, which will probably result in - // an AST that's so deep that recursively visiting it will run out of stack space. - const QString msg = QCoreApplication::translate("QQmlParser", "Maximum statement or expression depth exceeded"); - diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); - return false; - } - } state_stack[tos] = action; diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index 0978ab523a..e84c62af2f 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -273,9 +273,14 @@ public: inline void accept(Visitor *visitor) { - if (visitor->preVisit(this)) - accept0(visitor); - visitor->postVisit(this); + Visitor::RecursionDepthCheck recursionCheck(visitor); + if (recursionCheck()) { + if (visitor->preVisit(this)) + accept0(visitor); + visitor->postVisit(this); + } else { + visitor->throwRecursionDepthError(); + } } inline static void accept(Node *node, Visitor *visitor) diff --git a/src/qml/parser/qqmljsastvisitor.cpp b/src/qml/parser/qqmljsastvisitor.cpp index eec151298e..666623eecc 100644 --- a/src/qml/parser/qqmljsastvisitor.cpp +++ b/src/qml/parser/qqmljsastvisitor.cpp @@ -43,7 +43,7 @@ QT_QML_BEGIN_NAMESPACE namespace QQmlJS { namespace AST { -Visitor::Visitor() +Visitor::Visitor(quint16 parentRecursionDepth) : m_recursionDepth(parentRecursionDepth) { } diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h index c925096de6..9c69f88e0c 100644 --- a/src/qml/parser/qqmljsastvisitor_p.h +++ b/src/qml/parser/qqmljsastvisitor_p.h @@ -61,7 +61,33 @@ namespace QQmlJS { namespace AST { class QML_PARSER_EXPORT Visitor { public: - Visitor(); + class RecursionDepthCheck + { + Q_DISABLE_COPY(RecursionDepthCheck) + public: + RecursionDepthCheck(RecursionDepthCheck &&) = delete; + RecursionDepthCheck &operator=(RecursionDepthCheck &&) = delete; + + RecursionDepthCheck(Visitor *visitor) : m_visitor(visitor) + { + ++(m_visitor->m_recursionDepth); + } + + ~RecursionDepthCheck() + { + --(m_visitor->m_recursionDepth); + } + + bool operator()() const { + return m_visitor->m_recursionDepth < s_recursionLimit; + } + + private: + static const quint16 s_recursionLimit = 4096; + Visitor *m_visitor; + }; + + Visitor(quint16 parentRecursionDepth = 0); virtual ~Visitor(); virtual bool preVisit(Node *) { return true; } @@ -374,6 +400,14 @@ public: virtual bool visit(DebuggerStatement *) { return true; } virtual void endVisit(DebuggerStatement *) {} + + virtual void throwRecursionDepthError() = 0; + + quint16 recursionDepth() const { return m_recursionDepth; } + +protected: + quint16 m_recursionDepth = 0; + friend class RecursionDepthCheck; }; } } // namespace AST diff --git a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp index c2c73935c0..71dd900073 100644 --- a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp +++ b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp @@ -105,6 +105,11 @@ public: { nodeStack.removeLast(); } + + void throwRecursionDepthError() final + { + QFAIL("Maximum statement or expression depth exceeded"); + } }; } -- cgit v1.2.3 From 9921180a44d9097b1b83c2fa7b3f36dbb555140c Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 15 Mar 2019 13:11:35 +0100 Subject: Try to fix tst_qquickrectangle::gradient_separate() Use QTRY_VERIFY in order to allow for a delay in rendering the rectangle. Fixes: QTBUG-74468 Change-Id: I797b269358aaa35487144bb03a85f36646e2302f Reviewed-by: Simon Hausmann --- tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp b/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp index f6ca999cf5..b34612ee88 100644 --- a/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp +++ b/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp @@ -134,14 +134,12 @@ void tst_qquickrectangle::gradient_separate() // Start off clean QQuickItemPrivate *rectPriv = QQuickItemPrivate::get(rect); - bool isDirty = rectPriv->dirtyAttributes & QQuickItemPrivate::Content; - QVERIFY(!isDirty); + QTRY_COMPARE(rectPriv->dirtyAttributes & QQuickItemPrivate::Content, 0); QMetaObject::invokeMethod(rect, "changeGradient"); // Changing the gradient should have scheduled an update of the item. - isDirty = rectPriv->dirtyAttributes & QQuickItemPrivate::Content; - QVERIFY(isDirty); + QVERIFY((rectPriv->dirtyAttributes & QQuickItemPrivate::Content) != 0); } // When a gradient is changed, every Rectangle connected to it must update. -- cgit v1.2.3 From a79d1038a14db01037d80b9701a530c3654c7adc Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 21 Dec 2018 11:26:45 +0100 Subject: Make object property lookup resolution virtual This allows sub-classes of Object to have their own lookup resolution and verification logic, instead of squeezing it all into qv4lookup.cpp. The typical fallbacks are still in qv4lookup.cpp though. Task-number: QTBUG-69898 Change-Id: I32a8884982b37e2065090666a7bf05b198f5b7fd Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4lookup.cpp | 76 +------------------------------------- src/qml/jsruntime/qv4object.cpp | 82 +++++++++++++++++++++++++++++++++++++++++ src/qml/jsruntime/qv4object_p.h | 7 ++++ src/qml/jsruntime/qv4vtable_p.h | 14 +++++++ 4 files changed, 105 insertions(+), 74 deletions(-) diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 994daa864b..790a5843c2 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -69,37 +69,7 @@ void Lookup::resolveProtoGetter(PropertyKey name, const Heap::Object *proto) ReturnedValue Lookup::resolveGetter(ExecutionEngine *engine, const Object *object) { - Heap::Object *obj = object->d(); - PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - if (name.isArrayIndex()) { - indexedLookup.index = name.asArrayIndex(); - getter = getterIndexed; - return getter(this, engine, *object); - } - - auto index = obj->internalClass->findValueOrGetter(name); - if (index.isValid()) { - PropertyAttributes attrs = index.attrs; - uint nInline = obj->vtable()->nInlineProperties; - if (attrs.isData()) { - if (index.index < obj->vtable()->nInlineProperties) { - index.index += obj->vtable()->inlinePropertyOffset; - getter = getter0Inline; - } else { - index.index -= nInline; - getter = getter0MemberData; - } - } else { - getter = getterAccessor; - } - objectLookup.ic = obj->internalClass; - objectLookup.offset = index.index; - return getter(this, engine, *object); - } - - protoLookup.protoId = obj->internalClass->protoId; - resolveProtoGetter(name, obj->prototype()); - return getter(this, engine, *object); + return object->resolveLookupGetter(engine, this); } ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Value &object) @@ -473,49 +443,7 @@ ReturnedValue Lookup::globalGetterProtoAccessor(Lookup *l, ExecutionEngine *engi bool Lookup::resolveSetter(ExecutionEngine *engine, Object *object, const Value &value) { - Scope scope(engine); - ScopedString name(scope, scope.engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - - Heap::InternalClass *c = object->internalClass(); - PropertyKey key = name->toPropertyKey(); - auto idx = c->findValueOrSetter(key); - if (idx.isValid()) { - if (object->isArrayObject() && idx.index == Heap::ArrayObject::LengthPropertyIndex) { - Q_ASSERT(!idx.attrs.isAccessor()); - setter = arrayLengthSetter; - return setter(this, engine, *object, value); - } else if (idx.attrs.isData() && idx.attrs.isWritable()) { - objectLookup.ic = object->internalClass(); - objectLookup.offset = idx.index; - setter = idx.index < object->d()->vtable()->nInlineProperties ? Lookup::setter0Inline : Lookup::setter0; - return setter(this, engine, *object, value); - } else { - // ### handle setter - setter = setterFallback; - } - return setter(this, engine, *object, value); - } - - insertionLookup.protoId = c->protoId; - if (!object->put(key, value)) { - setter = Lookup::setterFallback; - return false; - } - - if (object->internalClass() == c) { - // ### setter in the prototype, should handle this - setter = setterFallback; - return true; - } - idx = object->internalClass()->findValueOrSetter(key); - if (!idx.isValid() || idx.attrs.isAccessor()) { // ### can this even happen? - setter = setterFallback; - return false; - } - insertionLookup.newClass = object->internalClass(); - insertionLookup.offset = idx.index; - setter = setterInsert; - return true; + return object->resolveLookupSetter(engine, this, value); } bool Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 9d6cb730a9..7dd0a247d6 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -736,6 +736,88 @@ ReturnedValue Object::virtualInstanceOf(const Object *typeObject, const Value &v return checkedInstanceOf(engine, function, var); } +ReturnedValue Object::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup) +{ + Heap::Object *obj = object->d(); + PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]); + if (name.isArrayIndex()) { + lookup->indexedLookup.index = name.asArrayIndex(); + lookup->getter = Lookup::getterIndexed; + return lookup->getter(lookup, engine, *object); + } + + auto index = obj->internalClass->findValueOrGetter(name); + if (index.isValid()) { + PropertyAttributes attrs = index.attrs; + uint nInline = obj->vtable()->nInlineProperties; + if (attrs.isData()) { + if (index.index < obj->vtable()->nInlineProperties) { + index.index += obj->vtable()->inlinePropertyOffset; + lookup->getter = Lookup::getter0Inline; + } else { + index.index -= nInline; + lookup->getter = Lookup::getter0MemberData; + } + } else { + lookup->getter = Lookup::getterAccessor; + } + lookup->objectLookup.ic = obj->internalClass; + lookup->objectLookup.offset = index.index; + return lookup->getter(lookup, engine, *object); + } + + lookup->protoLookup.protoId = obj->internalClass->protoId; + lookup->resolveProtoGetter(name, obj->prototype()); + return lookup->getter(lookup, engine, *object); +} + +bool Object::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value) +{ + Scope scope(engine); + ScopedString name(scope, scope.engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]); + + Heap::InternalClass *c = object->internalClass(); + PropertyKey key = name->toPropertyKey(); + auto idx = c->findValueOrSetter(key); + if (idx.isValid()) { + if (object->isArrayObject() && idx.index == Heap::ArrayObject::LengthPropertyIndex) { + Q_ASSERT(!idx.attrs.isAccessor()); + lookup->setter = Lookup::arrayLengthSetter; + return lookup->setter(lookup, engine, *object, value); + } else if (idx.attrs.isData() && idx.attrs.isWritable()) { + lookup->objectLookup.ic = object->internalClass(); + lookup->objectLookup.offset = idx.index; + lookup->setter = idx.index < object->d()->vtable()->nInlineProperties ? Lookup::setter0Inline : Lookup::setter0; + return lookup->setter(lookup, engine, *object, value); + } else { + // ### handle setter + lookup->setter = Lookup::setterFallback; + } + return lookup->setter(lookup, engine, *object, value); + } + + lookup->insertionLookup.protoId = c->protoId; + if (!object->put(key, value)) { + lookup->setter = Lookup::setterFallback; + return false; + } + + if (object->internalClass() == c) { + // ### setter in the prototype, should handle this + lookup->setter = Lookup::setterFallback; + return true; + } + idx = object->internalClass()->findValueOrSetter(key); + if (!idx.isValid() || idx.attrs.isAccessor()) { // ### can this even happen? + lookup->setter = Lookup::setterFallback; + return false; + } + lookup->insertionLookup.newClass = object->internalClass(); + lookup->insertionLookup.offset = idx.index; + lookup->setter = Lookup::setterInsert; + return true; +} + ReturnedValue Object::checkedInstanceOf(ExecutionEngine *engine, const FunctionObject *f, const Value &var) { Scope scope(engine); diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 9f24449c91..c3f1cb2c35 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -375,6 +375,11 @@ public: bool setProtoFromNewTarget(const Value *newTarget); + ReturnedValue resolveLookupGetter(ExecutionEngine *engine, Lookup *lookup) const + { return vtable()->resolveLookupGetter(this, engine, lookup); } + ReturnedValue resolveLookupSetter(ExecutionEngine *engine, Lookup *lookup, const Value &value) + { return vtable()->resolveLookupSetter(this, engine, lookup, value); } + protected: static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver,bool *hasProperty); static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver); @@ -389,6 +394,8 @@ protected: static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target); static qint64 virtualGetLength(const Managed *m); static ReturnedValue virtualInstanceOf(const Object *typeObject, const Value &var); + static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup); + static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value); public: // qv4runtime uses this directly static ReturnedValue checkedInstanceOf(ExecutionEngine *engine, const FunctionObject *typeObject, const Value &var); diff --git a/src/qml/jsruntime/qv4vtable_p.h b/src/qml/jsruntime/qv4vtable_p.h index 4acefecdf5..aff1ae82d7 100644 --- a/src/qml/jsruntime/qv4vtable_p.h +++ b/src/qml/jsruntime/qv4vtable_p.h @@ -56,6 +56,8 @@ QT_BEGIN_NAMESPACE namespace QV4 { +struct Lookup; + struct OwnPropertyKeyIterator { virtual ~OwnPropertyKeyIterator() = 0; virtual PropertyKey next(const Object *o, Property *p = nullptr, PropertyAttributes *attrs = nullptr) = 0; @@ -84,6 +86,9 @@ struct VTable typedef ReturnedValue (*Call)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); typedef ReturnedValue (*CallAsConstructor)(const FunctionObject *, const Value *argv, int argc, const Value *newTarget); + typedef ReturnedValue (*ResolveLookupGetter)(const Object *, ExecutionEngine *, Lookup *); + typedef bool (*ResolveLookupSetter)(Object *, ExecutionEngine *, Lookup *, const Value &); + const VTable * const parent; quint32 inlinePropertyOffset : 16; quint32 nInlineProperties : 16; @@ -118,6 +123,9 @@ struct VTable Call call; CallAsConstructor callAsConstructor; + + ResolveLookupGetter resolveLookupGetter; + ResolveLookupSetter resolveLookupSetter; }; @@ -142,6 +150,9 @@ protected: static constexpr VTable::Call virtualCall = nullptr; static constexpr VTable::CallAsConstructor virtualCallAsConstructor = nullptr; + + static constexpr VTable::ResolveLookupGetter virtualResolveLookupGetter = nullptr; + static constexpr VTable::ResolveLookupSetter virtualResolveLookupSetter = nullptr; }; #define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \ @@ -181,6 +192,9 @@ protected: \ classname::virtualCall, \ classname::virtualCallAsConstructor, \ + \ + classname::virtualResolveLookupGetter, \ + classname::virtualResolveLookupSetter \ } #define DEFINE_MANAGED_VTABLE(classname) \ -- cgit v1.2.3 From 8a69735c4914d02be9448b6ae98e4c550e1f187a Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Sat, 22 Dec 2018 09:09:57 +0100 Subject: Fix type error exception messages when using member lookups Our tests expect those exceptions to have the same message as when not using lookups. Task-number: QTBUG-69898 Change-Id: Iab36519844a3a49ef9e34346e9afeb2eee9f9ced Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4vme_moth.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 937a535b83..000e1ab9d5 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -594,7 +594,17 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(GetLookup) STORE_IP(); STORE_ACC(); + QV4::Lookup *l = function->compilationUnit->runtimeLookups + index; + + if (accumulator.isNullOrUndefined()) { + QString message = QStringLiteral("Cannot read property '%1' of %2") + .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString()) + .arg(accumulator.toQStringNoThrow()); + acc = engine->throwTypeError(message); + goto handleUnwind; + } + acc = l->getter(l, engine, accumulator); CHECK_EXCEPTION; MOTH_END_INSTR(GetLookup) @@ -723,11 +733,23 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(CallPropertyLookup) STORE_IP(); Lookup *l = function->compilationUnit->runtimeLookups + lookupIndex; + + if (stack[base].isNullOrUndefined()) { + QString message = QStringLiteral("Cannot call method '%1' of %2") + .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString()) + .arg(stack[base].toQStringNoThrow()); + acc = engine->throwTypeError(message); + goto handleUnwind; + } + // ok to have the value on the stack here Value f = Value::fromReturnedValue(l->getter(l, engine, stack[base])); if (Q_UNLIKELY(!f.isFunctionObject())) { - acc = engine->throwTypeError(); + QString message = QStringLiteral("Property '%1' of object %2 is not a function") + .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString()) + .arg(stack[base].toQStringNoThrow()); + acc = engine->throwTypeError(message); goto handleUnwind; } -- cgit v1.2.3 From 24ec7b6c8352600230c40b61be4bfce07076c9a5 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Sat, 22 Dec 2018 09:41:10 +0100 Subject: Fix up global name determination when compiling ahead of time The list of names is still suboptimal, but at least it's shared now. Task-number: QTBUG-69898 Change-Id: I16c9839c4a1f097053b28caea894b67757972826 Reviewed-by: Ulf Hermann --- src/qml/compiler/qv4codegen.cpp | 4 ++-- src/qml/compiler/qv4codegen_p.h | 1 + tools/qmlcachegen/qmlcachegen.cpp | 13 ++----------- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 0ca452b93e..66c334d197 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -103,7 +103,7 @@ Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict) pushExpr(); } -const char *globalNames[] = { +const char *Codegen::s_globalNames[] = { "isNaN", "parseFloat", "String", @@ -183,7 +183,7 @@ void Codegen::generateFromProgram(const QString &fileName, // // 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) + for (const char **g = s_globalNames; *g != nullptr; ++g) m_globalNames << QString::fromLatin1(*g); } diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index a6355bf93a..0b25d9c53d 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -754,6 +754,7 @@ public: m_globalNames = globalNames; } + static const char *s_globalNames[]; protected: friend class ScanFunctions; diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp index 1805dde5d2..1bfc831dac 100644 --- a/tools/qmlcachegen/qmlcachegen.cpp +++ b/tools/qmlcachegen/qmlcachegen.cpp @@ -51,17 +51,8 @@ QSet illegalNames; void setupIllegalNames() { - // #### this in incomplete - illegalNames.insert(QStringLiteral("Math")); - illegalNames.insert(QStringLiteral("Array")); - illegalNames.insert(QStringLiteral("String")); - illegalNames.insert(QStringLiteral("Function")); - illegalNames.insert(QStringLiteral("Boolean")); - illegalNames.insert(QStringLiteral("Number")); - illegalNames.insert(QStringLiteral("Date")); - illegalNames.insert(QStringLiteral("RegExp")); - illegalNames.insert(QStringLiteral("Error")); - illegalNames.insert(QStringLiteral("Object")); + for (const char **g = QV4::Compiler::Codegen::s_globalNames; *g != nullptr; ++g) + illegalNames.insert(QString::fromLatin1(*g)); } struct Error -- cgit v1.2.3 From 5f24122c780b462d7091abc12c9861d1e9713dca Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Sat, 22 Dec 2018 10:56:52 +0100 Subject: Fix lookups the transition between primitive strings and string objects Suppose we have function foo(x) { return x.constructor; } and we call it first with foo("hello") then the lookup will be initialized with a primitive getter from the prototype. When we subsequently call foo(new String("world")) then the primitiveGetterProto() will check that the provided object is of the same type as last time, which erroneously succeeds. Indeed, both are of Managed type. However now we're passing a full-fledged object, which is not a primitive anymore - hence the additional check to ensure that we fall back to the generic getter. Task-number: QTBUG-69898 Change-Id: I3c7a8384bfdf0e31b7c6247cce80fe7448b627b3 Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4lookup.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 790a5843c2..54bce7d7b3 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -379,7 +379,7 @@ ReturnedValue Lookup::getterIndexed(Lookup *l, ExecutionEngine *engine, const Va ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.type() == l->primitiveLookup.type) { + if (object.type() == l->primitiveLookup.type && !object.isObject()) { Heap::Object *o = l->primitiveLookup.proto; if (l->primitiveLookup.protoId == o->internalClass->protoId) return l->primitiveLookup.data->asReturnedValue(); @@ -390,7 +390,7 @@ ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, c ReturnedValue Lookup::primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.type() == l->primitiveLookup.type) { + if (object.type() == l->primitiveLookup.type && !object.isObject()) { Heap::Object *o = l->primitiveLookup.proto; if (l->primitiveLookup.protoId == o->internalClass->protoId) { const Value *getter = l->primitiveLookup.data; -- cgit v1.2.3 From dc3e3090d21339d78abc706369117b3396c843af Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 15 Mar 2019 09:39:58 +0100 Subject: Fix qdoc errors Add ',' to enumerator and rearrange Q_QDOC #ifdefs, fixing: LOG Build & visit PCH for QtQuickDoc src/quick/scenegraph/coreapi/qsgnode.h:97:49: error: missing ',' between enumerators src/qml/qml/qqml.h:593:17: error: expected namespace name Change-Id: I4491c5885c5cdb8a156d9a7abcca5db4d68d1c2e Reviewed-by: Ulf Hermann Reviewed-by: Paul Wicking --- src/qml/qml/qqml.h | 3 ++- src/quick/scenegraph/coreapi/qsgnode.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 05a9f70247..bf9330856d 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -584,7 +584,6 @@ namespace QtQml { const QMetaObject *, bool create); #ifndef Q_QDOC } -#endif QT_WARNING_PUSH QT_WARNING_DISABLE_CLANG("-Wheader-hygiene") @@ -594,6 +593,8 @@ using namespace QtQml; QT_WARNING_POP +#endif // Q_QDOC + //The C++ version of protected namespaces in qmldir Q_QML_EXPORT bool qmlProtectModule(const char* uri, int majVersion); Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor); diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h index 854e284c9e..cb677de030 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.h +++ b/src/quick/scenegraph/coreapi/qsgnode.h @@ -96,7 +96,7 @@ public: // Uppermost 8 bits are reserved for internal use. IsVisitableNode = 0x01000000 #ifdef Q_CLANG_QDOC - InternalReserved = 0x01000000 + , InternalReserved = 0x01000000 #endif }; Q_DECLARE_FLAGS(Flags, Flag) -- cgit v1.2.3 From f396cc753da75c68c6a501379a18df3099697f42 Mon Sep 17 00:00:00 2001 From: Kirill Burtsev Date: Thu, 14 Mar 2019 18:41:03 +0100 Subject: Fix leaking propertyCache inside QQmlAdaptorModel::Accessors QQmlRefPointer works in AddRef mode for assignment of a raw pointer. This creates additional reference to original object and it will never be garbage collected in this case. Amends change 99e2356a73. Task-number: QTBUG-74148 Change-Id: Ic0f03e842965c5c82b357d10ab8b0d6a62411fc8 Reviewed-by: Simon Hausmann --- src/qml/util/qqmladaptormodel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp index d9cb6506b8..a9a38c5381 100644 --- a/src/qml/util/qqmladaptormodel.cpp +++ b/src/qml/util/qqmladaptormodel.cpp @@ -525,7 +525,7 @@ public: metaObject.reset(builder.toMetaObject()); *static_cast(this) = *metaObject; - propertyCache = new QQmlPropertyCache(metaObject.data(), model.modelItemRevision); + propertyCache.adopt(new QQmlPropertyCache(metaObject.data(), model.modelItemRevision)); } }; @@ -659,8 +659,8 @@ public: { VDMListDelegateDataType *dataType = const_cast(this); if (!propertyCache) { - dataType->propertyCache = new QQmlPropertyCache( - &QQmlDMListAccessorData::staticMetaObject, model.modelItemRevision); + dataType->propertyCache.adopt(new QQmlPropertyCache( + &QQmlDMListAccessorData::staticMetaObject, model.modelItemRevision)); } return new QQmlDMListAccessorData( -- cgit v1.2.3 From df2d75b6aa13d770e891910ffcef21968db423a4 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 18 Mar 2019 10:51:48 +0100 Subject: Fix compilation for SLES 12 Apparently only some compilers see through QPointer on connect() Fixes: QTBUG-74500 Change-Id: I4d0ca7c8ab8b7eae281deff14523a1628e669279 Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp index 6e831eacc1..a5332c8860 100644 --- a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp +++ b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp @@ -349,7 +349,7 @@ void tst_qqmlnotifier::deleteFromHandler() QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("objectRenamer.qml")); QPointer mess = component.create(); - QObject::connect(mess, &QObject::objectNameChanged, [&]() { delete mess; }); + QObject::connect(mess.data(), &QObject::objectNameChanged, [&]() { delete mess; }); QTRY_VERIFY(mess.isNull()); // BANG! } else { QProcess process; -- cgit v1.2.3 From 40e149f5fa67967e890b8f9d09cbb00cb2f62259 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 18 Mar 2019 11:43:24 +0100 Subject: Export all private Input Handlers and related classes This was the intention already in 5.12, but we left it with Q_AUTOTEST_EXPORT until now. Users should be able to begin experiments with subclassing handlers, since that is intended to be officially supported in 5.14 with public headers. Change-Id: I89471b3ef748936059ed4444eac5348d26a3344b Reviewed-by: Shawn Rutledge --- src/quick/handlers/qquickdragaxis_p.h | 7 +++---- src/quick/handlers/qquickdraghandler_p.h | 2 +- src/quick/handlers/qquickhoverhandler_p.h | 2 +- src/quick/handlers/qquickmultipointhandler_p.h | 2 +- src/quick/handlers/qquickpinchhandler_p.h | 2 +- src/quick/handlers/qquickpointerdevicehandler_p.h | 2 +- src/quick/handlers/qquickpointerdevicehandler_p_p.h | 2 +- src/quick/handlers/qquickpointhandler_p.h | 2 +- src/quick/handlers/qquicktaphandler_p.h | 2 +- 9 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/quick/handlers/qquickdragaxis_p.h b/src/quick/handlers/qquickdragaxis_p.h index 2c2e0a426d..16496feee3 100644 --- a/src/quick/handlers/qquickdragaxis_p.h +++ b/src/quick/handlers/qquickdragaxis_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQuick module of the Qt Toolkit. @@ -51,10 +51,9 @@ // We mean it. // -#include -#include +#include -class Q_AUTOTEST_EXPORT QQuickDragAxis : public QObject +class Q_QUICK_PRIVATE_EXPORT QQuickDragAxis : public QObject { Q_OBJECT Q_PROPERTY(qreal minimum READ minimum WRITE setMinimum NOTIFY minimumChanged) diff --git a/src/quick/handlers/qquickdraghandler_p.h b/src/quick/handlers/qquickdraghandler_p.h index 387a81eb43..748026488a 100644 --- a/src/quick/handlers/qquickdraghandler_p.h +++ b/src/quick/handlers/qquickdraghandler_p.h @@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE -class Q_AUTOTEST_EXPORT QQuickDragHandler : public QQuickMultiPointHandler +class Q_QUICK_PRIVATE_EXPORT QQuickDragHandler : public QQuickMultiPointHandler { Q_OBJECT Q_PROPERTY(QQuickDragAxis * xAxis READ xAxis CONSTANT) diff --git a/src/quick/handlers/qquickhoverhandler_p.h b/src/quick/handlers/qquickhoverhandler_p.h index 1ee2aeb7e6..d8e5fc00a1 100644 --- a/src/quick/handlers/qquickhoverhandler_p.h +++ b/src/quick/handlers/qquickhoverhandler_p.h @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE -class Q_AUTOTEST_EXPORT QQuickHoverHandler : public QQuickSinglePointHandler +class Q_QUICK_PRIVATE_EXPORT QQuickHoverHandler : public QQuickSinglePointHandler { Q_OBJECT Q_PROPERTY(bool hovered READ isHovered NOTIFY hoveredChanged) diff --git a/src/quick/handlers/qquickmultipointhandler_p.h b/src/quick/handlers/qquickmultipointhandler_p.h index 94142013cc..06f170154b 100644 --- a/src/quick/handlers/qquickmultipointhandler_p.h +++ b/src/quick/handlers/qquickmultipointhandler_p.h @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE -class Q_AUTOTEST_EXPORT QQuickMultiPointHandler : public QQuickPointerDeviceHandler +class Q_QUICK_PRIVATE_EXPORT QQuickMultiPointHandler : public QQuickPointerDeviceHandler { Q_OBJECT Q_PROPERTY(int minimumPointCount READ minimumPointCount WRITE setMinimumPointCount NOTIFY minimumPointCountChanged) diff --git a/src/quick/handlers/qquickpinchhandler_p.h b/src/quick/handlers/qquickpinchhandler_p.h index 1afc028758..766d57f892 100644 --- a/src/quick/handlers/qquickpinchhandler_p.h +++ b/src/quick/handlers/qquickpinchhandler_p.h @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE -class Q_AUTOTEST_EXPORT QQuickPinchHandler : public QQuickMultiPointHandler +class Q_QUICK_PRIVATE_EXPORT QQuickPinchHandler : public QQuickMultiPointHandler { Q_OBJECT Q_PROPERTY(qreal minimumScale READ minimumScale WRITE setMinimumScale NOTIFY minimumScaleChanged) diff --git a/src/quick/handlers/qquickpointerdevicehandler_p.h b/src/quick/handlers/qquickpointerdevicehandler_p.h index 82b24369d3..bb15142824 100644 --- a/src/quick/handlers/qquickpointerdevicehandler_p.h +++ b/src/quick/handlers/qquickpointerdevicehandler_p.h @@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE class QQuickPointerDeviceHandlerPrivate; -class Q_AUTOTEST_EXPORT QQuickPointerDeviceHandler : public QQuickPointerHandler +class Q_QUICK_PRIVATE_EXPORT QQuickPointerDeviceHandler : public QQuickPointerHandler { Q_OBJECT Q_PROPERTY(QQuickPointerDevice::DeviceTypes acceptedDevices READ acceptedDevices WRITE setAcceptedDevices NOTIFY acceptedDevicesChanged) diff --git a/src/quick/handlers/qquickpointerdevicehandler_p_p.h b/src/quick/handlers/qquickpointerdevicehandler_p_p.h index 6a950590f3..03272d9f69 100644 --- a/src/quick/handlers/qquickpointerdevicehandler_p_p.h +++ b/src/quick/handlers/qquickpointerdevicehandler_p_p.h @@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE -class Q_AUTOTEST_EXPORT QQuickPointerDeviceHandlerPrivate : public QQuickPointerHandlerPrivate +class Q_QUICK_PRIVATE_EXPORT QQuickPointerDeviceHandlerPrivate : public QQuickPointerHandlerPrivate { Q_DECLARE_PUBLIC(QQuickPointerDeviceHandler) diff --git a/src/quick/handlers/qquickpointhandler_p.h b/src/quick/handlers/qquickpointhandler_p.h index 380ce1f90f..c197cb4f20 100644 --- a/src/quick/handlers/qquickpointhandler_p.h +++ b/src/quick/handlers/qquickpointhandler_p.h @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE -class Q_AUTOTEST_EXPORT QQuickPointHandler : public QQuickSinglePointHandler +class Q_QUICK_PRIVATE_EXPORT QQuickPointHandler : public QQuickSinglePointHandler { Q_OBJECT Q_PROPERTY(QVector2D translation READ translation NOTIFY translationChanged) diff --git a/src/quick/handlers/qquicktaphandler_p.h b/src/quick/handlers/qquicktaphandler_p.h index 6ec5d55227..56e08590b2 100644 --- a/src/quick/handlers/qquicktaphandler_p.h +++ b/src/quick/handlers/qquicktaphandler_p.h @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE -class Q_AUTOTEST_EXPORT QQuickTapHandler : public QQuickSinglePointHandler +class Q_QUICK_PRIVATE_EXPORT QQuickTapHandler : public QQuickSinglePointHandler { Q_OBJECT Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged) -- cgit v1.2.3 From f4649ebfe5be81c24a384c0806fd015e756a4dca Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 25 Feb 2019 16:01:03 +0100 Subject: Update JavaScript documentation Update function list and refer to the 7th edition of the ECMAScript standard. Fixes: QTBUG-73837 Change-Id: I4332de3ded0373393107b6d5bab95363a0b9ebb9 Reviewed-by: Simon Hausmann --- src/qml/doc/src/javascript/functionlist.qdoc | 61 +++++++++++++++++++++++++ src/qml/doc/src/javascript/hostenvironment.qdoc | 5 +- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/qml/doc/src/javascript/functionlist.qdoc b/src/qml/doc/src/javascript/functionlist.qdoc index 24ff640284..7a6a922480 100644 --- a/src/qml/doc/src/javascript/functionlist.qdoc +++ b/src/qml/doc/src/javascript/functionlist.qdoc @@ -55,6 +55,8 @@ \li decodeURIComponent(encodedURIComponent) \li encodeURI(uri) \li encodeURIComponent(uriComponent) + \li escape(string) + \li unescape(string) \endlist \section2 Constructor Properties @@ -63,11 +65,20 @@ \li Object \li Function \li Array + \li ArrayBuffer \li String \li Boolean \li Number + \li DataView \li Date + \li Promise \li RegExp + \li Map + \li WeakMap + \li Set + \li WeakSet + \li SharedArrayBuffer + \li Symbol \li Error \li EvalError \li RangeError @@ -80,8 +91,11 @@ \section2 Other Properties \list + \li Atomics \li Math \li JSON + \li Reflect + \li Proxy \endlist \section1 The Object Object @@ -92,12 +106,19 @@ \list \li getPrototypeOf(O) + \li setPrototypeOf(O, P) \li getOwnPropertyDescriptor(O, P) + \li getOwnPropertyDescriptors(O) \li getOwnPropertyNames(O) + \li getOwnPropertySymbols(O) + \li assign(O [, Properties]) \li create(O [, Properties]) \li defineProperty(O, P, Attributes) \li defineProperties(O, Properties) + \li entries(O) + \li is(V1, V2) \li keys(O) + \li values(O) \li seal(O) \li isSealed(O) \li freeze(O) @@ -117,6 +138,8 @@ \li hasOwnProperty(V) \li isPrototypeOf(V) \li propertyIsEnumerable(V) + \li __defineGetter__(P, F) + \li __defineSetter__(P, F) \endlist \section1 Function Objects @@ -130,6 +153,7 @@ \li apply(thisArg, argArray) \li call(thisArg [, arg1 [, arg2, ...]]) \li bind((thisArg [, arg1 [, arg2, …]]) + \li [Symbol.hasInstance](O) \endlist \section1 Array Objects @@ -142,9 +166,14 @@ \li toString() \li toLocaleString() \li concat([item1 [, item2 [, ...]]]) + \li copyWithin([item1 [, item2 [, ...]]]) + \li entries() + \li fill(item [, index1 [, index2]]) \li join(separator) \li find(callbackfn [, thisArg]) // ECMAScript 6: Added in Qt 5.9 \li findIndex(callbackfn [, thisArg]) // ECMAScript 6: Added in Qt 5.9 + \li includes(item) + \li keys() \li pop() \li push([item1 [, item2 [, ...]]]) \li reverse() @@ -162,6 +191,8 @@ \li filter(callbackfn [, thisArg]) \li reduce(callbackfn [, initialValue]) \li reduceRight(callbackfn [, initialValue]) + \li values() + \li [Symbol.iterator]() \endlist \section1 String Objects @@ -175,6 +206,7 @@ \li valueOf() \li charAt(pos) \li charCodeAt(pos) + \li codePointAt(pos) \li concat([string1 [, string2 [, ...]]]) \li endsWith(searchString [, endPosition ]) // ECMAScript 6: Added in Qt 5.8 \li includes(searchString [, position ]) // ECMAScript 6: Added in 5.8 @@ -182,18 +214,23 @@ \li lastIndexOf(searchString, position) \li localeCompare(that) \li match(regexp) + \li normalize() + \li padEnd(length [, string]) + \li padStart(length [, string]) \li repeat(count) // ECMAScript 6: Added in Qt 5.9 \li replace(searchValue, replaceValue) \li search(regexp) \li slice(start, end) \li split(separator, limit) \li startsWith(searchString [, position ]) // ECMAScript 6: Added in Qt 5.8 + \li substr(start, length) \li substring(start, end) \li toLowerCase() \li toLocaleLowerCase() \li toUpperCase() \li toLocaleUpperCase() \li trim() + \li [Symbol.iterator]() \endlist Additionally, the QML engine adds the following functions to the \l String prototype: @@ -222,6 +259,7 @@ \list \li toString(radix) \li toLocaleString() + \li valueOf() \li toFixed(fractionDigits) \li toExponential(fractionDigits) \li toPrecision(precision) @@ -245,12 +283,16 @@ \li MAX_VALUE \li MIN_VALUE \li EPSILON // ECMAScript 6: Added in Qt 5.8 + \li MAX_SAFE_INTEGER + \li MIN_SAFE_INTEGER \endlist \section3 Function Properties \list \li isFinite(x) // ECMAScript 6: Added in Qt 5.8 + \li isInteger(x) + \li isSafeInteger(x) \li isNaN(x) // ECMAScript 6: Added in Qt 5.8 \endlist @@ -274,14 +316,27 @@ \list \li abs(x) \li acos(x) + \li acosh(x) \li asin(x) + \li asinh(x) \li atan(x) + \li atanh(x) \li atan2(y, x) + \li cbrt(x) \li ceil(x) + \li clz32(x) \li cos(x) + \li cosh(x) \li exp(x) + \li expm1(x) \li floor(x) + \li fround(x) + \li hypot(x, y) + \li imul(x, y) \li log(x) + \li log10(x) + \li log1p(x) + \li log2(x) \li max([value1 [, value2 [, ...]]]) \li min([value1 [, value2 [, ...]]]) \li pow(x, y) @@ -289,8 +344,11 @@ \li round(x) \li sign(x) // ECMAScript 6: Added in Qt 5.8 \li sin(x) + \li sinh(x) \li sqrt(x) \li tan(x) + \li tanh(x) + \li trunc(x) \endlist \section1 Date Objects @@ -338,11 +396,14 @@ \li setUTCDate(date) \li setMonth(month [, date]) \li setUTCMonth(month [, date]) + \li setYear(year) \li setFullYear(year [, month [, date]]) \li setUTCFullYear(year [, month [, date]]) \li toUTCString() + \li toGMTString() \li toISOString() \li toJSON() + \li [Symbol.toPrimitive](hint) \endlist Additionally, the QML engine adds the following functions to the \l Date prototype: diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc index eb40f10065..c22c392b80 100644 --- a/src/qml/doc/src/javascript/hostenvironment.qdoc +++ b/src/qml/doc/src/javascript/hostenvironment.qdoc @@ -40,11 +40,10 @@ not provide a \c window object or \c{DOM API} as commonly found in a browser env Like a browser or server-side JavaScript environment, the QML runtime implements the \l{ECMA-262}{ECMAScript Language Specification} standard. This provides access to all of the built-in types and functions defined by the standard, such as Object, Array, and Math. -The QML runtime implements the 5th edition of the standard, which is the same edition commonly -implemented by browsers. +The QML runtime implements the 7th edition of the standard. The standard ECMAScript built-ins are not explicitly documented in the QML documentation. For more -information on their use, please refer to the ECMA-262 5th edition standard or one of the many online +information on their use, please refer to the ECMA-262 7th edition standard or one of the many online JavaScript reference and tutorial sites, such as the \l{W3Schools JavaScript Reference} (JavaScript Objects Reference section). Many sites focus on JavaScript in the browser, so in some cases you may need to double check the specification to determine whether a given function or object is part of standard ECMAScript or -- cgit v1.2.3 From 0dd884aca1fffcd94fbe55006c94363415aa0965 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 14 Mar 2019 10:42:19 +0100 Subject: Baseline JIT: Save accumulator in toInt32LhsAcc() toInt32LhsAcc convertes both the lhs and the accumulator to int32. If the accumulator is not saved, a GC run during the conversion of the lhs might trash its value. Fixes: QTBUG-74058 Change-Id: Ic42693061c7d483bb430d77bcc095de6ff9a6843 Reviewed-by: Simon Hausmann --- src/qml/jit/qv4baselineassembler.cpp | 32 +++++++++++----------- .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 12 ++++++++ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/qml/jit/qv4baselineassembler.cpp b/src/qml/jit/qv4baselineassembler.cpp index 5c08c42977..b13f646360 100644 --- a/src/qml/jit/qv4baselineassembler.cpp +++ b/src/qml/jit/qv4baselineassembler.cpp @@ -208,17 +208,20 @@ public: isNumber.link(this); } + // this converts both the lhs and the accumulator to int32 void toInt32LhsAcc(Address lhs, RegisterID lhsTarget) { load64(lhs, lhsTarget); urshift64(lhsTarget, TrustedImm32(Value::QuickType_Shift), ScratchRegister2); auto lhsIsInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister2); - pushAligned(AccumulatorRegister); + const Address accumulatorStackAddress(JSStackFrameRegister, + offsetof(CallData, accumulator)); + storeAccumulator(accumulatorStackAddress); move(lhsTarget, registerForArg(0)); callHelper(toInt32Helper); move(ReturnValueRegister, lhsTarget); - popAligned(AccumulatorRegister); + loadAccumulator(accumulatorStackAddress); lhsIsInt.link(this); urshift64(AccumulatorRegister, TrustedImm32(Value::QuickType_Shift), ScratchRegister2); @@ -498,6 +501,7 @@ public: isNumber.link(this); } + // this converts both the lhs and the accumulator to int32 void toInt32LhsAcc(Address lhs, RegisterID lhsTarget) { bool accumulatorNeedsSaving = AccumulatorRegisterValue == ReturnValueRegisterValue @@ -510,32 +514,28 @@ public: auto lhsIsInt = jump(); lhsIsNotInt.link(this); - if (accumulatorNeedsSaving) { - push(AccumulatorRegisterTag); - push(AccumulatorRegisterValue); - } + + // Save accumulator from being garbage collected, no matter if we will reuse the register. + const Address accumulatorStackAddress(JSStackFrameRegister, + offsetof(CallData, accumulator)); + storeAccumulator(accumulatorStackAddress); if (ArgInRegCount < 2) { - if (!accumulatorNeedsSaving) - subPtr(TrustedImm32(2 * PointerSize), StackPointerRegister); + subPtr(TrustedImm32(2 * PointerSize), StackPointerRegister); push(lhsTarget); load32(lhs, lhsTarget); push(lhsTarget); } else { - if (accumulatorNeedsSaving) - subPtr(TrustedImm32(2 * PointerSize), StackPointerRegister); move(lhsTarget, registerForArg(1)); load32(lhs, registerForArg(0)); } callHelper(toInt32Helper); move(ReturnValueRegisterValue, lhsTarget); - if (accumulatorNeedsSaving) { - addPtr(TrustedImm32(2 * PointerSize), StackPointerRegister); - pop(AccumulatorRegisterValue); - pop(AccumulatorRegisterTag); - } else if (ArgInRegCount < 2) { + if (ArgInRegCount < 2) addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister); - } + + if (accumulatorNeedsSaving) // otherwise it's still the same + loadAccumulator(accumulatorStackAddress); lhsIsInt.link(this); diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index a67a503f82..f33f1d9125 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -365,6 +365,7 @@ private slots: void numberToStringWithRadix(); void tailCallWithArguments(); void deleteSparseInIteration(); + void saveAccumulatorBeforeToInt32(); private: // static void propertyVarWeakRefCallback(v8::Persistent object, void* parameter); @@ -8929,6 +8930,17 @@ void tst_qqmlecmascript::deleteSparseInIteration() QCOMPARE(value.property("2").toInt(), 4096); } +void tst_qqmlecmascript::saveAccumulatorBeforeToInt32() +{ + QJSEngine engine; + + // Infinite recursion produces a range error, but should not crash. + // Also, any GC runs in between should not trash the temporary results of "a+a". + const QJSValue value = engine.evaluate("function a(){a(a&a+a)}a()"); + QVERIFY(value.isError()); + QCOMPARE(value.toString(), QLatin1String("RangeError: Maximum call stack size exceeded.")); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" -- cgit v1.2.3 From db292d1fe70a0cfaf315a72d099441cf3969e284 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 21 Dec 2018 16:00:48 +0100 Subject: Enable lookups in QML The main feature that needs to be implemented in order to enable lookups in QML files is to respect that the QObject wrapper has its own storage layer (meta-object properties). Lookups need to be able to index those when the base is a QObject. This is done by caching the property data and guarding the validity by comparing property cache pointers. The same lookup logic is also implemented for value type wrappers. OVerall there's more that can be done with lookups in meta-objects, for constant properties for example. For "global" lookups we have a safeguard in place that generates a LoadName instruction for property access that should end up in the qml context wrapper. So no changes are needed here at first, but the lookup in the QML context can be optimized in the future. The way of storing the property cache in the lookup itself trades ugliness on destruction against the creation of less internal classes. Another option would be to store the property cache in the internal class and let QObjectWrapper always transition via the property cache. Task-number: QTBUG-69898 Change-Id: I9c378c071acc6d7d4a34a2a76616f9594119d515 Reviewed-by: Ulf Hermann --- src/qml/compiler/qqmltypecompiler.cpp | 1 - src/qml/compiler/qv4compileddata.cpp | 15 +++ src/qml/jsruntime/qv4lookup_p.h | 12 +++ src/qml/jsruntime/qv4qobjectwrapper.cpp | 173 +++++++++++++++++++++++++------- src/qml/jsruntime/qv4qobjectwrapper_p.h | 7 +- src/qml/jsruntime/qv4value_p.h | 16 +++ src/qml/qml/qqmlvaluetypewrapper.cpp | 151 +++++++++++++++++++++------- src/qml/qml/qqmlvaluetypewrapper_p.h | 3 + src/qml/types/qqmllistmodel.cpp | 7 ++ src/qml/types/qqmllistmodel_p_p.h | 2 + 10 files changed, 311 insertions(+), 76 deletions(-) diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 75ed8dd10f..f753c78b1a 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -147,7 +147,6 @@ QQmlRefPointer QQmlTypeCompiler::compile() document->jsModule.finalUrl = typeData->finalUrlString(); QmlIR::JSCodeGen v4CodeGenerator(document->code, &document->jsGenerator, &document->jsModule, &document->jsParserEngine, document->program, typeNameCache.data(), &document->jsGenerator.stringTable, engine->v8engine()->illegalNames()); - v4CodeGenerator.setUseFastLookups(false); QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator); if (!jsCodeGen.generateCodeForComponents()) return nullptr; diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 65690ec1f6..e428340f62 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -51,6 +51,8 @@ #include #include #include +#include +#include #include "qv4compilationunitmapper_p.h" #include #include @@ -270,6 +272,19 @@ void CompilationUnit::unlink() propertyCaches.clear(); + if (runtimeLookups) { + for (uint i = 0; i < data->lookupTableSize; ++i) { + QV4::Lookup &l = runtimeLookups[i]; + if (l.getter == QV4::QObjectWrapper::lookupGetter) { + if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache) + pc->release(); + } else if (l.getter == QQmlValueTypeWrapper::lookupGetter) { + if (QQmlPropertyCache *pc = l.qgadgetLookup.propertyCache) + pc->release(); + } + } + } + dependentScripts.clear(); typeNameCache = nullptr; diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 83e561863b..b0d5706dea 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -116,6 +116,18 @@ struct Lookup { quintptr _unused2; uint index; } indexedLookup; + struct { + Heap::InternalClass *ic; + quintptr unused; + QQmlPropertyCache *propertyCache; + QQmlPropertyData *propertyData; + } qobjectLookup; + struct { + Heap::InternalClass *ic; + quintptr unused; + QQmlPropertyCache *propertyCache; + QQmlPropertyData *propertyData; + } qgadgetLookup; }; uint nameIndex; diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 40be6f41c8..711c910906 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -56,6 +56,8 @@ #include #include #include +#include +#include #if QT_CONFIG(qml_sequence_object) #include @@ -269,9 +271,53 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje } } +static OptionalReturnedValue getDestroyOrToStringMethod(ExecutionEngine *v4, String *name, QObject *qobj, bool *hasProperty = nullptr) +{ + int index = 0; + if (name->equals(v4->id_destroy())) + index = QV4::QObjectMethod::DestroyMethod; + else if (name->equals(v4->id_toString())) + index = QV4::QObjectMethod::ToStringMethod; + else + return OptionalReturnedValue(); + + if (hasProperty) + *hasProperty = true; + ExecutionContext *global = v4->rootContext(); + return OptionalReturnedValue(QV4::QObjectMethod::create(global, qobj, index)); +} + +static OptionalReturnedValue getPropertyFromImports(ExecutionEngine *v4, String *name, QQmlContextData *qmlContext, QObject *qobj, + bool *hasProperty = nullptr) +{ + if (!qmlContext || !qmlContext->imports) + return OptionalReturnedValue(); + + QQmlTypeNameCache::Result r = qmlContext->imports->query(name); + + if (hasProperty) + *hasProperty = true; + + if (!r.isValid()) + return OptionalReturnedValue(); + + if (r.scriptIndex != -1) { + return OptionalReturnedValue(QV4::Encode::undefined()); + } else if (r.type.isValid()) { + return OptionalReturnedValue(QQmlTypeWrapper::create(v4, qobj,r.type, Heap::QQmlTypeWrapper::ExcludeEnums)); + } else if (r.importNamespace) { + return OptionalReturnedValue(QQmlTypeWrapper::create(v4, qobj, qmlContext->imports, r.importNamespace, + Heap::QQmlTypeWrapper::ExcludeEnums)); + } + Q_UNREACHABLE(); + return OptionalReturnedValue(); +} + ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty, bool includeImports) const { + // Keep this code in sync with ::virtualResolveLookupGetter + if (QQmlData::wasDeleted(d()->object())) { if (hasProperty) *hasProperty = false; @@ -280,39 +326,17 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String ExecutionEngine *v4 = engine(); - if (name->equals(v4->id_destroy()) || name->equals(v4->id_toString())) { - int index = name->equals(v4->id_destroy()) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod; - if (hasProperty) - *hasProperty = true; - ExecutionContext *global = v4->rootContext(); - return QV4::QObjectMethod::create(global, d()->object(), index); - } + if (auto methodValue = getDestroyOrToStringMethod(v4, name, d()->object(), hasProperty)) + return *methodValue; QQmlPropertyData local; QQmlPropertyData *result = findProperty(v4, qmlContext, name, revisionMode, &local); if (!result) { + // Check for attached properties if (includeImports && name->startsWithUpper()) { - // Check for attached properties - if (qmlContext && qmlContext->imports) { - QQmlTypeNameCache::Result r = qmlContext->imports->query(name); - - if (hasProperty) - *hasProperty = true; - - if (r.isValid()) { - if (r.scriptIndex != -1) { - return QV4::Encode::undefined(); - } else if (r.type.isValid()) { - return QQmlTypeWrapper::create(v4, d()->object(), - r.type, Heap::QQmlTypeWrapper::ExcludeEnums); - } else if (r.importNamespace) { - return QQmlTypeWrapper::create(v4, d()->object(), - qmlContext->imports, r.importNamespace, Heap::QQmlTypeWrapper::ExcludeEnums); - } - Q_ASSERT(!"Unreachable"); - } - } + if (auto importProperty = getPropertyFromImports(v4, name, qmlContext, d()->object(), hasProperty)) + return *importProperty; } return QV4::Object::virtualGet(this, name->propertyKey(), this, hasProperty); } @@ -361,13 +385,8 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC return QV4::Encode::null(); } - if (name->equals(engine->id_destroy()) || name->equals(engine->id_toString())) { - int index = name->equals(engine->id_destroy()) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod; - if (hasProperty) - *hasProperty = true; - ExecutionContext *global = engine->rootContext(); - return QV4::QObjectMethod::create(global, object, index); - } + if (auto methodValue = getDestroyOrToStringMethod(engine, name, object, hasProperty)) + return *methodValue; QQmlData *ddata = QQmlData::get(object, false); QQmlPropertyData local; @@ -829,6 +848,86 @@ OwnPropertyKeyIterator *QObjectWrapper::virtualOwnPropertyKeys(const Object *m, return new QObjectWrapperOwnPropertyKeyIterator; } +ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup) +{ + // Keep this code in sync with ::getQmlProperty + PropertyKey id = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit-> + runtimeStrings[lookup->nameIndex]); + if (!id.isString()) + return Object::virtualResolveLookupGetter(object, engine, lookup); + Scope scope(engine); + + const QObjectWrapper *This = static_cast(object); + ScopedString name(scope, id.asStringOrSymbol()); + QQmlContextData *qmlContext = engine->callingQmlContext(); + + QObject * const qobj = This->d()->object(); + + if (QQmlData::wasDeleted(qobj)) + return QV4::Encode::undefined(); + + if (auto methodValue = getDestroyOrToStringMethod(engine, name, qobj)) + return *methodValue; + + QQmlData *ddata = QQmlData::get(qobj, false); + if (!ddata || !ddata->propertyCache) { + QQmlPropertyData local; + QQmlPropertyData *property = QQmlPropertyCache::property(engine->jsEngine(), qobj, name, qmlContext, local); + return getProperty(engine, qobj, property, /*captureRequired*/true); + } + QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobj, qmlContext); + + if (!property) { + // Check for attached properties + if (name->startsWithUpper()) { + if (auto importProperty = getPropertyFromImports(engine, name, qmlContext, qobj)) + return *importProperty; + } + return QV4::Object::virtualResolveLookupGetter(object, engine, lookup); + } + + lookup->qobjectLookup.ic = This->internalClass(); + lookup->qobjectLookup.propertyCache = ddata->propertyCache; + lookup->qobjectLookup.propertyCache->addref(); + lookup->qobjectLookup.propertyData = property; + lookup->getter = QV4::QObjectWrapper::lookupGetter; + return lookup->getter(lookup, engine, *object); +} + +ReturnedValue QObjectWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object) +{ + const auto revertLookup = [lookup, engine, &object]() { + lookup->qobjectLookup.propertyCache->release(); + lookup->qobjectLookup.propertyCache = nullptr; + lookup->getter = Lookup::getterGeneric; + return Lookup::getterGeneric(lookup, engine, object); + }; + + // we can safely cast to a QV4::Object here. If object is something else, + // the internal class won't match + Heap::Object *o = static_cast(object.heapObject()); + if (!o || o->internalClass != lookup->qobjectLookup.ic) + return revertLookup(); + + const Heap::QObjectWrapper *This = static_cast(o); + QObject *qobj = This->object(); + if (QQmlData::wasDeleted(qobj)) + return QV4::Encode::undefined(); + + QQmlData *ddata = QQmlData::get(qobj, /*create*/false); + if (!ddata || ddata->propertyCache != lookup->qobjectLookup.propertyCache) + return revertLookup(); + + QQmlPropertyData *property = lookup->qobjectLookup.propertyData; + return getProperty(engine, qobj, property, /*captureRequired = */true); +} + +bool QObjectWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, + const Value &value) +{ + return Object::virtualResolveLookupSetter(object, engine, lookup, value); +} + namespace QV4 { struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase @@ -1920,13 +2019,13 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, in return method.asReturnedValue(); } -ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index) +ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index) { Scope valueScope(scope); Scoped method(valueScope, valueScope.engine->memoryManager->allocate(scope)); - method->d()->setPropertyCache(valueType->d()->propertyCache()); + method->d()->setPropertyCache(valueType->propertyCache()); method->d()->index = index; - method->d()->valueTypeWrapper.set(valueScope.engine, valueType->d()); + method->d()->valueTypeWrapper.set(valueScope.engine, valueType); return method.asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 6465ee0fa6..a09e7b6e95 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -183,6 +183,11 @@ struct Q_QML_EXPORT QObjectWrapper : public Object void destroyObject(bool lastCall); static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired = true); + + static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup); + static ReturnedValue lookupGetter(Lookup *l, ExecutionEngine *engine, const Value &object); + static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value); + protected: static void setProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, const Value &value); @@ -228,7 +233,7 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject enum { DestroyMethod = -1, ToStringMethod = -2 }; static ReturnedValue create(QV4::ExecutionContext *scope, QObject *object, int index); - static ReturnedValue create(QV4::ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index); + static ReturnedValue create(QV4::ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index); int methodIndex() const { return d()->index; } QObject *object() const { return d()->object(); } diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 20a84beccd..b4a045edfb 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -863,6 +863,22 @@ struct ValueArray { // have wrong offsets between host and target. Q_STATIC_ASSERT(offsetof(ValueArray<0>, values) == 8); +class OptionalReturnedValue { + ReturnedValue value; +public: + + OptionalReturnedValue() : value(Value::emptyValue().asReturnedValue()) {} + explicit OptionalReturnedValue(ReturnedValue v) + : value(v) + { + Q_ASSERT(!Value::fromReturnedValue(v).isEmpty()); + } + + ReturnedValue operator->() const { return value; } + ReturnedValue operator*() const { return value; } + explicit operator bool() const { return !Value::fromReturnedValue(value).isEmpty(); } +}; + } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index b503d75a47..b22d1530e2 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -51,6 +51,8 @@ #include #include #include +#include +#include #include QT_BEGIN_NAMESPACE @@ -372,6 +374,117 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, con return Encode(b->engine()->newString(result)); } +Q_ALWAYS_INLINE static ReturnedValue getGadgetProperty(ExecutionEngine *engine, + Heap::QQmlValueTypeWrapper *valueTypeWrapper, + QQmlPropertyData *property) +{ + if (property->isFunction()) { + // calling a Q_INVOKABLE function of a value type + return QV4::QObjectMethod::create(engine->rootContext(), valueTypeWrapper, property->coreIndex()); + } + +#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \ + if (property->propType() == metatype) { \ + cpptype v; \ + void *args[] = { &v, nullptr }; \ + metaObject->d.static_metacall(reinterpret_cast(valueTypeWrapper->gadgetPtr), \ + QMetaObject::ReadProperty, index, args); \ + return QV4::Encode(constructor(v)); \ + } + + const QMetaObject *metaObject = valueTypeWrapper->propertyCache()->metaObject(); + + int index = property->coreIndex(); + QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::ReadProperty, &metaObject, &index); + + // These four types are the most common used by the value type wrappers + VALUE_TYPE_LOAD(QMetaType::QReal, qreal, qreal); + VALUE_TYPE_LOAD(QMetaType::Int || property->isEnum(), int, int); + VALUE_TYPE_LOAD(QMetaType::Int, int, int); + VALUE_TYPE_LOAD(QMetaType::QString, QString, engine->newString); + VALUE_TYPE_LOAD(QMetaType::Bool, bool, bool); + + QVariant v; + void *args[] = { nullptr, nullptr }; + if (property->propType() == QMetaType::QVariant) { + args[0] = &v; + } else { + v = QVariant(property->propType(), static_cast(nullptr)); + args[0] = v.data(); + } + metaObject->d.static_metacall(reinterpret_cast(valueTypeWrapper->gadgetPtr), QMetaObject::ReadProperty, + index, args); + return engine->fromVariant(v); +#undef VALUE_TYPE_LOAD +} + +ReturnedValue QQmlValueTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, + Lookup *lookup) +{ + PropertyKey id = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit-> + runtimeStrings[lookup->nameIndex]); + if (!id.isString()) + return Object::virtualResolveLookupGetter(object, engine, lookup); + + const QQmlValueTypeWrapper *r = static_cast(object); + QV4::ExecutionEngine *v4 = r->engine(); + Scope scope(v4); + ScopedString name(scope, id.asStringOrSymbol()); + + // Note: readReferenceValue() can change the reference->type. + if (const QQmlValueTypeReference *reference = r->as()) { + if (!reference->readReferenceValue()) + return Value::undefinedValue().asReturnedValue(); + } + + QQmlPropertyData *result = r->d()->propertyCache()->property(name.getPointer(), nullptr, nullptr); + if (!result) + return QV4::Object::virtualResolveLookupGetter(object, engine, lookup); + + lookup->qgadgetLookup.ic = r->internalClass(); + lookup->qgadgetLookup.propertyCache = r->d()->propertyCache(); + lookup->qgadgetLookup.propertyCache->addref(); + lookup->qgadgetLookup.propertyData = result; + lookup->getter = QQmlValueTypeWrapper::lookupGetter; + return lookup->getter(lookup, engine, *object); +} + +ReturnedValue QQmlValueTypeWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object) +{ + const auto revertLookup = [lookup, engine, &object]() { + lookup->qgadgetLookup.propertyCache->release(); + lookup->qgadgetLookup.propertyCache = nullptr; + lookup->getter = Lookup::getterGeneric; + return Lookup::getterGeneric(lookup, engine, object); + }; + + // we can safely cast to a QV4::Object here. If object is something else, + // the internal class won't match + Heap::Object *o = static_cast(object.heapObject()); + if (!o || o->internalClass != lookup->qgadgetLookup.ic) + return revertLookup(); + + Heap::QQmlValueTypeWrapper *valueTypeWrapper = + const_cast(static_cast(o)); + if (valueTypeWrapper->propertyCache() != lookup->qgadgetLookup.propertyCache) + return revertLookup(); + + if (lookup->qgadgetLookup.ic->vtable == QQmlValueTypeReference::staticVTable()) { + Scope scope(engine); + Scoped referenceWrapper(scope, valueTypeWrapper); + referenceWrapper->readReferenceValue(); + } + + QQmlPropertyData *property = lookup->qgadgetLookup.propertyData; + return getGadgetProperty(engine, valueTypeWrapper, property); +} + +bool QQmlValueTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, + const Value &value) +{ + return Object::virtualResolveLookupSetter(object, engine, lookup, value); +} + ReturnedValue QQmlValueTypeWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty) { Q_ASSERT(m->as()); @@ -397,43 +510,7 @@ ReturnedValue QQmlValueTypeWrapper::virtualGet(const Managed *m, PropertyKey id, if (hasProperty) *hasProperty = true; - if (result->isFunction()) - // calling a Q_INVOKABLE function of a value type - return QV4::QObjectMethod::create(v4->rootContext(), r, result->coreIndex()); - -#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \ - if (result->propType() == metatype) { \ - cpptype v; \ - void *args[] = { &v, 0 }; \ - metaObject->d.static_metacall(reinterpret_cast(gadget), QMetaObject::ReadProperty, index, args); \ - return QV4::Encode(constructor(v)); \ - } - - const QMetaObject *metaObject = r->d()->propertyCache()->metaObject(); - - int index = result->coreIndex(); - QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::ReadProperty, &metaObject, &index); - - void *gadget = r->d()->gadgetPtr; - - // These four types are the most common used by the value type wrappers - VALUE_TYPE_LOAD(QMetaType::QReal, qreal, qreal); - VALUE_TYPE_LOAD(QMetaType::Int || result->isEnum(), int, int); - VALUE_TYPE_LOAD(QMetaType::Int, int, int); - VALUE_TYPE_LOAD(QMetaType::QString, QString, v4->newString); - VALUE_TYPE_LOAD(QMetaType::Bool, bool, bool); - - QVariant v; - void *args[] = { nullptr, nullptr }; - if (result->propType() == QMetaType::QVariant) { - args[0] = &v; - } else { - v = QVariant(result->propType(), static_cast(nullptr)); - args[0] = v.data(); - } - metaObject->d.static_metacall(reinterpret_cast(gadget), QMetaObject::ReadProperty, index, args); - return v4->fromVariant(v); -#undef VALUE_TYPE_ACCESSOR + return getGadgetProperty(v4, r->d(), result); } bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver) diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h index 8db9474132..baac129afa 100644 --- a/src/qml/qml/qqmlvaluetypewrapper_p.h +++ b/src/qml/qml/qqmlvaluetypewrapper_p.h @@ -112,6 +112,9 @@ public: static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p); static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target); static ReturnedValue method_toString(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup); + static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value); + static ReturnedValue lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object); static void initProto(ExecutionEngine *v4); }; diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index debf14df97..006825cc93 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -1613,6 +1614,12 @@ ReturnedValue ModelObject::virtualGet(const Managed *m, PropertyKey id, const Va return that->engine()->fromVariant(value); } +ReturnedValue ModelObject::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup) +{ + lookup->getter = Lookup::getterFallback; + return lookup->getter(lookup, engine, *object); +} + struct ModelObjectOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator { int roleNameIndex = 0; diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h index ff52ee049f..2876c71de6 100644 --- a/src/qml/types/qqmllistmodel_p_p.h +++ b/src/qml/types/qqmllistmodel_p_p.h @@ -181,6 +181,8 @@ struct ModelObject : public QObjectWrapper protected: static bool virtualPut(Managed *m, PropertyKey id, const Value& value, Value *receiver); static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty); + static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup); + static ReturnedValue lookupGetter(Lookup *l, ExecutionEngine *engine, const Value &object); static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target); }; -- cgit v1.2.3 From 0b7e479235aec74f051af4d5ef95e74753b59c6d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 22 Feb 2019 18:13:34 +0100 Subject: Create import directory from intercepted URL, not orignial one If the qmldir URL got intercepted, we should use the intercepted URL to get to the contents to be loaded. Fixes: QTBUG-73843 Change-Id: I51715575e767ed429a8237517f47196677409fe0 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlimport.cpp | 2 +- tests/auto/qml/qqmlimport/data/interceptQmldir.qml | 7 ++++++ .../auto/qml/qqmlimport/data/intercepted/View.qml | 5 ++++ tests/auto/qml/qqmlimport/data/intercepted/qmldir | 2 ++ tests/auto/qml/qqmlimport/tst_qqmlimport.cpp | 28 ++++++++++++++++++++++ 5 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 tests/auto/qml/qqmlimport/data/interceptQmldir.qml create mode 100644 tests/auto/qml/qqmlimport/data/intercepted/View.qml create mode 100644 tests/auto/qml/qqmlimport/data/intercepted/qmldir diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index e379d416fd..a31dbd1e08 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -1546,7 +1546,7 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix QString localFileOrQrc = QQmlFile::urlToLocalFileOrQrc(qmldirUrl); Q_ASSERT(!localFileOrQrc.isEmpty()); - QString dir = QQmlFile::urlToLocalFileOrQrc(resolveLocalUrl(base, importUri)); + const QString dir = localFileOrQrc.left(localFileOrQrc.lastIndexOf(Slash) + 1); if (!typeLoader->directoryExists(dir)) { if (!isImplicitImport) { QQmlError error; diff --git a/tests/auto/qml/qqmlimport/data/interceptQmldir.qml b/tests/auto/qml/qqmlimport/data/interceptQmldir.qml new file mode 100644 index 0000000000..bf485b2282 --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/interceptQmldir.qml @@ -0,0 +1,7 @@ +import QtQml 2.2 + +import "$(INTERCEPT)" as Intercepted + +QtObject { + property QtObject view: Intercepted.View {} +} diff --git a/tests/auto/qml/qqmlimport/data/intercepted/View.qml b/tests/auto/qml/qqmlimport/data/intercepted/View.qml new file mode 100644 index 0000000000..92aa3af95a --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/intercepted/View.qml @@ -0,0 +1,5 @@ +import QtQml 2.2 + +QtObject { + property int foo: 12 +} diff --git a/tests/auto/qml/qqmlimport/data/intercepted/qmldir b/tests/auto/qml/qqmlimport/data/intercepted/qmldir new file mode 100644 index 0000000000..ab31de73d8 --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/intercepted/qmldir @@ -0,0 +1,2 @@ +module SomeModule +View 1.0 View.qml diff --git a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp index 70aaa9678e..a3cb68fdcb 100644 --- a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp +++ b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -43,6 +44,7 @@ private slots: void uiFormatLoading(); void completeQmldirPaths_data(); void completeQmldirPaths(); + void interceptQmldir(); void cleanup(); }; @@ -185,6 +187,32 @@ void tst_QQmlImport::completeQmldirPaths() QCOMPARE(QQmlImports::completeQmldirPaths(uri, basePaths, majorVersion, minorVersion), expectedPaths); } +class QmldirUrlInterceptor : public QQmlAbstractUrlInterceptor { +public: + QUrl intercept(const QUrl &url, DataType type) override + { + if (type != UrlString && !url.isEmpty() && url.isValid()) { + QString str = url.toString(QUrl::None); + return str.replace(QStringLiteral("$(INTERCEPT)"), QStringLiteral("intercepted")); + } + return url; + } +}; + +void tst_QQmlImport::interceptQmldir() +{ + QQmlEngine engine; + QmldirUrlInterceptor interceptor; + engine.setUrlInterceptor(&interceptor); + + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("interceptQmldir.qml")); + QVERIFY(component.isReady()); + QScopedPointer obj(component.create()); + QVERIFY(!obj.isNull()); +} + + QTEST_MAIN(tst_QQmlImport) #include "tst_qqmlimport.moc" -- cgit v1.2.3 From fdd988494aedba9f58b54e958fab91f566186ed1 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 14 Mar 2019 13:44:47 +0100 Subject: Doc: Clarify section about qmlRegisterInterface() There is very little you can do with things registered as interfaces. Change-Id: I5e4dcf8529c2d7c8012db3fa1dcfc23563cc2cba Fixes: QTBUG-74318 Reviewed-by: Simon Hausmann --- src/qml/doc/src/cppintegration/definetypes.qdoc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc index f6f630c749..41bc9fd140 100644 --- a/src/qml/doc/src/cppintegration/definetypes.qdoc +++ b/src/qml/doc/src/cppintegration/definetypes.qdoc @@ -142,9 +142,10 @@ types: \li qmlRegisterType() (with no parameters) registers a C++ type that is not instantiable and cannot be referred to from QML. This enables the engine to coerce any inherited types that are instantiable from QML. -\li qmlRegisterInterface() registers a Qt interface type with a specific QML -type name. The type is not instantiable from QML but can be referred to by its -type name. +\li qmlRegisterInterface() registers an existing Qt interface type. The type is +not instantiable from QML, and you cannot declare QML properties with it. Using +C++ properties of this type from QML will do the expected interface casts, +though. \li qmlRegisterUncreatableType() registers a named C++ type that is not instantiable but should be identifiable as a type to the QML type system. This is useful if a type's enums or attached properties should be accessible from QML -- cgit v1.2.3 From 1134a36efa54c68736d708411423bafa9d0923f6 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 18 Mar 2019 13:22:19 +0100 Subject: Relax tst_QQuickGridView::contentHeightWithDelayRemove Apparently we cannot rely on the content height change to immediately take effect. Change-Id: I8b4bf7b7d0b72da84228c7a3f1460b42c97e0330 Fixes: QTBUG-74518 Reviewed-by: Shawn Rutledge --- tests/auto/quick/qquickgridview/tst_qquickgridview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp index 301ec43cb5..e346e25aaf 100644 --- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp +++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp @@ -6636,7 +6636,7 @@ void tst_QQuickGridView::contentHeightWithDelayRemove() QCOMPARE(qRound(gridview->contentHeight()), qRound(initialContentHeight)); QTRY_COMPARE(qRound(gridview->contentHeight()), eventualContentHeight); } else { - QCOMPARE(qRound(gridview->contentHeight()), eventualContentHeight); + QTRY_COMPARE(qRound(gridview->contentHeight()), eventualContentHeight); } delete window; -- cgit v1.2.3 From 84c3e16d78b62550ee240ccfa9d64c816719a83b Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 18 Mar 2019 13:36:59 +0100 Subject: Blacklist tst_TouchMouse::buttonOnFlickable() on mingw Task-number: QTBUG-74517 Change-Id: I3e0a90a264f8f686bba89e6b8dc4ebcf05418f77 Reviewed-by: Shawn Rutledge --- tests/auto/quick/touchmouse/BLACKLIST | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/auto/quick/touchmouse/BLACKLIST b/tests/auto/quick/touchmouse/BLACKLIST index b2ba52eca9..0dfe28087a 100644 --- a/tests/auto/quick/touchmouse/BLACKLIST +++ b/tests/auto/quick/touchmouse/BLACKLIST @@ -1,2 +1,6 @@ [buttonOnDelayedPressFlickable] windows gcc developer-build + +# QTBUG-74517 +[buttonOnFlickable] +windows gcc developer-build -- cgit v1.2.3 From 7feb0848fdbe9657a1f8152c71474ed78458639b Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 18 Mar 2019 14:50:27 +0100 Subject: Blacklist AnimatedImage::test_crashRaceCondition_replyFinished() This is unstable on macOS 10.13. Task-number: QTBUG-74525 Change-Id: I8c04b4f0b4c560d1805982a605f994e0f1f1c87d Reviewed-by: Shawn Rutledge --- tests/auto/qmltest/animatedimage/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/auto/qmltest/animatedimage/BLACKLIST diff --git a/tests/auto/qmltest/animatedimage/BLACKLIST b/tests/auto/qmltest/animatedimage/BLACKLIST new file mode 100644 index 0000000000..3a5ed393ea --- /dev/null +++ b/tests/auto/qmltest/animatedimage/BLACKLIST @@ -0,0 +1,2 @@ +[AnimatedImage::test_crashRaceCondition_replyFinished] +osx-10.13 -- cgit v1.2.3 From 3f7ed7b7adc2adb96c0c393c0355de112cab0ee6 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 19 Mar 2019 15:36:23 +0100 Subject: Raise timeout in QQmlPreview test Apparently on some platforms this can time out. Change-Id: I30cd274ff3127319c558b473b6ec7e7f5bc79c38 Reviewed-by: Simon Hausmann --- tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp index 4c4c514832..f713aa76c3 100644 --- a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp +++ b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp @@ -338,7 +338,7 @@ void tst_QQmlPreview::fps() QVERIFY(m_client); m_client->triggerLoad(testFileUrl(file)); if (QGuiApplication::platformName() != "offscreen") { - QTRY_VERIFY(m_frameStats.numSyncs > 10); + QTRY_VERIFY_WITH_TIMEOUT(m_frameStats.numSyncs > 10, 10000); QVERIFY(m_frameStats.minSync <= m_frameStats.maxSync); QVERIFY(m_frameStats.totalSync / m_frameStats.numSyncs >= m_frameStats.minSync - 1); QVERIFY(m_frameStats.totalSync / m_frameStats.numSyncs <= m_frameStats.maxSync); -- cgit v1.2.3 From d4076f5ae93e7994e5ce5edcf35a090978613e98 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 19 Mar 2019 11:20:04 +0100 Subject: Blacklist tst_QQuickListView::enforceRange_withoutHighlight on opensuse Task-number: QTBUG-74544 Change-Id: I0a8c54d2a02d959edacd82abcee4553222d575d9 Reviewed-by: Shawn Rutledge --- tests/auto/quick/qquicklistview/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/quick/qquicklistview/BLACKLIST b/tests/auto/quick/qquicklistview/BLACKLIST index e22d52294f..ecdf8f558e 100644 --- a/tests/auto/quick/qquicklistview/BLACKLIST +++ b/tests/auto/quick/qquicklistview/BLACKLIST @@ -1,5 +1,7 @@ [enforceRange_withoutHighlight] osx +opensuse-42.3 +opensuse-leap #QTBUG-53863 [populateTransitions] opensuse-42.1 -- cgit v1.2.3 From c9e6251cc8dfcf002f64b07e48dd68b7edd3f630 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 2 Jan 2019 16:09:56 +0100 Subject: Implement dummy QML lookups for "global" variables When resolving names in the context of QML bindings, we now direct runtime access to QQmlContextWrapper::resolveQmlPropertyLookupGetter. At the moment this does basically the same as Runtime::method_loadName, which we called earlier. However this now provides the opportunity to optimize lookups in the QML context in a central place. When performing a call on a scope or context object property, we also did not use a CallName() instruction - which would have gotten the thisObject wrong - but instead we use a dedicated CallScopeObjectProperty and CallContextObjectProperty instruction. These rely on identifying these properties at compile time, which goes away with lookups (and also doesn't work when using ahead-of-time compilation). Therefore the qml context property lookup is using a getPropertyAndBase style signature and Runtime::method_callQmlContextPropertyLookup uses that. For the tests to pass, some error expectations need adjusting. In particular the compile-time detection of write attempts to id objects is now delayed to the run-time. The old code path is still there and will be removed separately in the next commit (as it is massive). Task-number: QTBUG-69898 Change-Id: Iad1ff93d3758c4db984a7c2d003beee21ed2275c Reviewed-by: Ulf Hermann --- src/qml/compiler/qqmlirbuilder.cpp | 3 +- src/qml/compiler/qv4bytecodehandler.cpp | 6 +++ src/qml/compiler/qv4codegen.cpp | 35 ++++++++---- src/qml/compiler/qv4codegen_p.h | 5 +- src/qml/compiler/qv4compileddata.cpp | 2 + src/qml/compiler/qv4compileddata_p.h | 7 +-- src/qml/compiler/qv4compiler.cpp | 12 +++-- src/qml/compiler/qv4compiler_p.h | 2 +- src/qml/compiler/qv4compilercontext.cpp | 7 ++- src/qml/compiler/qv4compilercontext_p.h | 1 + src/qml/compiler/qv4instr_moth.cpp | 8 +++ src/qml/compiler/qv4instr_moth_p.h | 4 ++ src/qml/jit/qv4baselinejit.cpp | 22 ++++++++ src/qml/jit/qv4baselinejit_p.h | 2 + src/qml/jit/qv4jithelpers.cpp | 6 +++ src/qml/jit/qv4jithelpers_p.h | 1 + src/qml/jsruntime/qv4engine.cpp | 8 +++ src/qml/jsruntime/qv4engine_p.h | 1 + src/qml/jsruntime/qv4lookup_p.h | 1 + src/qml/jsruntime/qv4qmlcontext.cpp | 62 ++++++++++++++++++---- src/qml/jsruntime/qv4qmlcontext_p.h | 4 ++ src/qml/jsruntime/qv4runtime.cpp | 49 ++++++++++------- src/qml/jsruntime/qv4runtimeapi_p.h | 1 + src/qml/jsruntime/qv4vme_moth.cpp | 13 +++++ .../qml/qqmlecmascript/data/signalHandlers.qml | 2 + .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 10 ++-- .../auto/qml/qqmllanguage/data/thisInQmlScope.qml | 13 +++++ tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 2 + 28 files changed, 235 insertions(+), 54 deletions(-) diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 59b9968bf6..4b4d3c27e8 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -2228,7 +2228,8 @@ void JSCodeGen::beginFunctionBodyHook() QV4::Compiler::Codegen::Reference JSCodeGen::fallbackNameLookup(const QString &name) { #ifndef V4_BOOTSTRAP - if (_disableAcceleratedLookups) + // FIXME: Remove this function. + if (_disableAcceleratedLookups || true) return Reference(); // Implement QML lookup semantics in the current file context. diff --git a/src/qml/compiler/qv4bytecodehandler.cpp b/src/qml/compiler/qv4bytecodehandler.cpp index af86b70014..a34472010b 100644 --- a/src/qml/compiler/qv4bytecodehandler.cpp +++ b/src/qml/compiler/qv4bytecodehandler.cpp @@ -192,6 +192,9 @@ std::vector ByteCodeHandler::collectLabelsInBytecode(const char *code, uint COLLECTOR_BEGIN_INSTR(LoadGlobalLookup) COLLECTOR_END_INSTR(LoadGlobalLookup) + COLLECTOR_BEGIN_INSTR(LoadQmlContextPropertyLookup) + COLLECTOR_END_INSTR(LoadQmlContextPropertyLookup) + COLLECTOR_BEGIN_INSTR(StoreNameSloppy) COLLECTOR_END_INSTR(StoreNameSloppy) @@ -270,6 +273,9 @@ std::vector ByteCodeHandler::collectLabelsInBytecode(const char *code, uint COLLECTOR_BEGIN_INSTR(CallGlobalLookup) COLLECTOR_END_INSTR(CallGlobalLookup) + COLLECTOR_BEGIN_INSTR(CallQmlContextPropertyLookup) + COLLECTOR_END_INSTR(CallQmlContextPropertyLookup) + COLLECTOR_BEGIN_INSTR(CallScopeObjectProperty) COLLECTOR_END_INSTR(CallScopeObjectProperty) diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 66c334d197..de87d6d48c 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1982,11 +1982,19 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio call.argv = calldata.argv; bytecodeGenerator->addInstruction(call); } else if (!disable_lookups && useFastLookups && base.global) { - Instruction::CallGlobalLookup call; - call.index = registerGlobalGetterLookup(base.nameAsIndex()); - call.argc = calldata.argc; - call.argv = calldata.argv; - bytecodeGenerator->addInstruction(call); + if (base.qmlGlobal) { + Instruction::CallQmlContextPropertyLookup call; + call.index = registerQmlContextPropertyGetterLookup(base.nameAsIndex()); + call.argc = calldata.argc; + call.argv = calldata.argv; + bytecodeGenerator->addInstruction(call); + } else { + Instruction::CallGlobalLookup call; + call.index = registerGlobalGetterLookup(base.nameAsIndex()); + call.argc = calldata.argc; + call.argv = calldata.argv; + bytecodeGenerator->addInstruction(call); + } } else { Instruction::CallName call; call.name = base.nameAsIndex(); @@ -2361,8 +2369,9 @@ Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs, co return fallback; Reference r = Reference::fromName(this, name); - r.global = useFastLookups && (resolved.type == Context::ResolvedName::Global); - if (!r.global && canAccelerateGlobalLookups() && m_globalNames.contains(name)) + r.global = useFastLookups && (resolved.type == Context::ResolvedName::Global || resolved.type == Context::ResolvedName::QmlGlobal); + r.qmlGlobal = resolved.type == Context::ResolvedName::QmlGlobal; + if (!r.global && !r.qmlGlobal && m_globalNames.contains(name)) r.global = true; return r; } @@ -4385,9 +4394,15 @@ QT_WARNING_POP } } if (!disable_lookups && global) { - Instruction::LoadGlobalLookup load; - load.index = codegen->registerGlobalGetterLookup(nameAsIndex()); - codegen->bytecodeGenerator->addInstruction(load); + if (qmlGlobal) { + Instruction::LoadQmlContextPropertyLookup load; + load.index = codegen->registerQmlContextPropertyGetterLookup(nameAsIndex()); + codegen->bytecodeGenerator->addInstruction(load); + } else { + Instruction::LoadGlobalLookup load; + load.index = codegen->registerGlobalGetterLookup(nameAsIndex()); + codegen->bytecodeGenerator->addInstruction(load); + } } else { Instruction::LoadName load; load.name = nameAsIndex(); diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 0b25d9c53d..b1cc4c090a 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -207,7 +207,8 @@ public: subscriptRequiresTDZCheck(false), stackSlotIsLocalOrArgument(false), isVolatile(false), - global(false) + global(false), + qmlGlobal(false) {} Reference(const Reference &) = default; @@ -421,6 +422,7 @@ public: quint32 stackSlotIsLocalOrArgument:1; quint32 isVolatile:1; quint32 global:1; + quint32 qmlGlobal:1; private: void storeAccumulator() const; @@ -553,6 +555,7 @@ public: int registerGetterLookup(int nameIndex) { return jsUnitGenerator->registerGetterLookup(nameIndex); } int registerSetterLookup(int nameIndex) { return jsUnitGenerator->registerSetterLookup(nameIndex); } int registerGlobalGetterLookup(int nameIndex) { return jsUnitGenerator->registerGlobalGetterLookup(nameIndex); } + int registerQmlContextPropertyGetterLookup(int nameIndex) { return jsUnitGenerator->registerQmlContextPropertyGetterLookup(nameIndex); } // Returns index in _module->functions virtual int defineFunction(const QString &name, AST::Node *ast, diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index e428340f62..6701443971 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -170,6 +170,8 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) l->setter = QV4::Lookup::setterGeneric; else if (type == CompiledData::Lookup::Type_GlobalGetter) l->globalGetter = QV4::Lookup::globalGetterGeneric; + else if (type == CompiledData::Lookup::Type_QmlContextPropertyGetter) + l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter; l->nameIndex = compiledLookups[i].nameIndex; } } diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index c4821daa86..d63b1fd2b9 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -160,9 +160,10 @@ static_assert(sizeof(RegExp) == 4, "RegExp structure needs to have the expected struct Lookup { enum Type : unsigned int { - Type_Getter = 0x0, - Type_Setter = 0x1, - Type_GlobalGetter = 2 + Type_Getter = 0, + Type_Setter = 1, + Type_GlobalGetter = 2, + Type_QmlContextPropertyGetter = 3 }; union { diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 3076c6b526..a3c9347c67 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -154,15 +154,19 @@ int QV4::Compiler::JSUnitGenerator::registerSetterLookup(int nameIndex) return lookups.size() - 1; } -int QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(const QString &name) +int QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(int nameIndex) { - return registerGlobalGetterLookup(registerString(name)); + CompiledData::Lookup l; + l.type_and_flags = CompiledData::Lookup::Type_GlobalGetter; + l.nameIndex = nameIndex; + lookups << l; + return lookups.size() - 1; } -int QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(int nameIndex) +int QV4::Compiler::JSUnitGenerator::registerQmlContextPropertyGetterLookup(int nameIndex) { CompiledData::Lookup l; - l.type_and_flags = CompiledData::Lookup::Type_GlobalGetter; + l.type_and_flags = CompiledData::Lookup::Type_QmlContextPropertyGetter; l.nameIndex = nameIndex; lookups << l; return lookups.size() - 1; diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h index 2f5889ab53..49e334bb81 100644 --- a/src/qml/compiler/qv4compiler_p.h +++ b/src/qml/compiler/qv4compiler_p.h @@ -118,8 +118,8 @@ struct Q_QML_PRIVATE_EXPORT JSUnitGenerator { int registerGetterLookup(int nameIndex); int registerSetterLookup(const QString &name); int registerSetterLookup(int nameIndex); - int registerGlobalGetterLookup(const QString &name); int registerGlobalGetterLookup(int nameIndex); + int registerQmlContextPropertyGetterLookup(int nameIndex); int registerRegExp(QQmlJS::AST::RegExpLiteral *regexp); diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp index 5772bff7bf..84c5d67e8d 100644 --- a/src/qml/compiler/qv4compilercontext.cpp +++ b/src/qml/compiler/qv4compilercontext.cpp @@ -187,10 +187,13 @@ Context::ResolvedName Context::resolveName(const QString &name, const QQmlJS::AS } // ### can we relax the restrictions here? - if (c->contextType == ContextType::Eval || c->contextType == ContextType::Binding) + if (c->contextType == ContextType::Eval) return result; - result.type = ResolvedName::Global; + if (c->contextType == ContextType::Binding) + result.type = ResolvedName::QmlGlobal; + else + result.type = ResolvedName::Global; return result; } diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h index 328715da07..c9e54c0d1b 100644 --- a/src/qml/compiler/qv4compilercontext_p.h +++ b/src/qml/compiler/qv4compilercontext_p.h @@ -336,6 +336,7 @@ struct Context { struct ResolvedName { enum Type { Unresolved, + QmlGlobal, Global, Local, Stack, diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp index 83aca3a02c..d2e95b83c4 100644 --- a/src/qml/compiler/qv4instr_moth.cpp +++ b/src/qml/compiler/qv4instr_moth.cpp @@ -286,6 +286,10 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st d << index; MOTH_END_INSTR(LoadGlobalLookup) + MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup) + d << index; + MOTH_END_INSTR(LoadQmlContextPropertyLookup) + MOTH_BEGIN_INSTR(StoreNameSloppy) d << name; MOTH_END_INSTR(StoreNameSloppy) @@ -388,6 +392,10 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st d << index << dumpArguments(argc, argv, nFormals); MOTH_END_INSTR(CallGlobalLookup) + MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup) + d << index << dumpArguments(argc, argv, nFormals); + MOTH_END_INSTR(CallQmlContextPropertyLookup) + MOTH_BEGIN_INSTR(CallScopeObjectProperty) d << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals); MOTH_END_INSTR(CallScopeObjectProperty) diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 2ca8f692b8..1c77e6050c 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -86,6 +86,7 @@ QT_BEGIN_NAMESPACE #define INSTR_LoadClosure(op) INSTRUCTION(op, LoadClosure, 1, value) #define INSTR_LoadName(op) INSTRUCTION(op, LoadName, 1, name) #define INSTR_LoadGlobalLookup(op) INSTRUCTION(op, LoadGlobalLookup, 1, index) +#define INSTR_LoadQmlContextPropertyLookup(op) INSTRUCTION(op, LoadQmlContextPropertyLookup, 1, index) #define INSTR_StoreNameSloppy(op) INSTRUCTION(op, StoreNameSloppy, 1, name) #define INSTR_StoreNameStrict(op) INSTRUCTION(op, StoreNameStrict, 1, name) #define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 1, name) @@ -113,6 +114,7 @@ QT_BEGIN_NAMESPACE #define INSTR_CallName(op) INSTRUCTION(op, CallName, 3, name, argc, argv) #define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 2, argc, argv) #define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 3, index, argc, argv) +#define INSTR_CallQmlContextPropertyLookup(op) INSTRUCTION(op, CallQmlContextPropertyLookup, 3, index, argc, argv) #define INSTR_CallScopeObjectProperty(op) INSTRUCTION(op, CallScopeObjectProperty, 4, name, base, argc, argv) #define INSTR_CallContextObjectProperty(op) INSTRUCTION(op, CallContextObjectProperty, 4, name, base, argc, argv) #define INSTR_CallWithSpread(op) INSTRUCTION(op, CallWithSpread, 4, func, thisObject, argc, argv) @@ -228,6 +230,7 @@ QT_BEGIN_NAMESPACE F(LoadClosure) \ F(LoadName) \ F(LoadGlobalLookup) \ + F(LoadQmlContextPropertyLookup) \ F(StoreNameSloppy) \ F(StoreNameStrict) \ F(LoadElement) \ @@ -296,6 +299,7 @@ QT_BEGIN_NAMESPACE F(CallName) \ F(CallPossiblyDirectEval) \ F(CallGlobalLookup) \ + F(CallQmlContextPropertyLookup) \ F(CallScopeObjectProperty) \ F(CallContextObjectProperty) \ F(CallWithSpread) \ diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp index 098bbfc6c6..47cef3b3bd 100644 --- a/src/qml/jit/qv4baselinejit.cpp +++ b/src/qml/jit/qv4baselinejit.cpp @@ -213,6 +213,16 @@ void BaselineJIT::generate_LoadGlobalLookup(int index) as->checkException(); } +void BaselineJIT::generate_LoadQmlContextPropertyLookup(int index) +{ + as->prepareCallWithArgCount(3); + as->passInt32AsArg(index, 2); + as->passEngineAsArg(1); + as->passFunctionAsArg(0); + BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::loadQmlContextPropertyLookup, CallResultDestination::InAccumulator); + as->checkException(); +} + void BaselineJIT::generate_StoreNameSloppy(int name) { STORE_IP(); @@ -514,6 +524,18 @@ void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv) as->checkException(); } +void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int argv) +{ + STORE_IP(); + as->prepareCallWithArgCount(4); + as->passInt32AsArg(argc, 3); + as->passJSSlotAsArg(argv, 2); + as->passInt32AsArg(index, 1); + as->passEngineAsArg(0); + BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callQmlContextPropertyLookup, CallResultDestination::InAccumulator); + as->checkException(); +} + void BaselineJIT::generate_CallScopeObjectProperty(int propIdx, int base, int argc, int argv) { STORE_IP(); diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h index 98d23f4517..4db1eb1806 100644 --- a/src/qml/jit/qv4baselinejit_p.h +++ b/src/qml/jit/qv4baselinejit_p.h @@ -97,6 +97,7 @@ public: void generate_LoadClosure(int value) override; void generate_LoadName(int name) override; void generate_LoadGlobalLookup(int index) override; + void generate_LoadQmlContextPropertyLookup(int index) override; void generate_StoreNameSloppy(int name) override; void generate_StoreNameStrict(int name) override; void generate_LoadElement(int base) override; @@ -128,6 +129,7 @@ public: void generate_CallName(int name, int argc, int argv) override; void generate_CallPossiblyDirectEval(int argc, int argv) override; void generate_CallGlobalLookup(int index, int argc, int argv) override; + void generate_CallQmlContextPropertyLookup(int index, int argc, int argv) override; void generate_CallScopeObjectProperty(int propIdx, int base, int argc, int argv) override; void generate_CallContextObjectProperty(int propIdx, int base, int argc, int argv) override; void generate_CallWithSpread(int func, int thisObject, int argc, int argv) override; diff --git a/src/qml/jit/qv4jithelpers.cpp b/src/qml/jit/qv4jithelpers.cpp index f43f37ad70..674fd8c8c8 100644 --- a/src/qml/jit/qv4jithelpers.cpp +++ b/src/qml/jit/qv4jithelpers.cpp @@ -70,6 +70,12 @@ ReturnedValue loadGlobalLookup(Function *f, ExecutionEngine *engine, int index) return l->globalGetter(l, engine); } +ReturnedValue loadQmlContextPropertyLookup(Function *f, ExecutionEngine *engine, int index) +{ + Lookup *l = f->compilationUnit->runtimeLookups + index; + return l->qmlContextPropertyGetter(l, engine, nullptr); +} + ReturnedValue toObject(ExecutionEngine *engine, const Value &obj) { if (obj.isObject()) diff --git a/src/qml/jit/qv4jithelpers_p.h b/src/qml/jit/qv4jithelpers_p.h index bd5f65034d..d9abfc071e 100644 --- a/src/qml/jit/qv4jithelpers_p.h +++ b/src/qml/jit/qv4jithelpers_p.h @@ -66,6 +66,7 @@ namespace Helpers { void convertThisToObject(ExecutionEngine *engine, Value *t); ReturnedValue loadGlobalLookup(Function *f, ExecutionEngine *engine, int index); +ReturnedValue loadQmlContextPropertyLookup(Function *f, ExecutionEngine *engine, int index); ReturnedValue toObject(ExecutionEngine *engine, const Value &obj); ReturnedValue exp(const Value &base, const Value &exp); ReturnedValue getLookup(Function *f, ExecutionEngine *engine, const Value &base, int index); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index f00578aa70..1d0c7c13fa 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1169,6 +1169,14 @@ ReturnedValue ExecutionEngine::throwTypeError(const QString &message) return throwError(error); } +ReturnedValue ExecutionEngine::throwReferenceError(const QString &name) +{ + Scope scope(this); + QString msg = name + QLatin1String(" is not defined"); + ScopedObject error(scope, newReferenceErrorObject(msg)); + return throwError(error); +} + ReturnedValue ExecutionEngine::throwReferenceError(const Value &value) { Scope scope(this); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 64c7e2f32b..86367c0ece 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -569,6 +569,7 @@ public: ReturnedValue throwTypeError(); ReturnedValue throwTypeError(const QString &message); ReturnedValue throwReferenceError(const Value &value); + ReturnedValue throwReferenceError(const QString &name); ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int lineNumber, int column); ReturnedValue throwRangeError(const Value &value); ReturnedValue throwRangeError(const QString &message); diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index b0d5706dea..e4d9ad8328 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -68,6 +68,7 @@ struct Lookup { union { ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object); ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine); + ReturnedValue (*qmlContextPropertyGetter)(Lookup *l, ExecutionEngine *engine, Value *thisObject); bool (*setter)(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v); }; union { diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index 88b0822f42..ae458c604a 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -55,6 +55,8 @@ #include #include #include +#include +#include QT_BEGIN_NAMESPACE @@ -77,14 +79,11 @@ void Heap::QQmlContextWrapper::destroy() Object::destroy(); } -ReturnedValue QQmlContextWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty) +ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *resource, PropertyKey id, const Value *receiver, bool *hasProperty, Value *base) { - Q_ASSERT(m->as()); - if (!id.isString()) - return Object::virtualGet(m, id, receiver, hasProperty); + return Object::virtualGet(resource, id, receiver, hasProperty); - const QQmlContextWrapper *resource = static_cast(m); QV4::ExecutionEngine *v4 = resource->engine(); QV4::Scope scope(v4); @@ -100,11 +99,11 @@ ReturnedValue QQmlContextWrapper::virtualGet(const Managed *m, PropertyKey id, c } } - return Object::virtualGet(m, id, receiver, hasProperty); + return Object::virtualGet(resource, id, receiver, hasProperty); } bool hasProp = false; - ScopedValue result(scope, Object::virtualGet(m, id, receiver, &hasProp)); + ScopedValue result(scope, Object::virtualGet(resource, id, receiver, &hasProp)); if (hasProp) { if (hasProperty) *hasProperty = hasProp; @@ -234,6 +233,8 @@ ReturnedValue QQmlContextWrapper::virtualGet(const Managed *m, PropertyKey id, c if (hasProp) { if (hasProperty) *hasProperty = true; + if (base) + *base = QV4::QObjectWrapper::wrap(v4, scopeObject); return result->asReturnedValue(); } } @@ -247,6 +248,8 @@ ReturnedValue QQmlContextWrapper::virtualGet(const Managed *m, PropertyKey id, c if (hasProp) { if (hasProperty) *hasProperty = true; + if (base) + *base = QV4::QObjectWrapper::wrap(v4, context->contextObject); return result->asReturnedValue(); } } @@ -264,6 +267,13 @@ ReturnedValue QQmlContextWrapper::virtualGet(const Managed *m, PropertyKey id, c return Encode::undefined(); } +ReturnedValue QQmlContextWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty) +{ + Q_ASSERT(m->as()); + const QQmlContextWrapper *This = static_cast(m); + return getPropertyAndBase(This, id, receiver, hasProperty, /*base*/nullptr); +} + bool QQmlContextWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver) { Q_ASSERT(m->as()); @@ -298,8 +308,16 @@ bool QQmlContextWrapper::virtualPut(Managed *m, PropertyKey id, const Value &val while (context) { const QV4::IdentifierHash &properties = context->propertyNames(); // Search context properties - if (properties.count() && properties.value(name) != -1) - return false; + if (properties.count()) { + const int propertyIndex = properties.value(name); + if (propertyIndex != -1) { + if (propertyIndex < context->idValueCount) { + v4->throwError(QLatin1String("left-hand side of assignment operator is not an lvalue")); + return false; + } + return false; + } + } // Search scope object if (scopeObject && @@ -323,6 +341,32 @@ bool QQmlContextWrapper::virtualPut(Managed *m, PropertyKey id, const Value &val return false; } +ReturnedValue QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(Lookup *l, ExecutionEngine *engine, Value *base) +{ + Scope scope(engine); + PropertyKey name =engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit-> + runtimeStrings[l->nameIndex]); + + // Special hack for bounded signal expressions, where the parameters of signals are injected + // into the handler expression through the locals of the call context. So for onClicked: { ... } + // the parameters of the clicked signal are injected and we must allow for them to be found here + // before any other property from the QML context. + ExecutionContext &ctx = static_cast(engine->currentStackFrame->jsFrame->context); + if (ctx.d()->type == Heap::ExecutionContext::Type_CallContext) { + uint index = ctx.d()->internalClass->indexOfValueOrGetter(name); + if (index < UINT_MAX) + return static_cast(ctx.d())->locals[index].asReturnedValue(); + } + + Scoped qmlContext(scope, engine->qmlContext()->qml()); + bool hasProperty = false; + ScopedValue result(scope, QQmlContextWrapper::getPropertyAndBase(qmlContext, name, /*receiver*/nullptr, + &hasProperty, base)); + if (!hasProperty) + return engine->throwReferenceError(name.toQString()); + return result->asReturnedValue(); +} + void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml) { Heap::ExecutionContext::init(Heap::ExecutionContext::Type_QmlContext); diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index dd6de3323d..f704280bf4 100644 --- a/src/qml/jsruntime/qv4qmlcontext_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -99,8 +99,12 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object inline QObject *getScopeObject() const { return d()->scopeObject; } inline QQmlContextData *getContext() const { return *d()->context; } + static ReturnedValue getPropertyAndBase(const QQmlContextWrapper *resource, PropertyKey id, const Value *receiver, + bool *hasProperty, Value *base); static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty); static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver); + + static ReturnedValue resolveQmlContextPropertyLookupGetter(Lookup *l, ExecutionEngine *engine, Value *base); }; struct Q_QML_EXPORT QmlContext : public ExecutionContext diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 53dd3a66dd..7163a51af1 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1301,18 +1301,42 @@ uint Runtime::method_compareIn(ExecutionEngine *engine, const Value &left, const return v->booleanValue(); } +static ReturnedValue throwPropertyIsNotAFunctionTypeError(ExecutionEngine *engine, Value *thisObject, const QString &propertyName) +{ + QString objectAsString = QStringLiteral("[null]"); + if (!thisObject->isUndefined()) + objectAsString = thisObject->toQStringNoThrow(); + QString msg = QStringLiteral("Property '%1' of object %2 is not a function") + .arg(propertyName, objectAsString); + return engine->throwTypeError(msg); +} ReturnedValue Runtime::method_callGlobalLookup(ExecutionEngine *engine, uint index, Value *argv, int argc) { + Scope scope(engine); Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index; Value function = Value::fromReturnedValue(l->globalGetter(l, engine)); + Value thisObject = Value::undefinedValue(); if (!function.isFunctionObject()) - return engine->throwTypeError(); + return throwPropertyIsNotAFunctionTypeError(engine, &thisObject, + engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString()); - Value thisObject = Value::undefinedValue(); return static_cast(function).call(&thisObject, argv, argc); } +ReturnedValue Runtime::method_callQmlContextPropertyLookup(ExecutionEngine *engine, uint index, Value *argv, int argc) +{ + Scope scope(engine); + ScopedValue thisObject(scope); + Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index; + Value function = Value::fromReturnedValue(l->qmlContextPropertyGetter(l, engine, thisObject)); + if (!function.isFunctionObject()) + return throwPropertyIsNotAFunctionTypeError(engine, thisObject, + engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString()); + + return static_cast(function).call(thisObject, argv, argc); +} + ReturnedValue Runtime::method_callPossiblyDirectEval(ExecutionEngine *engine, Value *argv, int argc) { Scope scope(engine); @@ -1323,13 +1347,8 @@ ReturnedValue Runtime::method_callPossiblyDirectEval(ExecutionEngine *engine, Va if (engine->hasException) return Encode::undefined(); - if (!function) { - QString objectAsString = QStringLiteral("[null]"); - if (!thisObject->isUndefined()) - objectAsString = thisObject->toQStringNoThrow(); - QString msg = QStringLiteral("Property 'eval' of object %2 is not a function").arg(objectAsString); - return engine->throwTypeError(msg); - } + if (!function) + return throwPropertyIsNotAFunctionTypeError(engine, thisObject, QLatin1String("eval")); if (function->d() == engine->evalFunction()->d()) return static_cast(function.getPointer())->evalCall(thisObject, argv, argc, true); @@ -1348,15 +1367,9 @@ ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, V if (engine->hasException) return Encode::undefined(); - if (!f) { - QString objectAsString = QStringLiteral("[null]"); - if (!thisObject->isUndefined()) - objectAsString = thisObject->toQStringNoThrow(); - QString msg = QStringLiteral("Property '%1' of object %2 is not a function") - .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString(), - objectAsString); - return engine->throwTypeError(msg); - } + if (!f) + return throwPropertyIsNotAFunctionTypeError(engine, thisObject, + engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString()); return f->call(thisObject, argv, argc); } diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index 06e8a8a960..aa4ac27621 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -93,6 +93,7 @@ struct ExceptionCheck { #define FOR_EACH_RUNTIME_METHOD(F) \ /* call */ \ F(ReturnedValue, callGlobalLookup, (ExecutionEngine *engine, uint index, Value *argv, int argc)) \ + F(ReturnedValue, callQmlContextPropertyLookup, (ExecutionEngine *engine, uint index, Value *argv, int argc)) \ F(ReturnedValue, callName, (ExecutionEngine *engine, int nameIndex, Value *argv, int argc)) \ F(ReturnedValue, callProperty, (ExecutionEngine *engine, Value *base, int nameIndex, Value *argv, int argc)) \ F(ReturnedValue, callPropertyLookup, (ExecutionEngine *engine, Value *base, uint index, Value *argv, int argc)) \ diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 000e1ab9d5..2d9337b03e 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -556,6 +556,13 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, CHECK_EXCEPTION; MOTH_END_INSTR(LoadGlobalLookup) + MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup) + STORE_IP(); + QV4::Lookup *l = function->compilationUnit->runtimeLookups + index; + acc = l->qmlContextPropertyGetter(l, engine, nullptr); + CHECK_EXCEPTION; + MOTH_END_INSTR(LoadQmlContextPropertyLookup) + MOTH_BEGIN_INSTR(StoreNameStrict) STORE_IP(); STORE_ACC(); @@ -781,6 +788,12 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, CHECK_EXCEPTION; MOTH_END_INSTR(CallGlobalLookup) + MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup) + STORE_IP(); + acc = Runtime::method_callQmlContextPropertyLookup(engine, index, stack + argv, argc); + CHECK_EXCEPTION; + MOTH_END_INSTR(CallQmlContextPropertyLookup) + MOTH_BEGIN_INSTR(CallScopeObjectProperty) STORE_IP(); acc = Runtime::method_callQmlScopeObjectProperty(engine, stack + base, name, stack + argv, argc); diff --git a/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml index 14326bb9e6..a924519f0f 100644 --- a/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml +++ b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml @@ -8,6 +8,8 @@ QtObject { signal testSignal onTestSignal: count++ + readonly property string scopeObjectAsString: this.toString() + property int funcCount: 0 function testFunction() { funcCount++; diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index f33f1d9125..d8784f4855 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -1609,7 +1609,7 @@ void tst_qqmlecmascript::aliasPropertyReset() // test that a manual write (of undefined) to a non-resettable property fails properly QUrl url = testFileUrl("aliasreset/aliasPropertyReset.error.1.qml"); - QString warning1 = url.toString() + QLatin1String(": Error: Cannot assign [undefined] to int"); + QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int"); QQmlComponent e1(&engine, url); object = e1.create(); QVERIFY(object != nullptr); @@ -6468,7 +6468,8 @@ void tst_qqmlecmascript::signalHandlers() QMetaObject::invokeMethod(o.data(), "testSignalHandlerCall"); QCOMPARE(o->property("count").toInt(), 1); - QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function")); + QString scopeObjectAsString = o->property("scopeObjectAsString").toString(); + QCOMPARE(o->property("errorString").toString(), QString("TypeError: Property 'onTestSignal' of object %1 is not a function").arg(scopeObjectAsString)); QCOMPARE(o->property("funcCount").toInt(), 0); QMetaObject::invokeMethod(o.data(), "testSignalConnection"); @@ -8163,12 +8164,11 @@ void tst_qqmlecmascript::stackLimits() void tst_qqmlecmascript::idsAsLValues() { QQmlEngine engine; - QString err = QString(QLatin1String("%1:5 left-hand side of assignment operator is not an lvalue\n")).arg(testFileUrl("idAsLValue.qml").toString()); + QString err = QString(QLatin1String("%1:5: Error: left-hand side of assignment operator is not an lvalue")).arg(testFileUrl("idAsLValue.qml").toString()); QQmlComponent component(&engine, testFileUrl("idAsLValue.qml")); - QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready"); + QTest::ignoreMessage(QtWarningMsg, qPrintable(err)); MyQmlObject *object = qobject_cast(component.create()); QVERIFY(!object); - QCOMPARE(component.errorString(), err); } void tst_qqmlecmascript::qtbug_34792() diff --git a/tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml b/tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml index e3c99e70e1..9ff758c33f 100644 --- a/tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml +++ b/tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml @@ -6,5 +6,18 @@ QtObject { y = this.x; } property var f: g + Component.onCompleted: f() + + property int a: 42 + property int b: 0 + function g_subobj(){ + b = this.a; + } + property var f_subobj: g_subobj + + property QtObject subObject: QtObject { + property int a: 100 + Component.onCompleted: f_subobj() + } } diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 89856d6603..9a3f488cea 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -5020,6 +5020,8 @@ void tst_qqmllanguage::thisInQmlScope() QVERIFY(!o.isNull()); QCOMPARE(o->property("x"), QVariant(42)); QCOMPARE(o->property("y"), QVariant(42)); + QCOMPARE(o->property("a"), QVariant(42)); + QCOMPARE(o->property("b"), QVariant(42)); } void tst_qqmllanguage::valueTypeGroupPropertiesInBehavior() -- cgit v1.2.3 From 5cfccf30898aed5ca96c0f8779b0f8a1117118b7 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 3 Jan 2019 15:44:34 +0100 Subject: Remove dead compile time QML context/scope property and id object code After enabling lookups in QML files, we can remove all the code that tries to deal with (type) compile time detection of access to id objects and properties of the scope/context object. This also allows removing quite a bit of run-time code paths and even byte code instructions. Task-number: QTBUG-69898 Change-Id: I7b26d7983393594a3ef56466d3e633f1822b76f4 Reviewed-by: Ulf Hermann --- src/qml/compiler/qqmlirbuilder.cpp | 410 +------------------------------ src/qml/compiler/qqmlirbuilder_p.h | 34 +-- src/qml/compiler/qqmltypecompiler.cpp | 33 +-- src/qml/compiler/qv4bytecodehandler.cpp | 27 -- src/qml/compiler/qv4codegen.cpp | 71 +----- src/qml/compiler/qv4codegen_p.h | 58 +---- src/qml/compiler/qv4compileddata_p.h | 27 +- src/qml/compiler/qv4compiler.cpp | 45 +--- src/qml/compiler/qv4compilercontext_p.h | 5 - src/qml/compiler/qv4instr_moth.cpp | 36 --- src/qml/compiler/qv4instr_moth_p.h | 16 -- src/qml/jit/qv4baselinejit.cpp | 103 -------- src/qml/jit/qv4baselinejit_p.h | 13 - src/qml/jsruntime/qv4function.cpp | 1 - src/qml/jsruntime/qv4function_p.h | 1 - src/qml/jsruntime/qv4qobjectwrapper.cpp | 28 +-- src/qml/jsruntime/qv4qobjectwrapper_p.h | 3 +- src/qml/jsruntime/qv4runtime.cpp | 86 ------- src/qml/jsruntime/qv4runtimeapi_p.h | 14 +- src/qml/jsruntime/qv4vme_moth.cpp | 51 ---- src/qml/qml/qqmlbinding.cpp | 32 ++- src/qml/qml/qqmljavascriptexpression.cpp | 82 +------ src/qml/qml/qqmljavascriptexpression_p.h | 21 +- src/qml/types/qqmllistmodel.cpp | 3 +- tools/qmlcachegen/qmlcachegen.cpp | 9 +- 25 files changed, 44 insertions(+), 1165 deletions(-) diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 4b4d3c27e8..ab43ea350b 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -974,7 +974,6 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node) foe->node = funDecl; foe->parentNode = funDecl; foe->nameIndex = registerString(funDecl->name.toString()); - foe->disableAcceleratedLookups = false; const int index = _object->functionsAndExpressions->append(foe); Function *f = New(); @@ -1095,7 +1094,6 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST expr->parentNode = parentNode; expr->nameIndex = registerString(QLatin1String("expression for ") + stringAt(binding->propertyNameIndex)); - expr->disableAcceleratedLookups = false; const int index = bindingsTarget()->functionsAndExpressions->append(expr); binding->value.compiledScriptIndex = index; // We don't need to store the binding script as string, except for script strings @@ -1822,19 +1820,13 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, Binding JSCodeGen::JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator, QV4::Compiler::Module *jsModule, QQmlJS::Engine *jsEngine, - QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, + QQmlJS::AST::UiProgram *qmlRoot, const QV4::Compiler::StringTableGenerator *stringPool, const QSet &globalNames) : QV4::Compiler::Codegen(jsUnitGenerator, /*strict mode*/false) , sourceCode(sourceCode) , jsEngine(jsEngine) , qmlRoot(qmlRoot) - , imports(imports) , stringPool(stringPool) - , _disableAcceleratedLookups(false) - , _contextObject(nullptr) - , _scopeObject(nullptr) - , _qmlContextSlot(-1) - , _importedScriptsSlot(-1) { m_globalNames = globalNames; @@ -1842,18 +1834,6 @@ JSCodeGen::JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator * _fileNameIsUrl = true; } -void JSCodeGen::beginContextScope(const JSCodeGen::ObjectIdMapping &objectIds, QQmlPropertyCache *contextObject) -{ - _idObjects = objectIds; - _contextObject = contextObject; - _scopeObject = nullptr; -} - -void JSCodeGen::beginObjectScope(QQmlPropertyCache *scopeObject) -{ - _scopeObject = scopeObject; -} - QVector JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList &functions) { auto qmlName = [&](const CompiledFunctionOrExpression &c) { @@ -1918,7 +1898,6 @@ QVector JSCodeGen::generateJSCodeForFunctionsAndBindings(const QListfinish(); } - _disableAcceleratedLookups = qmlFunction.disableAcceleratedLookups; int idx = defineFunction(name, function ? function : qmlFunction.parentNode, function ? function->formals : nullptr, body); @@ -1928,392 +1907,6 @@ QVector JSCodeGen::generateJSCodeForFunctionsAndBindings(const QListproperty(name, /*object*/nullptr, /*context*/nullptr); - - if (pd && !cache->isAllowedInRevision(pd)) - return nullptr; - - return pd; -} - -enum MetaObjectResolverFlags { - AllPropertiesAreFinal = 0x1, - LookupsIncludeEnums = 0x2, - LookupsExcludeProperties = 0x4, - ResolveTypeInformationOnly = 0x8 -}; - -#if 0 -static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject); - -static void initScopedEnumResolver(QV4::IR::MemberExpressionResolver *resolver, const QQmlType &qmlType, int index); - -static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine, - const QV4::IR::MemberExpressionResolver *resolver, - QV4::IR::Member *member) -{ - QV4::IR::Type result = QV4::IR::VarType; - - QQmlType type = resolver->qmlType; - - if (member->name->constData()->isUpper()) { - bool ok = false; - int value = type.enumValue(qmlEngine, *member->name, &ok); - if (ok) { - member->setEnumValue(value); - return QV4::IR::SInt32Type; - } else { - int index = type.scopedEnumIndex(qmlEngine, *member->name, &ok); - if (ok) { - auto newResolver = resolver->owner->New(); - newResolver->owner = resolver->owner; - initScopedEnumResolver(newResolver, type, index); - return QV4::IR::DiscoveredType(newResolver); - } - } - } - - if (type.isCompositeSingleton()) { - QQmlRefPointer tdata = qmlEngine->typeLoader.getType(type.singletonInstanceInfo()->url); - Q_ASSERT(tdata); - tdata->release(); // Decrease the reference count added from QQmlTypeLoader::getType() - // When a singleton tries to reference itself, it may not be complete yet. - if (tdata->isComplete()) { - auto newResolver = resolver->owner->New(); - newResolver->owner = resolver->owner; - initMetaObjectResolver(newResolver, qmlEngine->propertyCacheForType(tdata->compilationUnit()->metaTypeId)); - newResolver->flags |= AllPropertiesAreFinal; - return newResolver->resolveMember(qmlEngine, newResolver, member); - } - } else if (type.isSingleton()) { - const QMetaObject *singletonMeta = type.singletonInstanceInfo()->instanceMetaObject; - if (singletonMeta) { // QJSValue-based singletons cannot be accelerated - auto newResolver = resolver->owner->New(); - newResolver->owner = resolver->owner; - initMetaObjectResolver(newResolver, qmlEngine->cache(singletonMeta)); - member->kind = QV4::IR::Member::MemberOfSingletonObject; - return newResolver->resolveMember(qmlEngine, newResolver, member); - } - } -#if 0 - else if (const QMetaObject *attachedMeta = type->attachedPropertiesType(qmlEngine)) { - // Right now the attached property IDs are not stable and cannot be embedded in the - // code that is cached on disk. - QQmlPropertyCache *cache = qmlEngine->cache(attachedMeta); - auto newResolver = resolver->owner->New(); - newResolver->owner = resolver->owner; - initMetaObjectResolver(newResolver, cache); - member->setAttachedPropertiesId(type->attachedPropertiesId(qmlEngine)); - return newResolver->resolveMember(qmlEngine, newResolver, member); - } -#endif - - return result; -} - -static void initQmlTypeResolver(QV4::IR::MemberExpressionResolver *resolver, const QQmlType &qmlType) -{ - Q_ASSERT(resolver); - - resolver->resolveMember = &resolveQmlType; - resolver->qmlType = qmlType; - resolver->typenameCache = 0; - resolver->flags = 0; -} - -static QV4::IR::DiscoveredType resolveImportNamespace( - QQmlEnginePrivate *, const QV4::IR::MemberExpressionResolver *resolver, - QV4::IR::Member *member) -{ - QV4::IR::Type result = QV4::IR::VarType; - QQmlTypeNameCache *typeNamespace = resolver->typenameCache; - const QQmlImportRef *importNamespace = resolver->import; - - QQmlTypeNameCache::Result r = typeNamespace->query(*member->name, importNamespace); - if (r.isValid()) { - member->freeOfSideEffects = true; - if (r.scriptIndex != -1) { - // TODO: remember the index and replace with subscript later. - result = QV4::IR::VarType; - } else if (r.type.isValid()) { - // TODO: Propagate singleton information, so that it is loaded - // through the singleton getter in the run-time. Until then we - // can't accelerate access :( - if (!r.type.isSingleton()) { - auto newResolver = resolver->owner->New(); - newResolver->owner = resolver->owner; - initQmlTypeResolver(newResolver, r.type); - return QV4::IR::DiscoveredType(newResolver); - } - } else { - Q_ASSERT(false); // How can this happen? - } - } - - return result; -} - -static void initImportNamespaceResolver(QV4::IR::MemberExpressionResolver *resolver, - QQmlTypeNameCache *imports, const QQmlImportRef *importNamespace) -{ - resolver->resolveMember = &resolveImportNamespace; - resolver->import = importNamespace; - resolver->typenameCache = imports; - resolver->flags = 0; -} - -static QV4::IR::DiscoveredType resolveMetaObjectProperty( - QQmlEnginePrivate *qmlEngine, const QV4::IR::MemberExpressionResolver *resolver, - QV4::IR::Member *member) -{ - QV4::IR::Type result = QV4::IR::VarType; - QQmlPropertyCache *metaObject = resolver->propertyCache; - - if (member->name->constData()->isUpper() && (resolver->flags & LookupsIncludeEnums)) { - const QMetaObject *mo = metaObject->createMetaObject(); - QByteArray enumName = member->name->toUtf8(); - for (int ii = mo->enumeratorCount() - 1; ii >= 0; --ii) { - QMetaEnum metaEnum = mo->enumerator(ii); - bool ok; - int value = metaEnum.keyToValue(enumName.constData(), &ok); - if (ok) { - member->setEnumValue(value); - return QV4::IR::SInt32Type; - } - } - } - - if (member->kind != QV4::IR::Member::MemberOfIdObjectsArray && member->kind != QV4::IR::Member::MemberOfSingletonObject && - qmlEngine && !(resolver->flags & LookupsExcludeProperties)) { - QQmlPropertyData *property = member->property; - if (!property && metaObject) { - if (QQmlPropertyData *candidate = metaObject->property(*member->name, /*object*/0, /*context*/0)) { - const bool isFinalProperty = (candidate->isFinal() || (resolver->flags & AllPropertiesAreFinal)) - && !candidate->isFunction(); - - if (lookupHints() - && !(resolver->flags & AllPropertiesAreFinal) - && !candidate->isFinal() - && !candidate->isFunction() - && candidate->isDirect()) { - qWarning() << "Hint: Access to property" << *member->name << "of" << metaObject->className() << "could be accelerated if it was marked as FINAL"; - } - - if (isFinalProperty && metaObject->isAllowedInRevision(candidate)) { - property = candidate; - member->inhibitTypeConversionOnWrite = true; - if (!(resolver->flags & ResolveTypeInformationOnly)) - member->property = candidate; // Cache for next iteration and isel needs it. - } - } - } - - if (property) { - // Enums cannot be mapped to IR types, they need to go through the run-time handling - // of accepting strings that will then be converted to the right values. - if (property->isEnum()) - return QV4::IR::VarType; - - switch (property->propType()) { - case QMetaType::Bool: result = QV4::IR::BoolType; break; - case QMetaType::Int: result = QV4::IR::SInt32Type; break; - case QMetaType::Double: result = QV4::IR::DoubleType; break; - case QMetaType::QString: result = QV4::IR::StringType; break; - default: - if (property->isQObject()) { - if (QQmlPropertyCache *cache = qmlEngine->propertyCacheForType(property->propType())) { - auto newResolver = resolver->owner->New(); - newResolver->owner = resolver->owner; - initMetaObjectResolver(newResolver, cache); - return QV4::IR::DiscoveredType(newResolver); - } - } else if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType())) { - if (QQmlPropertyCache *cache = qmlEngine->cache(valueTypeMetaObject)) { - auto newResolver = resolver->owner->New(); - newResolver->owner = resolver->owner; - initMetaObjectResolver(newResolver, cache); - newResolver->flags |= ResolveTypeInformationOnly; - return QV4::IR::DiscoveredType(newResolver); - } - } - break; - } - } - } - - return result; -} - -static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject) -{ - Q_ASSERT(resolver); - - resolver->resolveMember = &resolveMetaObjectProperty; - resolver->propertyCache = metaObject; - resolver->flags = 0; -} - -static QV4::IR::DiscoveredType resolveScopedEnum(QQmlEnginePrivate *qmlEngine, - const QV4::IR::MemberExpressionResolver *resolver, - QV4::IR::Member *member) -{ - if (!member->name->constData()->isUpper()) - return QV4::IR::VarType; - - QQmlType type = resolver->qmlType; - int index = resolver->flags; - - bool ok = false; - int value = type.scopedEnumValue(qmlEngine, index, *member->name, &ok); - if (!ok) - return QV4::IR::VarType; - member->setEnumValue(value); - return QV4::IR::SInt32Type; -} - -static void initScopedEnumResolver(QV4::IR::MemberExpressionResolver *resolver, const QQmlType &qmlType, int index) -{ - Q_ASSERT(resolver); - - resolver->resolveMember = &resolveScopedEnum; - resolver->qmlType = qmlType; - resolver->flags = index; -} -#endif - -#endif // V4_BOOTSTRAP - -void JSCodeGen::beginFunctionBodyHook() -{ - _qmlContextSlot = bytecodeGenerator->newRegister(); - _importedScriptsSlot = bytecodeGenerator->newRegister(); - -#ifndef V4_BOOTSTRAP - Instruction::LoadQmlContext load; - load.result = Reference::fromStackSlot(this, _qmlContextSlot).stackSlot(); - bytecodeGenerator->addInstruction(load); - -#if 0 - temp->type = QV4::IR::QObjectType; - temp->memberResolver = _function->New(); - initMetaObjectResolver(temp->memberResolver, _scopeObject); - auto name = _block->NAME(QV4::IR::Name::builtin_qml_context, 0, 0); - name->type = temp->type; -#endif - - Instruction::LoadQmlImportedScripts loadScripts; - loadScripts.result = Reference::fromStackSlot(this, _importedScriptsSlot).stackSlot(); - bytecodeGenerator->addInstruction(loadScripts); -#endif -} - -QV4::Compiler::Codegen::Reference JSCodeGen::fallbackNameLookup(const QString &name) -{ -#ifndef V4_BOOTSTRAP - // FIXME: Remove this function. - if (_disableAcceleratedLookups || true) - return Reference(); - - // Implement QML lookup semantics in the current file context. - // - // Note: We do not check if properties of the qml scope object or context object - // are final. That's because QML tries to get as close as possible to lexical scoping, - // which means in terms of properties that only those visible at compile time are chosen. - // I.e. access to a "foo" property declared within the same QML component as "property int foo" - // will always access that instance and as integer. If a sub-type implements its own property string foo, - // then that one is not chosen for accesses from within this file, because it wasn't visible at compile - // time. This corresponds to the logic in QQmlPropertyCache::findProperty to find the property associated - // with the correct QML context. - - // Look for IDs first. - for (const IdMapping &mapping : qAsConst(_idObjects)) { - if (name == mapping.name) { - if (_context->contextType == QV4::Compiler::ContextType::Binding) - _context->idObjectDependencies.insert(mapping.idIndex); - - Instruction::LoadIdObject load; - load.base = Reference::fromStackSlot(this, _qmlContextSlot).stackSlot(); - load.index = mapping.idIndex; - - Reference result = Reference::fromAccumulator(this); - bytecodeGenerator->addInstruction(load); - result.isReadonly = true; - return result; - } - } - - if (name.at(0).isUpper()) { - QQmlTypeNameCache::Result r = imports->query(name); - if (r.isValid()) { - if (r.scriptIndex != -1) { - Reference imports = Reference::fromStackSlot(this, _importedScriptsSlot); - return Reference::fromSubscript(imports, Reference::fromConst(this, QV4::Encode(r.scriptIndex))); - } else if (r.type.isValid()) { - return Reference::fromName(this, name); - } else { - Q_ASSERT(r.importNamespace); - return Reference::fromName(this, name); - } - } - } - - if (_scopeObject) { - QQmlPropertyData *data = lookupQmlCompliantProperty(_scopeObject, name); - if (data) { - // Q_INVOKABLEs can't be FINAL, so we have to look them up at run-time - if (data->isFunction()) - return Reference::fromName(this, name); - - Reference base = Reference::fromStackSlot(this, _qmlContextSlot); - Reference::PropertyCapturePolicy capturePolicy; - if (!data->isConstant() && !data->isQmlBinding()) - capturePolicy = Reference::CaptureAtRuntime; - else - capturePolicy = data->isConstant() ? Reference::DontCapture : Reference::CaptureAheadOfTime; - return Reference::fromQmlScopeObject(base, data->coreIndex(), data->notifyIndex(), capturePolicy); - } - } - - if (_contextObject) { - QQmlPropertyData *data = lookupQmlCompliantProperty(_contextObject, name); - if (data) { - // Q_INVOKABLEs can't be FINAL, so we have to look them up at run-time - if (data->isFunction()) - return Reference::fromName(this, name); - - Reference base = Reference::fromStackSlot(this, _qmlContextSlot); - Reference::PropertyCapturePolicy capturePolicy; - if (!data->isConstant() && !data->isQmlBinding()) - capturePolicy = Reference::CaptureAtRuntime; - else - capturePolicy = data->isConstant() ? Reference::DontCapture : Reference::CaptureAheadOfTime; - return Reference::fromQmlContextObject(base, data->coreIndex(), data->notifyIndex(), capturePolicy); - } - } -#else - Q_UNUSED(name) -#endif // V4_BOOTSTRAP - return Reference(); -} - #ifndef V4_BOOTSTRAP QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRevision, RevisionCheck check) const @@ -2433,7 +2026,6 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO b->value.compiledScriptIndex = functionIndices.count() - 1; QmlIR::CompiledFunctionOrExpression *foe = pool->New(); - foe->disableAcceleratedLookups = true; foe->nameIndex = 0; QQmlJS::AST::ExpressionNode *expr; diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 6affca3ca6..56724bcda5 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -345,7 +345,6 @@ struct Q_QML_PRIVATE_EXPORT CompiledFunctionOrExpression QQmlJS::AST::Node *parentNode = nullptr; // FunctionDeclaration, Statement or Expression QQmlJS::AST::Node *node = nullptr; // FunctionDeclaration, Statement or Expression quint32 nameIndex = 0; - bool disableAcceleratedLookups = false; CompiledFunctionOrExpression *next = nullptr; }; @@ -606,47 +605,16 @@ struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen { JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator, QV4::Compiler::Module *jsModule, QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, - QQmlTypeNameCache *imports, const QV4::Compiler::StringTableGenerator *stringPool, const QSet &globalNames); - - struct IdMapping - { - QString name; - int idIndex; - QQmlPropertyCache *type; - }; - typedef QVector ObjectIdMapping; - - void beginContextScope(const ObjectIdMapping &objectIds, QQmlPropertyCache *contextObject); - void beginObjectScope(QQmlPropertyCache *scopeObject); + const QV4::Compiler::StringTableGenerator *stringPool, const QSet &globalNames); // Returns mapping from input functions to index in IR::Module::functions / compiledData->runtimeFunctions QVector generateJSCodeForFunctionsAndBindings(const QList &functions); - int defineFunction(const QString &name, AST::Node *ast, - AST::FormalParameterList *formals, - AST::StatementList *body) override; - -protected: - void beginFunctionBodyHook() override; - bool canAccelerateGlobalLookups() const override { return !_disableAcceleratedLookups; } - Reference fallbackNameLookup(const QString &name) override; - private: - // returns nullptr if lookup needs to happen by name - QQmlPropertyData *lookupQmlCompliantProperty(QQmlPropertyCache *cache, const QString &name); - QString sourceCode; QQmlJS::Engine *jsEngine; // needed for memory pool QQmlJS::AST::UiProgram *qmlRoot; - QQmlTypeNameCache *imports; const QV4::Compiler::StringTableGenerator *stringPool; - - bool _disableAcceleratedLookups; - ObjectIdMapping _idObjects; - QQmlPropertyCache *_contextObject; - QQmlPropertyCache *_scopeObject; - int _qmlContextSlot; - int _importedScriptsSlot; }; struct Q_QML_PRIVATE_EXPORT IRLoader { diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index f753c78b1a..66d3afc7a0 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -146,7 +146,7 @@ QQmlRefPointer QQmlTypeCompiler::compile() document->jsModule.fileName = typeData->urlString(); document->jsModule.finalUrl = typeData->finalUrlString(); QmlIR::JSCodeGen v4CodeGenerator(document->code, &document->jsGenerator, &document->jsModule, &document->jsParserEngine, - document->program, typeNameCache.data(), &document->jsGenerator.stringTable, engine->v8engine()->illegalNames()); + document->program, &document->jsGenerator.stringTable, engine->v8engine()->illegalNames()); QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator); if (!jsCodeGen.generateCodeForComponents()) return nullptr; @@ -766,10 +766,6 @@ void QQmlScriptStringScanner::scan() if (!pd || pd->propType() != scriptStringMetaType) continue; - QmlIR::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex); - if (foe) - foe->disableAcceleratedLookups = true; - QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex); binding->stringIndex = compiler->registerString(script); } @@ -1323,24 +1319,6 @@ bool QQmlJSCodeGenerator::compileComponent(int contextObject) contextObject = componentBinding->value.objectIndex; } - QmlIR::JSCodeGen::ObjectIdMapping idMapping; - idMapping.reserve(obj->namedObjectsInComponent.count); - for (int i = 0; i < obj->namedObjectsInComponent.count; ++i) { - const int objectIndex = obj->namedObjectsInComponent.at(i); - QmlIR::JSCodeGen::IdMapping m; - const QmlIR::Object *obj = qmlObjects.at(objectIndex); - m.name = stringAt(obj->idNameIndex); - m.idIndex = obj->id; - m.type = propertyCaches->at(objectIndex); - - auto *tref = resolvedType(obj->inheritedTypeNameIndex); - if (tref && tref->isFullyDynamicType) - m.type = nullptr; - - idMapping << m; - } - v4CodeGen->beginContextScope(idMapping, propertyCaches->at(contextObject)); - if (!compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject)) return false; @@ -1354,16 +1332,9 @@ bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIn return true; if (object->functionsAndExpressions->count > 0) { - QQmlPropertyCache *scopeObject = propertyCaches->at(scopeObjectIndex); - v4CodeGen->beginObjectScope(scopeObject); - QList functionsToCompile; - for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next) { - const bool haveCustomParser = customParsers.contains(object->inheritedTypeNameIndex); - if (haveCustomParser) - foe->disableAcceleratedLookups = true; + for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next) functionsToCompile << *foe; - } const QVector runtimeFunctionIndices = v4CodeGen->generateJSCodeForFunctionsAndBindings(functionsToCompile); const QList jsErrors = v4CodeGen->qmlErrors(); if (!jsErrors.isEmpty()) { diff --git a/src/qml/compiler/qv4bytecodehandler.cpp b/src/qml/compiler/qv4bytecodehandler.cpp index a34472010b..e1fc0c6ee3 100644 --- a/src/qml/compiler/qv4bytecodehandler.cpp +++ b/src/qml/compiler/qv4bytecodehandler.cpp @@ -225,21 +225,6 @@ std::vector ByteCodeHandler::collectLabelsInBytecode(const char *code, uint COLLECTOR_BEGIN_INSTR(StoreSuperProperty) COLLECTOR_END_INSTR(StoreSuperProperty) - COLLECTOR_BEGIN_INSTR(StoreScopeObjectProperty) - COLLECTOR_END_INSTR(StoreScopeObjectProperty) - - COLLECTOR_BEGIN_INSTR(LoadScopeObjectProperty) - COLLECTOR_END_INSTR(LoadScopeObjectProperty) - - COLLECTOR_BEGIN_INSTR(StoreContextObjectProperty) - COLLECTOR_END_INSTR(StoreContextObjectProperty) - - COLLECTOR_BEGIN_INSTR(LoadContextObjectProperty) - COLLECTOR_END_INSTR(LoadContextObjectProperty) - - COLLECTOR_BEGIN_INSTR(LoadIdObject) - COLLECTOR_END_INSTR(LoadIdObject) - COLLECTOR_BEGIN_INSTR(Yield) COLLECTOR_END_INSTR(Yield) @@ -276,12 +261,6 @@ std::vector ByteCodeHandler::collectLabelsInBytecode(const char *code, uint COLLECTOR_BEGIN_INSTR(CallQmlContextPropertyLookup) COLLECTOR_END_INSTR(CallQmlContextPropertyLookup) - COLLECTOR_BEGIN_INSTR(CallScopeObjectProperty) - COLLECTOR_END_INSTR(CallScopeObjectProperty) - - COLLECTOR_BEGIN_INSTR(CallContextObjectProperty) - COLLECTOR_END_INSTR(CallContextObjectProperty) - COLLECTOR_BEGIN_INSTR(CallWithSpread) COLLECTOR_END_INSTR(CallWithSpread) @@ -546,12 +525,6 @@ std::vector ByteCodeHandler::collectLabelsInBytecode(const char *code, uint COLLECTOR_BEGIN_INSTR(GetTemplateObject) COLLECTOR_END_INSTR(GetTemplateObject) - COLLECTOR_BEGIN_INSTR(LoadQmlContext) - COLLECTOR_END_INSTR(LoadQmlContext) - - COLLECTOR_BEGIN_INSTR(LoadQmlImportedScripts) - COLLECTOR_END_INSTR(LoadQmlImportedScripts) - COLLECTOR_BEGIN_INSTR(TailCall) COLLECTOR_END_INSTR(TailCall) } diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index de87d6d48c..b0bec5b6f2 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1875,8 +1875,6 @@ bool Codegen::visit(CallExpression *ast) switch (base.type) { case Reference::Member: case Reference::Subscript: - case Reference::QmlScopeObject: - case Reference::QmlContextObject: base = base.asLValue(); break; case Reference::Name: @@ -1938,21 +1936,7 @@ bool Codegen::visit(CallExpression *ast) void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunction, int slotForThisObject) { //### Do we really need all these call instructions? can's we load the callee in a temp? - if (base.type == Reference::QmlScopeObject) { - Instruction::CallScopeObjectProperty call; - call.base = base.qmlBase.stackSlot(); - call.name = base.qmlCoreIndex; - call.argc = calldata.argc; - call.argv = calldata.argv; - bytecodeGenerator->addInstruction(call); - } else if (base.type == Reference::QmlContextObject) { - Instruction::CallContextObjectProperty call; - call.base = base.qmlBase.stackSlot(); - call.name = base.qmlCoreIndex; - call.argc = calldata.argc; - call.argv = calldata.argv; - bytecodeGenerator->addInstruction(call); - } else if (base.type == Reference::Member) { + if (base.type == Reference::Member) { if (!disable_lookups && useFastLookups) { Instruction::CallPropertyLookup call; call.base = base.propertyBase.stackSlot(); @@ -2363,11 +2347,6 @@ Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs, co return r; } - // This hook allows implementing QML lookup semantics - Reference fallback = fallbackNameLookup(name); - if (fallback.type != Reference::Invalid) - return fallback; - Reference r = Reference::fromName(this, name); r.global = useFastLookups && (resolved.type == Context::ResolvedName::Global || resolved.type == Context::ResolvedName::QmlGlobal); r.qmlGlobal = resolved.type == Context::ResolvedName::QmlGlobal; @@ -2387,12 +2366,6 @@ void Codegen::loadClosure(int closureId) } } -Codegen::Reference Codegen::fallbackNameLookup(const QString &name) -{ - Q_UNUSED(name) - return Reference(); -} - bool Codegen::visit(IdentifierExpression *ast) { if (hasError) @@ -3101,8 +3074,6 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, bytecodeGenerator->addInstruction(yield); } - beginFunctionBodyHook(); - statementList(body); if (!hasError) { @@ -4039,10 +4010,6 @@ bool Codegen::Reference::operator==(const Codegen::Reference &other) const return index == other.index; case Const: return constant == other.constant; - case QmlScopeObject: - case QmlContextObject: - return qmlCoreIndex == other.qmlCoreIndex && qmlNotifyIndex == other.qmlNotifyIndex - && capturePolicy == other.capturePolicy; } return true; } @@ -4100,9 +4067,7 @@ Codegen::Reference Codegen::Reference::storeConsumeAccumulator() const Codegen::Reference Codegen::Reference::baseObject() const { - if (type == Reference::QmlScopeObject || type == Reference::QmlContextObject) { - return Reference::fromStackSlot(codegen, qmlBase.stackSlot()); - } else if (type == Reference::Member) { + if (type == Reference::Member) { RValue rval = propertyBase; if (!rval.isValid()) return Reference::fromConst(codegen, Encode::undefined()); @@ -4187,8 +4152,6 @@ bool Codegen::Reference::storeWipesAccumulator() const case Name: case Member: case Subscript: - case QmlScopeObject: - case QmlContextObject: return true; } } @@ -4268,18 +4231,6 @@ void Codegen::Reference::storeAccumulator() const store.index = elementSubscript.stackSlot(); codegen->bytecodeGenerator->addInstruction(store); } return; - case QmlScopeObject: { - Instruction::StoreScopeObjectProperty store; - store.base = qmlBase; - store.propertyIndex = qmlCoreIndex; - codegen->bytecodeGenerator->addInstruction(store); - } return; - case QmlContextObject: { - Instruction::StoreContextObjectProperty store; - store.base = qmlBase; - store.propertyIndex = qmlCoreIndex; - codegen->bytecodeGenerator->addInstruction(store); - } return; case Invalid: case Accumulator: case Const: @@ -4436,24 +4387,6 @@ QT_WARNING_POP load.base = elementBase; codegen->bytecodeGenerator->addInstruction(load); } return; - case QmlScopeObject: { - Instruction::LoadScopeObjectProperty load; - load.base = qmlBase; - load.propertyIndex = qmlCoreIndex; - load.captureRequired = capturePolicy == CaptureAtRuntime; - codegen->bytecodeGenerator->addInstruction(load); - if (capturePolicy == CaptureAheadOfTime) - codegen->_context->scopeObjectPropertyDependencies.insert(qmlCoreIndex, qmlNotifyIndex); - } return; - case QmlContextObject: { - Instruction::LoadContextObjectProperty load; - load.base = qmlBase; - load.propertyIndex = qmlCoreIndex; - load.captureRequired = capturePolicy == CaptureAtRuntime; - codegen->bytecodeGenerator->addInstruction(load); - if (capturePolicy == CaptureAheadOfTime) - codegen->_context->contextObjectPropertyDependencies.insert(qmlCoreIndex, qmlNotifyIndex); - } return; case Invalid: break; } diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index b1cc4c090a..ad86483132 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -184,9 +184,7 @@ public: Member, Subscript, Import, - QmlScopeObject, - QmlContextObject, - LastLValue = QmlContextObject, + LastLValue = Import, Const } type = Invalid; @@ -223,10 +221,6 @@ public: bool isValid() const { return type != Invalid; } bool loadTriggersSideEffect() const { switch (type) { - case QmlScopeObject: - return capturePolicy != DontCapture; - case QmlContextObject: - return capturePolicy != DontCapture; case Name: case Member: case Subscript: @@ -245,28 +239,6 @@ public: return isStackSlot(); } - enum PropertyCapturePolicy { - /* - We're reading a property from the scope or context object, but it's a CONSTANT property, - so we don't need to register a dependency at all. - */ - DontCapture, - /* - We're reading the property of a QObject, and we know that it's the - scope object or context object, which we know very well. Instead of registering a - property capture every time, we can do that ahead of time and then register all those - captures in one shot in registerQmlDependencies(). - */ - CaptureAheadOfTime, - /* - We're reading the property of a QObject, and we're not quite sure where - the QObject comes from or what it is. So, when reading that property at run-time, - make sure that we capture where we read that property so that if it changes we can - re-evaluate the entire expression. - */ - CaptureAtRuntime - }; - static Reference fromAccumulator(Codegen *cg) { return Reference(cg, Accumulator); } @@ -333,22 +305,6 @@ public: r.isReadonly = true; return r; } - static Reference fromQmlScopeObject(const Reference &base, qint16 coreIndex, qint16 notifyIndex, PropertyCapturePolicy capturePolicy) { - Reference r(base.codegen, QmlScopeObject); - r.qmlBase = base.storeOnStack().stackSlot(); - r.qmlCoreIndex = coreIndex; - r.qmlNotifyIndex = notifyIndex; - r.capturePolicy = capturePolicy; - return r; - } - static Reference fromQmlContextObject(const Reference &base, qint16 coreIndex, qint16 notifyIndex, PropertyCapturePolicy capturePolicy) { - Reference r(base.codegen, QmlContextObject); - r.qmlBase = base.storeOnStack().stackSlot(); - r.qmlCoreIndex = coreIndex; - r.qmlNotifyIndex = notifyIndex; - r.capturePolicy = capturePolicy; - return r; - } static Reference fromThis(Codegen *cg) { Reference r = fromStackSlot(cg, CallData::This); r.isReadonly = true; @@ -403,12 +359,6 @@ public: Moth::StackSlot elementBase; RValue elementSubscript; }; - struct { // QML scope/context object case - Moth::StackSlot qmlBase; - qint16 qmlCoreIndex; - qint16 qmlNotifyIndex; - PropertyCapturePolicy capturePolicy; - }; Moth::StackSlot property; // super property }; QString name; @@ -598,12 +548,6 @@ protected: Reference referenceForPropertyName(const Codegen::Reference &object, AST::PropertyName *name); - // Hooks provided to implement QML lookup semantics - virtual bool canAccelerateGlobalLookups() const { return true; } - virtual Reference fallbackNameLookup(const QString &name); - - virtual void beginFunctionBodyHook() {} - void emitReturn(const Reference &expr); // nodes diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index d63b1fd2b9..1341c91e97 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -73,7 +73,7 @@ QT_BEGIN_NAMESPACE // Bump this whenever the compiler data structures change in an incompatible way. -#define QV4_DATA_STRUCTURE_VERSION 0x19 +#define QV4_DATA_STRUCTURE_VERSION 0x20 class QIODevice; class QQmlPropertyCache; @@ -288,21 +288,10 @@ struct Function quint16_le nRegisters; Location location; - // Qml Extensions Begin - // Array of resolved ID objects - size_t dependingIdObjectsOffset() const { return lineNumberOffset() + nLineNumbers * sizeof(CodeOffsetToLine); } - quint16_le nDependingIdObjects; - quint16_le nDependingContextProperties; - // Array of int pairs (property index and notify index) - size_t dependingContextPropertiesOffset() const { return dependingIdObjectsOffset() + nDependingIdObjects * sizeof(quint32); } - quint16_le nDependingScopeProperties; - // Array of int pairs (property index and notify index) - size_t dependingScopePropertiesOffset() const { return dependingContextPropertiesOffset() + nDependingContextProperties * sizeof(quint32); } - // Qml Extensions End - // Keep all unaligned data at the end quint8 flags; quint8 padding1; + quint16 padding2; // quint32 formalsIndex[nFormals] // quint32 localsIndex[nLocals] @@ -310,9 +299,6 @@ struct Function const quint32_le *formalsTable() const { return reinterpret_cast(reinterpret_cast(this) + formalsOffset); } const quint32_le *localsTable() const { return reinterpret_cast(reinterpret_cast(this) + localsOffset); } const CodeOffsetToLine *lineNumberTable() const { return reinterpret_cast(reinterpret_cast(this) + lineNumberOffset()); } - const quint32_le *qmlIdObjectDependencyTable() const { return reinterpret_cast(reinterpret_cast(this) + dependingIdObjectsOffset()); } - const quint32_le *qmlContextPropertiesDependencyTable() const { return reinterpret_cast(reinterpret_cast(this) + dependingContextPropertiesOffset()); } - const quint32_le *qmlScopePropertiesDependencyTable() const { return reinterpret_cast(reinterpret_cast(this) + dependingScopePropertiesOffset()); } // --- QQmlPropertyCacheCreator interface const quint32_le *formalsBegin() const { return formalsTable(); } @@ -321,11 +307,8 @@ struct Function const char *code() const { return reinterpret_cast(this) + codeOffset; } - inline bool hasQmlDependencies() const { return nDependingIdObjects > 0 || nDependingContextProperties > 0 || nDependingScopeProperties > 0; } - - static int calculateSize(int nFormals, int nLocals, int nLines, int nInnerfunctions, int nIdObjectDependencies, int nPropertyDependencies, int codeSize) { - int trailingData = (nFormals + nLocals + nInnerfunctions + nIdObjectDependencies + - 2 * nPropertyDependencies)*sizeof (quint32) + nLines*sizeof(CodeOffsetToLine); + static int calculateSize(int nFormals, int nLocals, int nLines, int nInnerfunctions, int codeSize) { + int trailingData = (nFormals + nLocals + nInnerfunctions)*sizeof (quint32) + nLines*sizeof(CodeOffsetToLine); size_t size = align(align(sizeof(Function)) + size_t(trailingData)) + align(codeSize); Q_ASSERT(size < INT_MAX); return int(size); @@ -335,7 +318,7 @@ struct Function return (a + 7) & ~size_t(7); } }; -static_assert(sizeof(Function) == 52, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); +static_assert(sizeof(Function) == 48, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); struct Method { enum Type { diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index a3c9347c67..4d85f25d4b 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -427,28 +427,6 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte function->nRegisters = irFunction->registerCountInFunction; - function->nDependingIdObjects = 0; - function->nDependingContextProperties = 0; - function->nDependingScopeProperties = 0; - - if (!irFunction->idObjectDependencies.isEmpty()) { - function->nDependingIdObjects = irFunction->idObjectDependencies.count(); - Q_ASSERT(function->dependingIdObjectsOffset() == currentOffset); - currentOffset += function->nDependingIdObjects * sizeof(quint32); - } - - if (!irFunction->contextObjectPropertyDependencies.isEmpty()) { - function->nDependingContextProperties = irFunction->contextObjectPropertyDependencies.count(); - Q_ASSERT(function->dependingContextPropertiesOffset() == currentOffset); - currentOffset += function->nDependingContextProperties * sizeof(quint32) * 2; - } - - if (!irFunction->scopeObjectPropertyDependencies.isEmpty()) { - function->nDependingScopeProperties = irFunction->scopeObjectPropertyDependencies.count(); - Q_ASSERT(function->dependingScopePropertiesOffset() == currentOffset); - currentOffset += function->nDependingScopeProperties * sizeof(quint32) * 2; - } - function->location.line = irFunction->line; function->location.column = irFunction->column; @@ -468,25 +446,6 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte // write line numbers memcpy(f + function->lineNumberOffset(), irFunction->lineNumberMapping.constData(), irFunction->lineNumberMapping.size()*sizeof(CompiledData::CodeOffsetToLine)); - // write QML dependencies - quint32_le *writtenDeps = (quint32_le *)(f + function->dependingIdObjectsOffset()); - for (int id : irFunction->idObjectDependencies) { - Q_ASSERT(id >= 0); - *writtenDeps++ = static_cast(id); - } - - writtenDeps = (quint32_le *)(f + function->dependingContextPropertiesOffset()); - for (auto property : irFunction->contextObjectPropertyDependencies) { - *writtenDeps++ = property.key(); // property index - *writtenDeps++ = property.value(); // notify index - } - - writtenDeps = (quint32_le *)(f + function->dependingScopePropertiesOffset()); - for (auto property : irFunction->scopeObjectPropertyDependencies) { - *writtenDeps++ = property.key(); // property index - *writtenDeps++ = property.value(); // notify index - } - // write byte code memcpy(f + function->codeOffset, irFunction->code.constData(), irFunction->code.size()); } @@ -683,10 +642,8 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp Context *f = module->functions.at(i); blockAndFunctionOffsets[i] = nextOffset; - const int qmlIdDepsCount = f->idObjectDependencies.count(); - const int qmlPropertyDepsCount = f->scopeObjectPropertyDependencies.count() + f->contextObjectPropertyDependencies.count(); quint32 size = QV4::CompiledData::Function::calculateSize(f->arguments.size(), f->locals.size(), f->lineNumberMapping.size(), f->nestedContexts.size(), - qmlIdDepsCount, qmlPropertyDepsCount, f->code.size()); + f->code.size()); functionSize += size - f->code.size(); nextOffset += size; } diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h index c9e54c0d1b..8f3b60e395 100644 --- a/src/qml/compiler/qv4compilercontext_p.h +++ b/src/qml/compiler/qv4compilercontext_p.h @@ -276,11 +276,6 @@ struct Context { } }; - // Qml extension: - SmallSet idObjectDependencies; - PropertyDependencyMap contextObjectPropertyDependencies; - PropertyDependencyMap scopeObjectPropertyDependencies; - Context(Context *parent, ContextType type) : parent(parent) , contextType(type) diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp index d2e95b83c4..c6c8caffba 100644 --- a/src/qml/compiler/qv4instr_moth.cpp +++ b/src/qml/compiler/qv4instr_moth.cpp @@ -330,26 +330,6 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st d << dumpRegister(property, nFormals); MOTH_END_INSTR(StoreSuperProperty) - MOTH_BEGIN_INSTR(StoreScopeObjectProperty) - d << dumpRegister(base, nFormals) << "[" << propertyIndex << "]"; - MOTH_END_INSTR(StoreScopeObjectProperty) - - MOTH_BEGIN_INSTR(LoadScopeObjectProperty) - d << dumpRegister(base, nFormals) << "[" << propertyIndex << "]" << (captureRequired ? " (capture)" : " (no capture)"); - MOTH_END_INSTR(LoadScopeObjectProperty) - - MOTH_BEGIN_INSTR(StoreContextObjectProperty) - d << dumpRegister(base, nFormals) << "[" << propertyIndex << "]"; - MOTH_END_INSTR(StoreContextObjectProperty) - - MOTH_BEGIN_INSTR(LoadContextObjectProperty) - d << dumpRegister(base, nFormals) << "[" << propertyIndex << "]" << (captureRequired ? " (capture)" : " (no capture)"); - MOTH_END_INSTR(LoadContextObjectProperty) - - MOTH_BEGIN_INSTR(LoadIdObject) - d << dumpRegister(base, nFormals) << "[" << index << "]"; - MOTH_END_INSTR(LoadIdObject) - MOTH_BEGIN_INSTR(Yield) MOTH_END_INSTR(Yield) @@ -396,14 +376,6 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st d << index << dumpArguments(argc, argv, nFormals); MOTH_END_INSTR(CallQmlContextPropertyLookup) - MOTH_BEGIN_INSTR(CallScopeObjectProperty) - d << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals); - MOTH_END_INSTR(CallScopeObjectProperty) - - MOTH_BEGIN_INSTR(CallContextObjectProperty) - d << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals); - MOTH_END_INSTR(CallContextObjectProperty) - MOTH_BEGIN_INSTR(CallWithSpread) d << "new" << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals) << dumpArguments(argc, argv, nFormals); MOTH_END_INSTR(CallWithSpread) @@ -724,14 +696,6 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st d << index; MOTH_END_INSTR(GetTemplateObject) - MOTH_BEGIN_INSTR(LoadQmlContext) - d << dumpRegister(result, nFormals); - MOTH_END_INSTR(LoadQmlContext) - - MOTH_BEGIN_INSTR(LoadQmlImportedScripts) - d << dumpRegister(result, nFormals); - MOTH_END_INSTR(LoadQmlImportedScripts) - MOTH_BEGIN_INSTR(TailCall) d << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals) << dumpArguments(argc, argv, nFormals); MOTH_END_INSTR(TailCall) diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 1c77e6050c..25fca3c0b0 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -91,8 +91,6 @@ QT_BEGIN_NAMESPACE #define INSTR_StoreNameStrict(op) INSTRUCTION(op, StoreNameStrict, 1, name) #define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 1, name) #define INSTR_GetLookup(op) INSTRUCTION(op, GetLookup, 1, index) -#define INSTR_LoadScopeObjectProperty(op) INSTRUCTION(op, LoadScopeObjectProperty, 3, propertyIndex, base, captureRequired) -#define INSTR_LoadContextObjectProperty(op) INSTRUCTION(op, LoadContextObjectProperty, 3, propertyIndex, base, captureRequired) #define INSTR_LoadIdObject(op) INSTRUCTION(op, LoadIdObject, 2, index, base) #define INSTR_Yield(op) INSTRUCTION(op, Yield, 0) #define INSTR_YieldStar(op) INSTRUCTION(op, YieldStar, 0) @@ -102,8 +100,6 @@ QT_BEGIN_NAMESPACE #define INSTR_SetLookup(op) INSTRUCTION(op, SetLookup, 2, index, base) #define INSTR_LoadSuperProperty(op) INSTRUCTION(op, LoadSuperProperty, 1, property) #define INSTR_StoreSuperProperty(op) INSTRUCTION(op, StoreSuperProperty, 1, property) -#define INSTR_StoreScopeObjectProperty(op) INSTRUCTION(op, StoreScopeObjectProperty, 2, base, propertyIndex) -#define INSTR_StoreContextObjectProperty(op) INSTRUCTION(op, StoreContextObjectProperty, 2, base, propertyIndex) #define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 1, base) #define INSTR_StoreElement(op) INSTRUCTION(op, StoreElement, 2, base, index) #define INSTR_CallValue(op) INSTRUCTION(op, CallValue, 3, name, argc, argv) @@ -115,8 +111,6 @@ QT_BEGIN_NAMESPACE #define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 2, argc, argv) #define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 3, index, argc, argv) #define INSTR_CallQmlContextPropertyLookup(op) INSTRUCTION(op, CallQmlContextPropertyLookup, 3, index, argc, argv) -#define INSTR_CallScopeObjectProperty(op) INSTRUCTION(op, CallScopeObjectProperty, 4, name, base, argc, argv) -#define INSTR_CallContextObjectProperty(op) INSTRUCTION(op, CallContextObjectProperty, 4, name, base, argc, argv) #define INSTR_CallWithSpread(op) INSTRUCTION(op, CallWithSpread, 4, func, thisObject, argc, argv) #define INSTR_Construct(op) INSTRUCTION(op, Construct, 3, func, argc, argv) #define INSTR_ConstructWithSpread(op) INSTRUCTION(op, ConstructWithSpread, 3, func, argc, argv) @@ -196,7 +190,6 @@ QT_BEGIN_NAMESPACE #define INSTR_Div(op) INSTRUCTION(op, Div, 1, lhs) #define INSTR_Mod(op) INSTRUCTION(op, Mod, 1, lhs) #define INSTR_Sub(op) INSTRUCTION(op, Sub, 1, lhs) -#define INSTR_LoadQmlContext(op) INSTRUCTION(op, LoadQmlContext, 1, result) #define INSTR_LoadQmlImportedScripts(op) INSTRUCTION(op, LoadQmlImportedScripts, 1, result) #define INSTR_InitializeBlockDeadTemporalZone(op) INSTRUCTION(op, InitializeBlockDeadTemporalZone, 2, firstReg, count) #define INSTR_ThrowOnNullOrUndefined(op) INSTRUCTION(op, ThrowOnNullOrUndefined, 0) @@ -241,11 +234,6 @@ QT_BEGIN_NAMESPACE F(SetLookup) \ F(LoadSuperProperty) \ F(StoreSuperProperty) \ - F(StoreScopeObjectProperty) \ - F(StoreContextObjectProperty) \ - F(LoadScopeObjectProperty) \ - F(LoadContextObjectProperty) \ - F(LoadIdObject) \ F(ConvertThisToObject) \ F(ToObject) \ F(Jump) \ @@ -300,8 +288,6 @@ QT_BEGIN_NAMESPACE F(CallPossiblyDirectEval) \ F(CallGlobalLookup) \ F(CallQmlContextPropertyLookup) \ - F(CallScopeObjectProperty) \ - F(CallContextObjectProperty) \ F(CallWithSpread) \ F(Construct) \ F(ConstructWithSpread) \ @@ -332,8 +318,6 @@ QT_BEGIN_NAMESPACE F(CreateMappedArgumentsObject) \ F(CreateUnmappedArgumentsObject) \ F(CreateRestParameter) \ - F(LoadQmlContext) \ - F(LoadQmlImportedScripts) \ F(Yield) \ F(YieldStar) \ F(Resume) \ diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp index 47cef3b3bd..1e4288e3c9 100644 --- a/src/qml/jit/qv4baselinejit.cpp +++ b/src/qml/jit/qv4baselinejit.cpp @@ -347,66 +347,6 @@ void BaselineJIT::generate_StoreSuperProperty(int property) as->checkException(); } - -void BaselineJIT::generate_StoreScopeObjectProperty(int base, int propertyIndex) -{ - STORE_ACC(); - as->prepareCallWithArgCount(4); - as->passAccumulatorAsArg(3); - as->passInt32AsArg(propertyIndex, 2); - as->passJSSlotAsArg(base, 1); - as->passEngineAsArg(0); - BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_storeQmlScopeObjectProperty, CallResultDestination::Ignore); - as->checkException(); -} - -void BaselineJIT::generate_StoreContextObjectProperty(int base, int propertyIndex) -{ - STORE_ACC(); - as->prepareCallWithArgCount(4); - as->passAccumulatorAsArg(3); - as->passInt32AsArg(propertyIndex, 2); - as->passJSSlotAsArg(base, 1); - as->passEngineAsArg(0); - BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_storeQmlContextObjectProperty, CallResultDestination::Ignore); - as->checkException(); -} - -void BaselineJIT::generate_LoadScopeObjectProperty(int propertyIndex, int base, int captureRequired) -{ - STORE_IP(); - as->prepareCallWithArgCount(4); - as->passInt32AsArg(captureRequired, 3); - as->passInt32AsArg(propertyIndex, 2); - as->passJSSlotAsArg(base, 1); - as->passEngineAsArg(0); - BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_loadQmlScopeObjectProperty, CallResultDestination::InAccumulator); - as->checkException(); -} - -void BaselineJIT::generate_LoadContextObjectProperty(int propertyIndex, int base, int captureRequired) -{ - STORE_IP(); - as->prepareCallWithArgCount(4); - as->passInt32AsArg(captureRequired, 3); - as->passInt32AsArg(propertyIndex, 2); - as->passJSSlotAsArg(base, 1); - as->passEngineAsArg(0); - BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_loadQmlContextObjectProperty, CallResultDestination::InAccumulator); - as->checkException(); -} - -void BaselineJIT::generate_LoadIdObject(int index, int base) -{ - STORE_IP(); - as->prepareCallWithArgCount(3); - as->passInt32AsArg(index, 2); - as->passJSSlotAsArg(base, 1); - as->passEngineAsArg(0); - BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_loadQmlIdObject, CallResultDestination::InAccumulator); - as->checkException(); -} - void BaselineJIT::generate_Yield() { // ##### @@ -536,33 +476,6 @@ void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int as->checkException(); } -void BaselineJIT::generate_CallScopeObjectProperty(int propIdx, int base, int argc, int argv) -{ - STORE_IP(); - as->prepareCallWithArgCount(5); - as->passInt32AsArg(argc, 4); - as->passJSSlotAsArg(argv, 3); - as->passInt32AsArg(propIdx, 2); - as->passJSSlotAsArg(base, 1); - as->passEngineAsArg(0); - BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callQmlScopeObjectProperty, CallResultDestination::InAccumulator); - as->checkException(); -} - -void BaselineJIT::generate_CallContextObjectProperty(int propIdx, int base, int argc, int argv) -{ - STORE_IP(); - as->prepareCallWithArgCount(5); - as->passInt32AsArg(argc, 4); - as->passJSSlotAsArg(argv, 3); - as->passInt32AsArg(propIdx, 2); - as->passJSSlotAsArg(base, 1); - as->passEngineAsArg(0); - BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callQmlContextObjectProperty, CallResultDestination::InAccumulator); - as->checkException(); -} - - void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv) { STORE_IP(); @@ -981,22 +894,6 @@ void BaselineJIT::generate_Sub(int lhs) { as->sub(lhs); } // as->checkException(); //} -void BaselineJIT::generate_LoadQmlContext(int result) -{ - as->prepareCallWithArgCount(1); - as->passEngineAsArg(0); - BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_loadQmlContext, CallResultDestination::InAccumulator); - as->storeReg(result); -} - -void BaselineJIT::generate_LoadQmlImportedScripts(int result) -{ - as->prepareCallWithArgCount(1); - as->passEngineAsArg(0); - BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_loadQmlImportedScripts, CallResultDestination::InAccumulator); - as->storeReg(result); -} - void BaselineJIT::generate_InitializeBlockDeadTemporalZone(int firstReg, int count) { as->loadValue(Value::emptyValue().rawValue()); diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h index 4db1eb1806..6646eb713e 100644 --- a/src/qml/jit/qv4baselinejit_p.h +++ b/src/qml/jit/qv4baselinejit_p.h @@ -108,15 +108,6 @@ public: void generate_SetLookup(int index, int base) override; void generate_LoadSuperProperty(int property) override; void generate_StoreSuperProperty(int property) override; - void generate_StoreScopeObjectProperty(int base, - int propertyIndex) override; - void generate_StoreContextObjectProperty(int base, - int propertyIndex) override; - void generate_LoadScopeObjectProperty(int propertyIndex, int base, - int captureRequired) override; - void generate_LoadContextObjectProperty(int propertyIndex, int base, - int captureRequired) override; - void generate_LoadIdObject(int index, int base) override; void generate_Yield() override; void generate_YieldStar() override; void generate_Resume(int) override; @@ -130,8 +121,6 @@ public: void generate_CallPossiblyDirectEval(int argc, int argv) override; void generate_CallGlobalLookup(int index, int argc, int argv) override; void generate_CallQmlContextPropertyLookup(int index, int argc, int argv) override; - void generate_CallScopeObjectProperty(int propIdx, int base, int argc, int argv) override; - void generate_CallContextObjectProperty(int propIdx, int base, int argc, int argv) override; void generate_CallWithSpread(int func, int thisObject, int argc, int argv) override; void generate_TailCall(int func, int thisObject, int argc, int argv) override; void generate_Construct(int func, int argc, int argv) override; @@ -213,8 +202,6 @@ public: void generate_Div(int lhs) override; void generate_Mod(int lhs) override; void generate_Sub(int lhs) override; - void generate_LoadQmlContext(int result) override; - void generate_LoadQmlImportedScripts(int result) override; void generate_InitializeBlockDeadTemporalZone(int firstReg, int count) override; void generate_ThrowOnNullOrUndefined() override; void generate_GetTemplateObject(int index) override; diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index 941c37de5b..51a9b92967 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -78,7 +78,6 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, , codeData(function->code()) , jittedCode(nullptr) , codeRef(nullptr) - , hasQmlDependencies(function->hasQmlDependencies()) { Scope scope(engine); Scoped ic(scope, engine->internalClasses(EngineBase::Class_CallContext)); diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 029dd7786b..62c5d24fc4 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -80,7 +80,6 @@ struct Q_QML_EXPORT Function { Heap::InternalClass *internalClass; uint nFormals; int interpreterCallCount = 0; - bool hasQmlDependencies; bool isEval = false; Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 711c910906..053581226f 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -233,7 +233,7 @@ QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QObject return result; } -ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired) +ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property) { QQmlData::flushPendingBinding(object, QQmlPropertyIndex(property->coreIndex())); @@ -259,7 +259,7 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : nullptr; - if (captureRequired && ep && ep->propertyCapture && !property->isConstant()) + if (ep && ep->propertyCapture && !property->isConstant()) ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex()); if (property->isVarProperty()) { @@ -357,26 +357,6 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String return getProperty(v4, d()->object(), result); } -ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired) -{ - if (QQmlData::wasDeleted(object)) - return QV4::Encode::null(); - QQmlData *ddata = QQmlData::get(object, /*create*/false); - if (!ddata) - return QV4::Encode::undefined(); - - if (Q_UNLIKELY(!ddata->propertyCache)) { - ddata->propertyCache = QQmlEnginePrivate::get(engine)->cache(object->metaObject()); - ddata->propertyCache->addref(); - } - - QQmlPropertyCache *cache = ddata->propertyCache; - Q_ASSERT(cache); - QQmlPropertyData *property = cache->property(propertyIndex); - Q_ASSERT(property); // We resolved this property earlier, so it better exist! - return getProperty(engine, object, property, captureRequired); -} - ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty) { if (QQmlData::wasDeleted(object)) { @@ -873,7 +853,7 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E if (!ddata || !ddata->propertyCache) { QQmlPropertyData local; QQmlPropertyData *property = QQmlPropertyCache::property(engine->jsEngine(), qobj, name, qmlContext, local); - return getProperty(engine, qobj, property, /*captureRequired*/true); + return getProperty(engine, qobj, property); } QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobj, qmlContext); @@ -919,7 +899,7 @@ ReturnedValue QObjectWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engi return revertLookup(); QQmlPropertyData *property = lookup->qobjectLookup.propertyData; - return getProperty(engine, qobj, property, /*captureRequired = */true); + return getProperty(engine, qobj, property); } bool QObjectWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index a09e7b6e95..471f352c2a 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -176,13 +176,12 @@ struct Q_QML_EXPORT QObjectWrapper : public Object using Object::get; - static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired); static void setProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, const Value &value); void setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value); void destroyObject(bool lastCall); - static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired = true); + static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property); static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup); static ReturnedValue lookupGetter(Lookup *l, ExecutionEngine *engine, const Value &object); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 7163a51af1..85d06bcabe 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1457,38 +1457,6 @@ ReturnedValue Runtime::method_callWithReceiver(ExecutionEngine *engine, const Va return static_cast(func).call(thisObject, argv, argc); } -ReturnedValue Runtime::method_callQmlScopeObjectProperty(ExecutionEngine *engine, Value *base, - int propertyIndex, Value *argv, int argc) -{ - Scope scope(engine); - ScopedFunctionObject fo(scope, method_loadQmlScopeObjectProperty(engine, *base, propertyIndex, - /*captureRequired*/true)); - if (!fo) { - QString error = QStringLiteral("Property '%1' of scope object is not a function").arg(propertyIndex); - return engine->throwTypeError(error); - } - - QObject *qmlScopeObj = static_cast(base)->d()->qml()->scopeObject; - ScopedValue qmlScopeValue(scope, QObjectWrapper::wrap(engine, qmlScopeObj)); - return fo->call(qmlScopeValue, argv, argc); -} - -ReturnedValue Runtime::method_callQmlContextObjectProperty(ExecutionEngine *engine, Value *base, - int propertyIndex, Value *argv, int argc) -{ - Scope scope(engine); - ScopedFunctionObject fo(scope, method_loadQmlContextObjectProperty(engine, *base, propertyIndex, - /*captureRequired*/true)); - if (!fo) { - QString error = QStringLiteral("Property '%1' of context object is not a function").arg(propertyIndex); - return engine->throwTypeError(error); - } - - QObject *qmlContextObj = static_cast(base)->d()->qml()->context->contextData()->contextObject; - ScopedValue qmlContextValue(scope, QObjectWrapper::wrap(engine, qmlContextObj)); - return fo->call(qmlContextValue, argv, argc); -} - struct CallArgs { Value *argv; int argc; @@ -1904,65 +1872,11 @@ QV4::ReturnedValue Runtime::method_createRestParameter(ExecutionEngine *engine, return engine->newArrayObject(values, nValues)->asReturnedValue(); } - -ReturnedValue Runtime::method_loadQmlContext(NoThrowEngine *engine) -{ - Heap::QmlContext *ctx = engine->qmlContext(); - Q_ASSERT(ctx); - return ctx->asReturnedValue(); -} - ReturnedValue Runtime::method_regexpLiteral(ExecutionEngine *engine, int id) { Heap::RegExpObject *ro = engine->newRegExpObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeRegularExpressions[id].as()); return ro->asReturnedValue(); } - -ReturnedValue Runtime::method_loadQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired) -{ - const QmlContext &c = static_cast(context); - return QV4::QObjectWrapper::getProperty(engine, c.d()->qml()->scopeObject, propertyIndex, captureRequired); -} - -ReturnedValue Runtime::method_loadQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired) -{ - const QmlContext &c = static_cast(context); - return QV4::QObjectWrapper::getProperty(engine, (*c.d()->qml()->context)->contextObject, propertyIndex, captureRequired); -} - -ReturnedValue Runtime::method_loadQmlIdObject(ExecutionEngine *engine, const Value &c, uint index) -{ - const QmlContext &qmlContext = static_cast(c); - QQmlContextData *context = *qmlContext.d()->qml()->context; - if (!context || index >= (uint)context->idValueCount) - return Encode::undefined(); - - QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : nullptr; - if (ep && ep->propertyCapture) - ep->propertyCapture->captureProperty(&context->idValues[index].bindings); - - return QObjectWrapper::wrap(engine, context->idValues[index].data()); -} - -void Runtime::method_storeQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value) -{ - const QmlContext &c = static_cast(context); - return QV4::QObjectWrapper::setProperty(engine, c.d()->qml()->scopeObject, propertyIndex, value); -} - -void Runtime::method_storeQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value) -{ - const QmlContext &c = static_cast(context); - return QV4::QObjectWrapper::setProperty(engine, (*c.d()->qml()->context)->contextObject, propertyIndex, value); -} - -ReturnedValue Runtime::method_loadQmlImportedScripts(NoThrowEngine *engine) -{ - QQmlContextData *context = engine->callingQmlContext(); - if (!context) - return Encode::undefined(); - return context->importedScripts.value(); -} #endif // V4_BOOTSTRAP ReturnedValue Runtime::method_uMinus(const Value &value) diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index aa4ac27621..4b3905c56f 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -195,19 +195,7 @@ struct ExceptionCheck { F(Bool, compareInstanceof, (ExecutionEngine *engine, const Value &left, const Value &right)) \ F(Bool, compareIn, (ExecutionEngine *engine, const Value &left, const Value &right)) \ \ - F(ReturnedValue, regexpLiteral, (ExecutionEngine *engine, int id)) \ - \ - /* qml */ \ - F(ReturnedValue, loadQmlContext, (NoThrowEngine *engine)) \ - F(ReturnedValue, loadQmlImportedScripts, (NoThrowEngine *engine)) \ - F(ReturnedValue, loadQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \ - F(ReturnedValue, loadQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \ - F(ReturnedValue, loadQmlIdObject, (ExecutionEngine *engine, const Value &context, uint index)) \ - F(ReturnedValue, callQmlScopeObjectProperty, (ExecutionEngine *engine, Value *base, int propertyIndex, Value *argv, int argc)) \ - F(ReturnedValue, callQmlContextObjectProperty, (ExecutionEngine *engine, Value *base, int propertyIndex, Value *argv, int argc)) \ - \ - F(void, storeQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)) \ - F(void, storeQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)) \ + F(ReturnedValue, regexpLiteral, (ExecutionEngine *engine, int id)) struct Q_QML_PRIVATE_EXPORT Runtime { Runtime(); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 2d9337b03e..ea2217499f 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -646,37 +646,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, CHECK_EXCEPTION; MOTH_END_INSTR(StoreSuperProperty) - MOTH_BEGIN_INSTR(StoreScopeObjectProperty) - STORE_ACC(); - Runtime::method_storeQmlScopeObjectProperty(engine, STACK_VALUE(base), propertyIndex, accumulator); - CHECK_EXCEPTION; - MOTH_END_INSTR(StoreScopeObjectProperty) - - MOTH_BEGIN_INSTR(LoadScopeObjectProperty) - STORE_IP(); - acc = Runtime::method_loadQmlScopeObjectProperty(engine, STACK_VALUE(base), propertyIndex, captureRequired); - CHECK_EXCEPTION; - MOTH_END_INSTR(LoadScopeObjectProperty) - - MOTH_BEGIN_INSTR(StoreContextObjectProperty) - STORE_IP(); - STORE_ACC(); - Runtime::method_storeQmlContextObjectProperty(engine, STACK_VALUE(base), propertyIndex, accumulator); - CHECK_EXCEPTION; - MOTH_END_INSTR(StoreContextObjectProperty) - - MOTH_BEGIN_INSTR(LoadContextObjectProperty) - STORE_IP(); - acc = Runtime::method_loadQmlContextObjectProperty(engine, STACK_VALUE(base), propertyIndex, captureRequired); - CHECK_EXCEPTION; - MOTH_END_INSTR(LoadContextObjectProperty) - - MOTH_BEGIN_INSTR(LoadIdObject) - STORE_IP(); - acc = Runtime::method_loadQmlIdObject(engine, STACK_VALUE(base), index); - CHECK_EXCEPTION; - MOTH_END_INSTR(LoadIdObject) - MOTH_BEGIN_INSTR(Yield) frame->yield = code; frame->yieldIsIterator = false; @@ -794,18 +763,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, CHECK_EXCEPTION; MOTH_END_INSTR(CallQmlContextPropertyLookup) - MOTH_BEGIN_INSTR(CallScopeObjectProperty) - STORE_IP(); - acc = Runtime::method_callQmlScopeObjectProperty(engine, stack + base, name, stack + argv, argc); - CHECK_EXCEPTION; - MOTH_END_INSTR(CallScopeObjectProperty) - - MOTH_BEGIN_INSTR(CallContextObjectProperty) - STORE_IP(); - acc = Runtime::method_callQmlContextObjectProperty(engine, stack + base, name, stack + argv, argc); - CHECK_EXCEPTION; - MOTH_END_INSTR(CallContextObjectProperty) - MOTH_BEGIN_INSTR(CallWithSpread) STORE_IP(); acc = Runtime::method_callWithSpread(engine, STACK_VALUE(func), STACK_VALUE(thisObject), stack + argv, argc); @@ -1425,14 +1382,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, #endif // QT_CONFIG(qml_debug) MOTH_END_INSTR(Debug) - MOTH_BEGIN_INSTR(LoadQmlContext) - STACK_VALUE(result) = Runtime::method_loadQmlContext(static_cast(engine)); - MOTH_END_INSTR(LoadQmlContext) - - MOTH_BEGIN_INSTR(LoadQmlImportedScripts) - STACK_VALUE(result) = Runtime::method_loadQmlImportedScripts(static_cast(engine)); - MOTH_END_INSTR(LoadQmlImportedScripts) - handleUnwind: Q_ASSERT(engine->hasException || frame->unwindLevel); if (!frame->unwindHandler) { diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index eea3670191..7f0442d034 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -260,8 +260,6 @@ protected: } else { clearError(); } - - cancelPermanentGuards(); } ep->dereferenceScarceResources(); @@ -643,24 +641,22 @@ QVector QQmlBinding::dependencies() const if (!m_target.data()) return dependencies; - for (const auto &guardList : { permanentGuards, activeGuards }) { - for (QQmlJavaScriptExpressionGuard *guard = guardList.first(); guard; guard = guardList.next(guard)) { - if (guard->signalIndex() == -1) // guard's sender is a QQmlNotifier, not a QObject*. - continue; + for (QQmlJavaScriptExpressionGuard *guard = activeGuards.first(); guard; guard = activeGuards.next(guard)) { + if (guard->signalIndex() == -1) // guard's sender is a QQmlNotifier, not a QObject*. + continue; - QObject *senderObject = guard->senderAsObject(); - if (!senderObject) - continue; + QObject *senderObject = guard->senderAsObject(); + if (!senderObject) + continue; - const QMetaObject *senderMeta = senderObject->metaObject(); - if (!senderMeta) - continue; + const QMetaObject *senderMeta = senderObject->metaObject(); + if (!senderMeta) + continue; - for (int i = 0; i < senderMeta->propertyCount(); i++) { - QMetaProperty property = senderMeta->property(i); - if (property.notifySignalIndex() == QMetaObjectPrivate::signal(senderMeta, guard->signalIndex()).methodIndex()) { - dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(senderObject->metaObject()->property(i).name()))); - } + for (int i = 0; i < senderMeta->propertyCount(); i++) { + QMetaProperty property = senderMeta->property(i); + if (property.notifySignalIndex() == QMetaObjectPrivate::signal(senderMeta, guard->signalIndex()).methodIndex()) { + dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(senderObject->metaObject()->property(i).name()))); } } } @@ -670,7 +666,7 @@ QVector QQmlBinding::dependencies() const bool QQmlBinding::hasDependencies() const { - return !permanentGuards.isEmpty() || !activeGuards.isEmpty() || translationsCaptured(); + return !activeGuards.isEmpty() || translationsCaptured(); } class QObjectPointerBinding: public QQmlNonbindingBinding diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 380163202a..9a3a5218e0 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -109,7 +109,6 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression() } clearActiveGuards(); - clearPermanentGuards(); clearError(); if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion. m_scopeObject.asT2()->_s = nullptr; @@ -118,12 +117,8 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression() void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v) { activeGuards.setFlagValue(v); - permanentGuards.setFlagValue(v); - if (!v) { + if (!v) clearActiveGuards(); - clearPermanentGuards(); - m_permanentDependenciesRegistered = false; - } } void QQmlJavaScriptExpression::resetNotifyOnValueChanged() @@ -216,10 +211,6 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b QV4::ReturnedValue res = v4Function->call(&callData->thisObject, callData->args, callData->argc(), static_cast(m_qmlScope.valueRef())); QV4::Scope scope(v4); QV4::ScopedValue result(scope, res); - if (v4Function->hasQmlDependencies) { - QV4::Heap::QmlContext *qc = m_qmlScope.as()->d(); - QQmlPropertyCapture::registerQmlDependencies(qc, v4, v4Function->compiledFunction); - } if (scope.hasException()) { if (watcher.wasDeleted()) @@ -254,7 +245,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b return result->asReturnedValue(); } -void QQmlPropertyCapture::captureProperty(QQmlNotifier *n, Duration duration) +void QQmlPropertyCapture::captureProperty(QQmlNotifier *n) { if (watcher->wasDeleted()) return; @@ -274,17 +265,14 @@ void QQmlPropertyCapture::captureProperty(QQmlNotifier *n, Duration duration) g->connect(n); } - if (duration == Permanently) - expression->permanentGuards.prepend(g); - else - expression->activeGuards.prepend(g); + expression->activeGuards.prepend(g); } /*! \internal \a n is in the signal index range (see QObjectPrivate::signalIndex()). */ -void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, Duration duration, bool doNotify) +void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, bool doNotify) { if (watcher->wasDeleted()) return; @@ -323,61 +311,8 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, Duration dur g->connect(o, n, engine, doNotify); } - if (duration == Permanently) - expression->permanentGuards.prepend(g); - else - expression->activeGuards.prepend(g); - } -} - -void QQmlPropertyCapture::registerQmlDependencies(QV4::Heap::QmlContext *context, const QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction) -{ - // Let the caller check and avoid the function call :) - Q_ASSERT(compiledFunction->hasQmlDependencies()); - - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->qmlEngine()); - if (!ep) - return; - QQmlPropertyCapture *capture = ep->propertyCapture; - if (!capture || capture->watcher->wasDeleted()) - return; - - if (capture->expression->m_permanentDependenciesRegistered) - return; - - capture->expression->m_permanentDependenciesRegistered = true; - - QV4::Heap::QQmlContextWrapper *wrapper = context->qml(); - QQmlContextData *qmlContext = wrapper->context->contextData(); - - const quint32_le *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable(); - const int idObjectDependencyCount = compiledFunction->nDependingIdObjects; - for (int i = 0; i < idObjectDependencyCount; ++i, ++idObjectDependency) { - Q_ASSERT(int(*idObjectDependency) < qmlContext->idValueCount); - capture->captureProperty(&qmlContext->idValues[*idObjectDependency].bindings, - QQmlPropertyCapture::Permanently); - } - - Q_ASSERT(qmlContext->contextObject); - const quint32_le *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable(); - const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties; - for (int i = 0; i < contextPropertyDependencyCount; ++i) { - const int propertyIndex = *contextPropertyDependency++; - const int notifyIndex = *contextPropertyDependency++; - capture->captureProperty(qmlContext->contextObject, propertyIndex, notifyIndex, - QQmlPropertyCapture::Permanently); - } - - QObject *scopeObject = wrapper->scopeObject; - const quint32_le *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable(); - const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties; - for (int i = 0; i < scopePropertyDependencyCount; ++i) { - const int propertyIndex = *scopePropertyDependency++; - const int notifyIndex = *scopePropertyDependency++; - capture->captureProperty(scopeObject, propertyIndex, notifyIndex, - QQmlPropertyCapture::Permanently); + expression->activeGuards.prepend(g); } - } QQmlError QQmlJavaScriptExpression::error(QQmlEngine *engine) const @@ -471,13 +406,6 @@ void QQmlJavaScriptExpression::clearActiveGuards() g->Delete(); } -void QQmlJavaScriptExpression::clearPermanentGuards() -{ - m_permanentDependenciesRegistered = false; - while (QQmlJavaScriptExpressionGuard *g = permanentGuards.takeFirst()) - g->Delete(); -} - void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *e, void **) { QQmlJavaScriptExpression *expression = diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index de3fba0774..453c8ab8a8 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -144,7 +144,6 @@ public: QQmlError error(QQmlEngine *) const; void clearError(); void clearActiveGuards(); - void clearPermanentGuards(); QQmlDelayedError *delayedError(); static QV4::ReturnedValue evalFunction(QQmlContextData *ctxt, QObject *scope, @@ -153,14 +152,6 @@ public: protected: void createQmlBinding(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, quint16 line); - void cancelPermanentGuards() const - { - if (m_permanentDependenciesRegistered) { - for (QQmlJavaScriptExpressionGuard *it = permanentGuards.first(); it; it = permanentGuards.next(it)) - it->cancelNotify(); - } - } - void setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f); void setCompilationUnit(const QQmlRefPointer &compilationUnit); @@ -169,7 +160,6 @@ protected: // activeGuards:flag2 - useSharedContext QBiPointer m_scopeObject; QForwardFieldList activeGuards; - QForwardFieldList permanentGuards; void setTranslationsCaptured(bool captured) { m_error.setFlagValue(captured); } bool translationsCaptured() const { return m_error.flag(); } @@ -186,7 +176,6 @@ private: QQmlContextData *m_context; QQmlJavaScriptExpression **m_prevExpression; QQmlJavaScriptExpression *m_nextExpression; - bool m_permanentDependenciesRegistered = false; QV4::PersistentValue m_qmlScope; QQmlRefPointer m_compilationUnit; @@ -204,14 +193,8 @@ public: Q_ASSERT(errorString == nullptr); } - enum Duration { - OnlyOnce, - Permanently - }; - - static void registerQmlDependencies(QV4::Heap::QmlContext *context, const QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction); - void captureProperty(QQmlNotifier *, Duration duration = OnlyOnce); - void captureProperty(QObject *, int, int, Duration duration = OnlyOnce, bool doNotify = true); + void captureProperty(QQmlNotifier *); + void captureProperty(QObject *, int, int, bool doNotify = true); void captureTranslation() { translationCaptured = true; } QQmlEngine *engine; diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index 006825cc93..69b7876cf6 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -1605,8 +1605,7 @@ ReturnedValue ModelObject::virtualGet(const Managed *m, PropertyKey id, const Va if (QQmlEngine *qmlEngine = that->engine()->qmlEngine()) { QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlEngine); if (ep && ep->propertyCapture) - ep->propertyCapture->captureProperty(that->object(), -1, role->index, - QQmlPropertyCapture::OnlyOnce, false); + ep->propertyCapture->captureProperty(that->object(), -1, role->index, /*doNotify=*/ false); } const int elementIndex = that->d()->elementIndex(); diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp index 1bfc831dac..e8583996bf 100644 --- a/tools/qmlcachegen/qmlcachegen.cpp +++ b/tools/qmlcachegen/qmlcachegen.cpp @@ -199,16 +199,14 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti QmlIR::JSCodeGen v4CodeGen(irDocument.code, &irDocument.jsGenerator, &irDocument.jsModule, &irDocument.jsParserEngine, irDocument.program, - /*import cache*/nullptr, &irDocument.jsGenerator.stringTable, illegalNames); + &irDocument.jsGenerator.stringTable, illegalNames); v4CodeGen.setUseFastLookups(false); // Disable lookups in non-standalone (aka QML) mode for (QmlIR::Object *object: qAsConst(irDocument.objects)) { if (object->functionsAndExpressions->count == 0) continue; QList functionsToCompile; - for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next) { - foe->disableAcceleratedLookups = true; + for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next) functionsToCompile << *foe; - } const QVector runtimeFunctionIndices = v4CodeGen.generateJSCodeForFunctionsAndBindings(functionsToCompile); QList jsErrors = v4CodeGen.errors(); if (!jsErrors.isEmpty()) { @@ -306,8 +304,7 @@ static bool compileJSFile(const QString &inputFileName, const QString &inputFile { QmlIR::JSCodeGen v4CodeGen(irDocument.code, &irDocument.jsGenerator, &irDocument.jsModule, &irDocument.jsParserEngine, - irDocument.program, /*import cache*/nullptr, - &irDocument.jsGenerator.stringTable, illegalNames); + irDocument.program, &irDocument.jsGenerator.stringTable, illegalNames); v4CodeGen.setUseFastLookups(false); // Disable lookups in non-standalone (aka QML) mode v4CodeGen.generateFromProgram(inputFileName, inputFileUrl, sourceCode, program, &irDocument.jsModule, QV4::Compiler::ContextType::ScriptImportedByQML); -- cgit v1.2.3 From 69d76d59cec0dcff4c52eef24e779fbef14beeca Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 19 Mar 2019 13:39:10 +0100 Subject: V4: Don't mark InternalClass::parent when garbage collecting The parent pointer is only kept so that we can update the parent's transitions when removing a child. There is no need to keep the parents alive for the children. Fixes: QTBUG-58559 Change-Id: Ia28183966bde6d478ca030fe11195489925dfc13 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4internalclass.cpp | 12 +++++++----- tests/auto/qml/qv4mm/tst_qv4mm.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index ddb8542e07..9906e2b1a0 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -257,11 +257,15 @@ void InternalClass::init(Heap::InternalClass *other) void InternalClass::destroy() { -#ifndef QT_NO_DEBUG for (const auto &t : transitions) { - Q_ASSERT(!t.lookup || !t.lookup->isMarked()); - } + if (t.lookup) { +#ifndef QT_NO_DEBUG + Q_ASSERT(t.lookup->parent == this); #endif + t.lookup->parent = nullptr; + } + } + if (parent && parent->engine && parent->isMarked()) parent->removeChildEntry(this); @@ -659,8 +663,6 @@ void InternalClass::markObjects(Heap::Base *b, MarkStack *stack) Heap::InternalClass *ic = static_cast(b); if (ic->prototype) ic->prototype->mark(stack); - if (ic->parent) - ic->parent->mark(stack); ic->nameMap.mark(stack); } diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp index 578a47d5fa..b57b716ed6 100644 --- a/tests/auto/qml/qv4mm/tst_qv4mm.cpp +++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp @@ -33,6 +33,7 @@ #include #include +#include #include "../../shared/util.h" @@ -46,6 +47,7 @@ private slots: void gcStats(); void multiWrappedQObjects(); void accessParentOnDestruction(); + void clearICParent(); }; void tst_qv4mm::gcStats() @@ -108,6 +110,30 @@ void tst_qv4mm::accessParentOnDestruction() QCOMPARE(obj->property("destructions").toInt(), 100); } +void tst_qv4mm::clearICParent() +{ + QJSEngine engine; + QJSValue value = engine.evaluate( + "(function() {\n" + " var test = Object.create(null);\n" + " for (var i = 0; i < 100; i++)\n" + " test[(\"key_\"+i)] = true;\n" + " for (var i = 0; i < 100; i++)\n" + " delete test[\"key_\" + i];\n" + " return test;\n" + "})();" + ); + engine.collectGarbage(); + QV4::Value *v4Value = QJSValuePrivate::getValue(&value); + QVERIFY(v4Value); + QV4::Heap::Object *v4Object = v4Value->toObject(engine.handle()); + QVERIFY(v4Object); + + // It should garbage collect the parents of the internalClass, + // as those aren't used anywhere else. + QCOMPARE(v4Object->internalClass->parent, nullptr); +} + QTEST_MAIN(tst_qv4mm) #include "tst_qv4mm.moc" -- cgit v1.2.3 From 710580aa84c5c3273e883d9e650f3159ad8250f3 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 3 Jan 2019 17:00:36 +0100 Subject: Accelerate access to singletons and imported scripts Use a dedicated lookup type to provide super fast access to engine wide singleton objects as well as scripts Task-number: QTBUG-69898 Change-Id: Ie430f48f6576a9171018ef18742dcf6b2adb4310 Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4lookup_p.h | 9 ++++++ src/qml/jsruntime/qv4qmlcontext.cpp | 55 +++++++++++++++++++++++++++++++++++-- src/qml/jsruntime/qv4qmlcontext_p.h | 4 ++- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index e4d9ad8328..2384a1194e 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -129,6 +129,15 @@ struct Lookup { QQmlPropertyCache *propertyCache; QQmlPropertyData *propertyData; } qgadgetLookup; + struct { + quintptr unused1; + quintptr unused2; + int scriptIndex; + } qmlContextScriptLookup; + struct { + Heap::Object *singleton; + quintptr unused; + } qmlContextSingletonLookup; }; uint nameIndex; diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index ae458c604a..ab80e6bc45 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -79,7 +79,7 @@ void Heap::QQmlContextWrapper::destroy() Object::destroy(); } -ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *resource, PropertyKey id, const Value *receiver, bool *hasProperty, Value *base) +ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *resource, PropertyKey id, const Value *receiver, bool *hasProperty, Value *base, Lookup *lookup) { if (!id.isString()) return Object::virtualGet(resource, id, receiver, hasProperty); @@ -159,6 +159,8 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r // Note: The scope object is only a QADMO for example when somebody registers a QQmlPropertyMap // sub-class as QML type and then instantiates it in .qml. if (scopeObject && QQmlPropertyCache::isDynamicMetaObject(scopeObject->metaObject())) { + // all bets are off, so don't try to optimize any lookups + lookup = nullptr; if (performGobalLookUp()) return result->asReturnedValue(); } @@ -171,11 +173,35 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r if (hasProperty) *hasProperty = true; if (r.scriptIndex != -1) { + if (lookup) { + lookup->qmlContextScriptLookup.scriptIndex = r.scriptIndex; + lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupScript; + return lookup->qmlContextPropertyGetter(lookup, v4, base); + } QV4::ScopedObject scripts(scope, context->importedScripts.valueRef()); if (scripts) return scripts->get(r.scriptIndex); return QV4::Encode::null(); } else if (r.type.isValid()) { + if (lookup) { + if (r.type.isSingleton()) { + QQmlEngine *e = v4->qmlEngine(); + QQmlType::SingletonInstanceInfo *siinfo = r.type.singletonInstanceInfo(); + siinfo->init(e); + if (siinfo->qobjectApi(e)) { + lookup->qmlContextSingletonLookup.singleton = + static_cast( + Value::fromReturnedValue( + QQmlTypeWrapper::create(v4, nullptr, r.type) + ).heapObject()); + } else { + QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e))); + lookup->qmlContextSingletonLookup.singleton = o->d(); + } + lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupSingleton; + return lookup->qmlContextPropertyGetter(lookup, v4, base); + } + } return QQmlTypeWrapper::create(v4, scopeObject, r.type); } else if (r.importNamespace) { return QQmlTypeWrapper::create(v4, scopeObject, context->imports, r.importNamespace); @@ -361,12 +387,37 @@ ReturnedValue QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(Lookup * Scoped qmlContext(scope, engine->qmlContext()->qml()); bool hasProperty = false; ScopedValue result(scope, QQmlContextWrapper::getPropertyAndBase(qmlContext, name, /*receiver*/nullptr, - &hasProperty, base)); + &hasProperty, base, l)); if (!hasProperty) return engine->throwReferenceError(name.toQString()); return result->asReturnedValue(); } +ReturnedValue QQmlContextWrapper::lookupScript(Lookup *l, ExecutionEngine *engine, Value *base) +{ + Q_UNUSED(base) + Scope scope(engine); + Scoped qmlContext(scope, engine->qmlContext()); + if (!qmlContext) + return QV4::Encode::null(); + + QQmlContextData *context = qmlContext->qmlContext(); + if (!context) + return QV4::Encode::null(); + + QV4::ScopedObject scripts(scope, context->importedScripts.valueRef()); + if (!scripts) + return QV4::Encode::null(); + return scripts->get(l->qmlContextScriptLookup.scriptIndex); +} + +ReturnedValue QQmlContextWrapper::lookupSingleton(Lookup *l, ExecutionEngine *engine, Value *base) +{ + Q_UNUSED(engine) + Q_UNUSED(base) + return Value::fromHeapObject(l->qmlContextSingletonLookup.singleton).asReturnedValue(); +} + void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml) { Heap::ExecutionContext::init(Heap::ExecutionContext::Type_QmlContext); diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index f704280bf4..5eacea5830 100644 --- a/src/qml/jsruntime/qv4qmlcontext_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -100,11 +100,13 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object inline QQmlContextData *getContext() const { return *d()->context; } static ReturnedValue getPropertyAndBase(const QQmlContextWrapper *resource, PropertyKey id, const Value *receiver, - bool *hasProperty, Value *base); + bool *hasProperty, Value *base, Lookup *lookup = nullptr); static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty); static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver); static ReturnedValue resolveQmlContextPropertyLookupGetter(Lookup *l, ExecutionEngine *engine, Value *base); + static ReturnedValue lookupScript(Lookup *l, ExecutionEngine *engine, Value *base); + static ReturnedValue lookupSingleton(Lookup *l, ExecutionEngine *engine, Value *base); }; struct Q_QML_EXPORT QmlContext : public ExecutionContext -- cgit v1.2.3 From 78a2887d8c5d866fc430f197abea6bb31293c4b1 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 4 Jan 2019 10:41:02 +0100 Subject: Accelerate access to id objects in lookups Task-number: QTBUG-69898 Change-Id: Ifbd9b3bf8d4b0c82b4c3933912e61eea8e0bb987 Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4lookup_p.h | 5 +++++ src/qml/jsruntime/qv4qmlcontext.cpp | 35 +++++++++++++++++++++++++++++++++-- src/qml/jsruntime/qv4qmlcontext_p.h | 1 + 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 2384a1194e..68da224273 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -138,6 +138,11 @@ struct Lookup { Heap::Object *singleton; quintptr unused; } qmlContextSingletonLookup; + struct { + quintptr unused1; + quintptr unused2; + int objectId; + } qmlContextIdObjectLookup; }; uint nameIndex; diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index ab80e6bc45..3d9e1cc0f8 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -223,11 +223,17 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r if (propertyIdx != -1) { if (propertyIdx < context->idValueCount) { + if (hasProperty) + *hasProperty = true; + + if (lookup) { + lookup->qmlContextIdObjectLookup.objectId = propertyIdx; + lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupIdObject; + return lookup->qmlContextPropertyGetter(lookup, v4, base); + } if (ep->propertyCapture) ep->propertyCapture->captureProperty(&context->idValues[propertyIdx].bindings); - if (hasProperty) - *hasProperty = true; return QV4::QObjectWrapper::wrap(v4, context->idValues[propertyIdx]); } else { @@ -281,6 +287,10 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r } context = context->parent; + + // As the hierarchy of contexts is not stable, we can't do accelerated lookups beyond + // the immediate QML context (of the .qml file). + lookup = nullptr; } // Do a lookup in the global object here to avoid expressionContext->unresolvedNames becoming @@ -418,6 +428,27 @@ ReturnedValue QQmlContextWrapper::lookupSingleton(Lookup *l, ExecutionEngine *en return Value::fromHeapObject(l->qmlContextSingletonLookup.singleton).asReturnedValue(); } +ReturnedValue QQmlContextWrapper::lookupIdObject(Lookup *l, ExecutionEngine *engine, Value *base) +{ + Q_UNUSED(base) + Scope scope(engine); + Scoped qmlContext(scope, engine->qmlContext()); + if (!qmlContext) + return QV4::Encode::null(); + + QQmlContextData *context = qmlContext->qmlContext(); + if (!context) + return QV4::Encode::null(); + + QQmlEnginePrivate *qmlEngine = QQmlEnginePrivate::get(engine->qmlEngine()); + const int objectId = l->qmlContextIdObjectLookup.objectId; + + if (qmlEngine->propertyCapture) + qmlEngine->propertyCapture->captureProperty(&context->idValues[objectId].bindings); + + return QV4::QObjectWrapper::wrap(engine, context->idValues[objectId]); +} + void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml) { Heap::ExecutionContext::init(Heap::ExecutionContext::Type_QmlContext); diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index 5eacea5830..caf9281540 100644 --- a/src/qml/jsruntime/qv4qmlcontext_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -107,6 +107,7 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object static ReturnedValue resolveQmlContextPropertyLookupGetter(Lookup *l, ExecutionEngine *engine, Value *base); static ReturnedValue lookupScript(Lookup *l, ExecutionEngine *engine, Value *base); static ReturnedValue lookupSingleton(Lookup *l, ExecutionEngine *engine, Value *base); + static ReturnedValue lookupIdObject(Lookup *l, ExecutionEngine *engine, Value *base); }; struct Q_QML_EXPORT QmlContext : public ExecutionContext -- cgit v1.2.3 From 40ae0bfd9977e53a87384d79ae971a7ded260a12 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 20 Mar 2019 14:27:13 +0100 Subject: Add test for dynamic anchors to parents in PropertyChanges Fixes: QTBUG-71042 Change-Id: I4d0927b0d6c9a4ccaaddfbfd6dd2a7841fbbc845 Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmllanguage/data/EdgeObject.qml | 20 ++++++++++++++++++++ .../data/anchorsToParentInPropertyChagnes.qml | 10 ++++++++++ tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 11 +++++++++++ 3 files changed, 41 insertions(+) create mode 100644 tests/auto/qml/qqmllanguage/data/EdgeObject.qml create mode 100644 tests/auto/qml/qqmllanguage/data/anchorsToParentInPropertyChagnes.qml diff --git a/tests/auto/qml/qqmllanguage/data/EdgeObject.qml b/tests/auto/qml/qqmllanguage/data/EdgeObject.qml new file mode 100644 index 0000000000..b25dc29c49 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/EdgeObject.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 + +Item { + property int edgeWidth: bg.width + + Rectangle { + id: bg + } + + states: [ + State { + when: 1 === 1 + PropertyChanges { + target: bg + anchors.left: parent.left + anchors.right: parent.right + } + } + ] +} diff --git a/tests/auto/qml/qqmllanguage/data/anchorsToParentInPropertyChagnes.qml b/tests/auto/qml/qqmllanguage/data/anchorsToParentInPropertyChagnes.qml new file mode 100644 index 0000000000..8b1682da92 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/anchorsToParentInPropertyChagnes.qml @@ -0,0 +1,10 @@ +import QtQuick 2.9 + +Item { + width: 200 + property int edgeWidth: edge.edgeWidth + EdgeObject { + id: edge + anchors.fill: parent + } +} diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 9a3f488cea..dea7c6c7ee 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -299,6 +299,7 @@ private slots: void retrieveQmlTypeId(); void polymorphicFunctionLookup(); + void anchorsToParentInPropertyChanges(); private: QQmlEngine engine; @@ -5069,6 +5070,16 @@ void tst_qqmllanguage::polymorphicFunctionLookup() QVERIFY(o->property("ok").toBool()); } +void tst_qqmllanguage::anchorsToParentInPropertyChanges() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("anchorsToParentInPropertyChagnes.qml")); + VERIFY_ERRORS(0); + QScopedPointer o(component.create()); + QVERIFY(!o.isNull()); + QTRY_COMPARE(o->property("edgeWidth").toInt(), 200); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" -- cgit v1.2.3 From bb34abcc05d11f23c329f4c52aab638d991c1b98 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 4 Jan 2019 15:32:33 +0100 Subject: Fix lookup fallback into the global object in QML bindings This change addresses in particular qmlbench's fib10.qml, where usage of properties of the global object needs to go be accelerated in order to avoid regressing in performance. Task-number: QTBUG-69898 Change-Id: Ic43c64f4dd5459c4e92f87f03235ea836f971515 Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4lookup_p.h | 7 +++++++ src/qml/jsruntime/qv4qmlcontext.cpp | 33 +++++++++++++++++++++++++++++++-- src/qml/jsruntime/qv4qmlcontext_p.h | 1 + 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 68da224273..ee6da21121 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -143,6 +143,13 @@ struct Lookup { quintptr unused2; int objectId; } qmlContextIdObjectLookup; + struct { + // Same as protoLookup, as used for global lookups + quintptr reserved1; + quintptr reserved2; + quintptr reserved3; + ReturnedValue (*getterTrampoline)(Lookup *l, ExecutionEngine *engine); + } qmlContextGlobalLookup; }; uint nameIndex; diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index 3d9e1cc0f8..e728cfb457 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -213,6 +213,7 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r } QQmlEnginePrivate *ep = QQmlEnginePrivate::get(v4->qmlEngine()); + Lookup * const originalLookup = lookup; while (context) { // Search context properties @@ -295,8 +296,24 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r // Do a lookup in the global object here to avoid expressionContext->unresolvedNames becoming // true if we access properties of the global object. - if (performGobalLookUp()) - return result->asReturnedValue(); + if (originalLookup) { + // Try a lookup in the global object. It's theoretically possible to first find a property + // in the global object and then later a context property with the same name is added, but that + // never really worked as we used to detect access to global properties at type compile time anyway. + lookup = originalLookup; + result = lookup->resolveGlobalGetter(v4); + if (lookup->globalGetter != Lookup::globalGetterGeneric) { + if (hasProperty) + *hasProperty = true; + lookup->qmlContextGlobalLookup.getterTrampoline = lookup->globalGetter; + lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupInGlobalObject; + return result->asReturnedValue(); + } + lookup->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter; + } else { + if (performGobalLookUp()) + return result->asReturnedValue(); + } expressionContext->unresolvedNames = true; @@ -449,6 +466,18 @@ ReturnedValue QQmlContextWrapper::lookupIdObject(Lookup *l, ExecutionEngine *eng return QV4::QObjectWrapper::wrap(engine, context->idValues[objectId]); } +ReturnedValue QQmlContextWrapper::lookupInGlobalObject(Lookup *l, ExecutionEngine *engine, Value *base) +{ + Q_UNUSED(base); + ReturnedValue result = l->qmlContextGlobalLookup.getterTrampoline(l, engine); + // In the unlikely event of mutation of the global object, update the trampoline. + if (l->qmlContextPropertyGetter != lookupInGlobalObject) { + l->qmlContextGlobalLookup.getterTrampoline = l->globalGetter; + l->qmlContextPropertyGetter = QQmlContextWrapper::lookupInGlobalObject; + } + return result; +} + void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml) { Heap::ExecutionContext::init(Heap::ExecutionContext::Type_QmlContext); diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index caf9281540..cfcc53c7c9 100644 --- a/src/qml/jsruntime/qv4qmlcontext_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -108,6 +108,7 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object static ReturnedValue lookupScript(Lookup *l, ExecutionEngine *engine, Value *base); static ReturnedValue lookupSingleton(Lookup *l, ExecutionEngine *engine, Value *base); static ReturnedValue lookupIdObject(Lookup *l, ExecutionEngine *engine, Value *base); + static ReturnedValue lookupInGlobalObject(Lookup *l, ExecutionEngine *engine, Value *base); }; struct Q_QML_EXPORT QmlContext : public ExecutionContext -- cgit v1.2.3 From f9dac6f900fde93014305854b1bf3a81d9e58b92 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Thu, 3 Jan 2019 16:28:16 -0600 Subject: Accelerate lookup of singleton properties Task-number: QTBUG-69898 Change-Id: Id03ba543fa293da2690099c3e6f94b2725de562f Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4lookup_p.h | 3 +- src/qml/jsruntime/qv4qobjectwrapper.cpp | 4 ++- src/qml/qml/qqmltypewrapper.cpp | 61 +++++++++++++++++++++++++++++++++ src/qml/qml/qqmltypewrapper_p.h | 3 ++ 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index ee6da21121..03dc5f6d3c 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -71,6 +71,7 @@ struct Lookup { ReturnedValue (*qmlContextPropertyGetter)(Lookup *l, ExecutionEngine *engine, Value *thisObject); bool (*setter)(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v); }; + // NOTE: gc assumes the first two entries in the struct are pointers to heap objects or null union { struct { Heap::Base *h1; @@ -119,7 +120,7 @@ struct Lookup { } indexedLookup; struct { Heap::InternalClass *ic; - quintptr unused; + Heap::QObjectWrapper *staticQObject; QQmlPropertyCache *propertyCache; QQmlPropertyData *propertyData; } qobjectLookup; diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 053581226f..351076ac28 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -867,6 +867,7 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E } lookup->qobjectLookup.ic = This->internalClass(); + lookup->qobjectLookup.staticQObject = nullptr; lookup->qobjectLookup.propertyCache = ddata->propertyCache; lookup->qobjectLookup.propertyCache->addref(); lookup->qobjectLookup.propertyData = property; @@ -889,7 +890,8 @@ ReturnedValue QObjectWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engi if (!o || o->internalClass != lookup->qobjectLookup.ic) return revertLookup(); - const Heap::QObjectWrapper *This = static_cast(o); + const Heap::QObjectWrapper *This = lookup->qobjectLookup.staticQObject ? lookup->qobjectLookup.staticQObject : + static_cast(o); QObject *qobj = This->object(); if (QQmlData::wasDeleted(qobj)) return QV4::Encode::undefined(); diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 4089a7f030..d30c225741 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -47,6 +47,8 @@ #include #include #include +#include +#include QT_BEGIN_NAMESPACE @@ -169,6 +171,7 @@ static ReturnedValue throwLowercaseEnumError(QV4::ExecutionEngine *v4, String *n ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty) { + // Keep this code in sync with ::virtualResolveLookupGetter Q_ASSERT(m->as()); if (!id.isString()) @@ -425,6 +428,64 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType)); } +ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup) +{ + // Keep this code in sync with ::virtualGet + PropertyKey id = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]); + if (!id.isString()) + return Object::virtualResolveLookupGetter(object, engine, lookup); + Scope scope(engine); + + const QQmlTypeWrapper *This = static_cast(object); + ScopedString name(scope, id.asStringOrSymbol()); + QQmlContextData *qmlContext = engine->callingQmlContext(); + + Scoped w(scope, static_cast(This)); + QQmlType type = w->d()->type(); + + if (type.isValid()) { + + if (type.isSingleton()) { + QQmlEngine *e = engine->qmlEngine(); + QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); + siinfo->init(e); + + QObject *qobjectSingleton = siinfo->qobjectApi(e); + if (qobjectSingleton) { + + const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums; + if (!includeEnums || !name->startsWithUpper()) { + QQmlData *ddata = QQmlData::get(qobjectSingleton, false); + if (ddata && ddata->propertyCache) { + ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton))); + QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext); + if (property) { + lookup->qobjectLookup.ic = This->internalClass(); + lookup->qobjectLookup.staticQObject = static_cast(val->heapObject()); + lookup->qobjectLookup.propertyCache = ddata->propertyCache; + lookup->qobjectLookup.propertyCache->addref(); + lookup->qobjectLookup.propertyData = property; + lookup->getter = QV4::QObjectWrapper::lookupGetter; + return lookup->getter(lookup, engine, *This); + } + // Fall through to base implementation + } + // Fall through to base implementation + } + // Fall through to base implementation + } + // Fall through to base implementation + } + // Fall through to base implementation + } + return QV4::Object::virtualResolveLookupGetter(object, engine, lookup); +} + +bool QQmlTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value) +{ + return Object::virtualResolveLookupSetter(object, engine, lookup, value); +} + void Heap::QQmlScopedEnumWrapper::destroy() { QQmlType::derefHandle(typePrivate); diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index fa1ad56902..44e82dec2b 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -111,6 +111,9 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlRefPointer &, const QQmlImportRef *, Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums); + static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup); + static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value); + protected: static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty); static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver); -- cgit v1.2.3 From bcbce96fffd25a4f2810f03cec060ab13e34ac9e Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Fri, 4 Jan 2019 13:09:21 -0600 Subject: Accelerate access to scope object properties in lookups Task-number: QTBUG-69898 Change-Id: I94bf1aa85c9b2302894f3224e41de81a456211f9 Reviewed-by: Ulf Hermann --- src/qml/compiler/qv4compileddata.cpp | 5 ++++ src/qml/jsruntime/qv4qmlcontext.cpp | 45 ++++++++++++++++++++++++++++++++- src/qml/jsruntime/qv4qmlcontext_p.h | 1 + src/qml/jsruntime/qv4qobjectwrapper.cpp | 24 ++++-------------- src/qml/jsruntime/qv4qobjectwrapper_p.h | 45 ++++++++++++++++++++++++++++++++- 5 files changed, 99 insertions(+), 21 deletions(-) diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 6701443971..7906b3572c 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -284,6 +284,11 @@ void CompilationUnit::unlink() if (QQmlPropertyCache *pc = l.qgadgetLookup.propertyCache) pc->release(); } + + if (l.qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty) { + if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache) + pc->release(); + } } } diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index e728cfb457..9bdfa10030 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -261,13 +261,30 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r // Search scope object if (scopeObject) { bool hasProp = false; + + QQmlPropertyData *propertyData = nullptr; QV4::ScopedValue result(scope, QV4::QObjectWrapper::getQmlProperty(v4, context, scopeObject, - name, QV4::QObjectWrapper::CheckRevision, &hasProp)); + name, QV4::QObjectWrapper::CheckRevision, &hasProp, &propertyData)); if (hasProp) { if (hasProperty) *hasProperty = true; if (base) *base = QV4::QObjectWrapper::wrap(v4, scopeObject); + + if (lookup && propertyData) { + QQmlData *ddata = QQmlData::get(scopeObject, false); + if (ddata && ddata->propertyCache) { + ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, scopeObject))); + const QObjectWrapper *That = static_cast(val->objectValue()); + lookup->qobjectLookup.ic = That->internalClass(); + lookup->qobjectLookup.staticQObject = nullptr; + lookup->qobjectLookup.propertyCache = ddata->propertyCache; + lookup->qobjectLookup.propertyCache->addref(); + lookup->qobjectLookup.propertyData = propertyData; + lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupScopeObjectProperty; + } + } + return result->asReturnedValue(); } } @@ -466,6 +483,32 @@ ReturnedValue QQmlContextWrapper::lookupIdObject(Lookup *l, ExecutionEngine *eng return QV4::QObjectWrapper::wrap(engine, context->idValues[objectId]); } +ReturnedValue QQmlContextWrapper::lookupScopeObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base) +{ + Q_UNUSED(base) + Scope scope(engine); + Scoped qmlContext(scope, engine->qmlContext()); + if (!qmlContext) + return QV4::Encode::undefined(); + + QObject *scopeObject = qmlContext->qmlScope(); + if (!scopeObject) + return QV4::Encode::undefined(); + + if (QQmlData::wasDeleted(scopeObject)) + return QV4::Encode::undefined(); + + const auto revertLookup = [l, engine, base]() { + l->qobjectLookup.propertyCache->release(); + l->qobjectLookup.propertyCache = nullptr; + l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter; + return QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(l, engine, base); + }; + + ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, scopeObject)); + return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup); +} + ReturnedValue QQmlContextWrapper::lookupInGlobalObject(Lookup *l, ExecutionEngine *engine, Value *base) { Q_UNUSED(base); diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index cfcc53c7c9..83bf2a1d3e 100644 --- a/src/qml/jsruntime/qv4qmlcontext_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -108,6 +108,7 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object static ReturnedValue lookupScript(Lookup *l, ExecutionEngine *engine, Value *base); static ReturnedValue lookupSingleton(Lookup *l, ExecutionEngine *engine, Value *base); static ReturnedValue lookupIdObject(Lookup *l, ExecutionEngine *engine, Value *base); + static ReturnedValue lookupScopeObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base); static ReturnedValue lookupInGlobalObject(Lookup *l, ExecutionEngine *engine, Value *base); }; diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 351076ac28..377c30617a 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -357,7 +357,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String return getProperty(v4, d()->object(), result); } -ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty) +ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty, QQmlPropertyData **property) { if (QQmlData::wasDeleted(object)) { if (hasProperty) @@ -384,6 +384,9 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC if (hasProperty) *hasProperty = true; + if (property) + *property = result; + return getProperty(engine, object, result); } else { // Check if this object is already wrapped. @@ -884,24 +887,7 @@ ReturnedValue QObjectWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engi return Lookup::getterGeneric(lookup, engine, object); }; - // we can safely cast to a QV4::Object here. If object is something else, - // the internal class won't match - Heap::Object *o = static_cast(object.heapObject()); - if (!o || o->internalClass != lookup->qobjectLookup.ic) - return revertLookup(); - - const Heap::QObjectWrapper *This = lookup->qobjectLookup.staticQObject ? lookup->qobjectLookup.staticQObject : - static_cast(o); - QObject *qobj = This->object(); - if (QQmlData::wasDeleted(qobj)) - return QV4::Encode::undefined(); - - QQmlData *ddata = QQmlData::get(qobj, /*create*/false); - if (!ddata || ddata->propertyCache != lookup->qobjectLookup.propertyCache) - return revertLookup(); - - QQmlPropertyData *property = lookup->qobjectLookup.propertyData; - return getProperty(engine, qobj, property); + return lookupGetterImpl(lookup, engine, object, /*useOriginalProperty*/ false, revertLookup); } bool QObjectWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 471f352c2a..2558ede401 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -62,6 +62,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -167,7 +168,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object QObject *object() const { return d()->object(); } ReturnedValue getQmlProperty(QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = nullptr, bool includeImports = false) const; - static ReturnedValue getQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = nullptr); + static ReturnedValue getQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = nullptr, QQmlPropertyData **property = nullptr); static bool setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const Value &value); @@ -185,6 +186,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup); static ReturnedValue lookupGetter(Lookup *l, ExecutionEngine *engine, const Value &object); + template static ReturnedValue lookupGetterImpl(Lookup *l, ExecutionEngine *engine, const Value &object, bool useOriginalProperty, ReversalFunctor revert); static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value); protected: @@ -222,6 +224,47 @@ inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *obje return wrap_slowPath(engine, object); } +template +inline ReturnedValue QObjectWrapper::lookupGetterImpl(Lookup *lookup, ExecutionEngine *engine, const Value &object, bool useOriginalProperty, ReversalFunctor revertLookup) +{ + // we can safely cast to a QV4::Object here. If object is something else, + // the internal class won't match + Heap::Object *o = static_cast(object.heapObject()); + if (!o || o->internalClass != lookup->qobjectLookup.ic) + return revertLookup(); + + const Heap::QObjectWrapper *This = lookup->qobjectLookup.staticQObject ? lookup->qobjectLookup.staticQObject : + static_cast(o); + QObject *qobj = This->object(); + if (QQmlData::wasDeleted(qobj)) + return QV4::Encode::undefined(); + + QQmlData *ddata = QQmlData::get(qobj, /*create*/false); + if (!ddata) + return revertLookup(); + + QQmlPropertyData *property = lookup->qobjectLookup.propertyData; + if (ddata->propertyCache != lookup->qobjectLookup.propertyCache) { + if (property->isOverridden() && (!useOriginalProperty || property->isFunction() || property->isSignalHandler())) + return revertLookup(); + + QQmlPropertyCache *fromMo = ddata->propertyCache; + QQmlPropertyCache *toMo = lookup->qobjectLookup.propertyCache; + bool canConvert = false; + while (fromMo) { + if (fromMo == toMo) { + canConvert = true; + break; + } + fromMo = fromMo->parent(); + } + if (!canConvert) + return revertLookup(); + } + + return getProperty(engine, qobj, property); +} + struct QQmlValueTypeWrapper; struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject -- cgit v1.2.3 From 937d8114e9ccf607462ab72a4b6e801756698473 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Fri, 22 Feb 2019 16:12:50 -0600 Subject: Accelerate access to initial context object properties in lookups Task-number: QTBUG-69898 Change-Id: If92a0931bd4d64f6c176e93effb04df85ce27284 Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4qmlcontext.cpp | 57 ++++++++++++++++++++++++++++++++++++- src/qml/jsruntime/qv4qmlcontext_p.h | 1 + 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index 9bdfa10030..97b955632d 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -215,6 +215,14 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r QQmlEnginePrivate *ep = QQmlEnginePrivate::get(v4->qmlEngine()); Lookup * const originalLookup = lookup; + decltype(lookup->qmlContextPropertyGetter) contextGetterFunction = QQmlContextWrapper::lookupContextObjectProperty; + + // minor optimization so we don't potentially try two property lookups on the same object + if (scopeObject == context->contextObject) { + scopeObject = nullptr; + contextGetterFunction = QQmlContextWrapper::lookupScopeObjectProperty; + } + while (context) { // Search context properties const QV4::IdentifierHash &properties = context->propertyNames(); @@ -294,12 +302,29 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r // Search context object if (context->contextObject) { bool hasProp = false; - result = QV4::QObjectWrapper::getQmlProperty(v4, context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, &hasProp); + QQmlPropertyData *propertyData = nullptr; + result = QV4::QObjectWrapper::getQmlProperty(v4, context, context->contextObject, + name, QV4::QObjectWrapper::CheckRevision, &hasProp, &propertyData); if (hasProp) { if (hasProperty) *hasProperty = true; if (base) *base = QV4::QObjectWrapper::wrap(v4, context->contextObject); + + if (lookup && propertyData) { + QQmlData *ddata = QQmlData::get(context->contextObject, false); + if (ddata && ddata->propertyCache) { + ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, context->contextObject))); + const QObjectWrapper *That = static_cast(val->objectValue()); + lookup->qobjectLookup.ic = That->internalClass(); + lookup->qobjectLookup.staticQObject = nullptr; + lookup->qobjectLookup.propertyCache = ddata->propertyCache; + lookup->qobjectLookup.propertyCache->addref(); + lookup->qobjectLookup.propertyData = propertyData; + lookup->qmlContextPropertyGetter = contextGetterFunction; + } + } + return result->asReturnedValue(); } } @@ -509,6 +534,36 @@ ReturnedValue QQmlContextWrapper::lookupScopeObjectProperty(Lookup *l, Execution return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup); } +ReturnedValue QQmlContextWrapper::lookupContextObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base) +{ + Q_UNUSED(base) + Scope scope(engine); + Scoped qmlContext(scope, engine->qmlContext()); + if (!qmlContext) + return QV4::Encode::undefined(); + + QQmlContextData *context = qmlContext->qmlContext(); + if (!context) + return QV4::Encode::undefined(); + + QObject *contextObject = context->contextObject; + if (!contextObject) + return QV4::Encode::undefined(); + + if (QQmlData::wasDeleted(contextObject)) + return QV4::Encode::undefined(); + + const auto revertLookup = [l, engine, base]() { + l->qobjectLookup.propertyCache->release(); + l->qobjectLookup.propertyCache = nullptr; + l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter; + return QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(l, engine, base); + }; + + ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, contextObject)); + return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup); +} + ReturnedValue QQmlContextWrapper::lookupInGlobalObject(Lookup *l, ExecutionEngine *engine, Value *base) { Q_UNUSED(base); diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index 83bf2a1d3e..6375294375 100644 --- a/src/qml/jsruntime/qv4qmlcontext_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -109,6 +109,7 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object static ReturnedValue lookupSingleton(Lookup *l, ExecutionEngine *engine, Value *base); static ReturnedValue lookupIdObject(Lookup *l, ExecutionEngine *engine, Value *base); static ReturnedValue lookupScopeObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base); + static ReturnedValue lookupContextObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base); static ReturnedValue lookupInGlobalObject(Lookup *l, ExecutionEngine *engine, Value *base); }; -- cgit v1.2.3 From 77847ca2c3bad62bab2219d37e1d3d51ce83ade2 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Mon, 18 Mar 2019 16:55:49 +0100 Subject: Doc: Rename State Machine QML Types page Make name more in line with the import and with the other overview pages. This became apparent because the All QML Modules overview page now shows the name of the page, instead of the import: https://doc-snapshots.qt.io/qt5-5.13/modules-qml.html# Change-Id: Iee1362247ea6837dd9404885890b2adb7af2c544 Reviewed-by: Ulf Hermann Reviewed-by: Venugopal Shivashankar --- src/qml/doc/src/statemachine.qdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qml/doc/src/statemachine.qdoc b/src/qml/doc/src/statemachine.qdoc index 6986f1baa0..231b85af76 100644 --- a/src/qml/doc/src/statemachine.qdoc +++ b/src/qml/doc/src/statemachine.qdoc @@ -27,7 +27,7 @@ /*! \qmlmodule QtQml.StateMachine 1.\QtMinorVersion - \title Declarative State Machine QML Types + \title Qt QML State Machine QML Types \brief Provides QML types to create and execute state graphs. The following is a list of QML types provided by the module: @@ -322,7 +322,7 @@ \section1 Related Information \list - \li \l{Declarative State Machine QML Types} + \li \l{Qt QML State Machine QML Types} \li \l{The State Machine Framework} \endlist */ -- cgit v1.2.3 From ee2facb418fb9a45d5052a8424c40d4e060f311c Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Mon, 18 Mar 2019 16:21:31 +0100 Subject: qmlimportscanner: Fix comments Change-Id: I435662abafbe7b76fed7b012bfed2f99aa7158a3 Reviewed-by: Ulf Hermann --- tools/qmlimportscanner/main.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp index 60e0f1773f..616de9e80d 100644 --- a/tools/qmlimportscanner/main.cpp +++ b/tools/qmlimportscanner/main.cpp @@ -89,13 +89,13 @@ QVariantList findImportsInAst(QQmlJS::AST::UiHeaderItemList *headerItemList, con { QVariantList imports; - // extract uri and version from the imports (which look like "import Foo.Bar 1.2.3") + // Extract uri and version from the imports (which look like "import Foo.Bar 1.2.3") for (QQmlJS::AST::UiHeaderItemList *headerItemIt = headerItemList; headerItemIt; headerItemIt = headerItemIt->next) { QVariantMap import; QQmlJS::AST::UiImport *importNode = QQmlJS::AST::cast(headerItemIt->headerItem); if (!importNode) continue; - // handle directory imports + // Handle directory imports if (!importNode->fileName.isEmpty()) { QString name = importNode->fileName.toString(); import[nameLiteral()] = name; @@ -137,7 +137,7 @@ QVariantMap pluginsForModulePath(const QString &modulePath) { qmldirFile.open(QIODevice::ReadOnly | QIODevice::Text); - // a qml import may contain several plugins + // A qml import may contain several plugins QString plugins; QString classnames; QStringList dependencies; @@ -206,7 +206,7 @@ QPair resolveImportPath(const QString &uri, const QString &ver } } - // remove the last version digit; stop if there are none left + // Remove the last version digit; stop if there are none left if (ver.isEmpty()) break; @@ -426,7 +426,7 @@ QVariantList findQmlImportsInDirectory(const QString &qmlDir) if (std::find_if(blacklist.cbegin(), blacklist.cend(), pathStartsWith(path)) != blacklist.cend()) continue; - // skip obvious build output directories + // Skip obvious build output directories if (path.contains(QLatin1String("Debug-iphoneos")) || path.contains(QLatin1String("Release-iphoneos")) || path.contains(QLatin1String("Debug-iphonesimulator")) || path.contains(QLatin1String("Release-iphonesimulator")) #ifdef Q_OS_WIN @@ -455,30 +455,29 @@ QSet importModulePaths(const QVariantList &imports) { return ret; } -// Find Qml Imports Recursively from a root set of qml files. +// Find qml imports recursively from a root set of qml files. // The directories in qmlDirs are searched recursively. // The files in qmlFiles parsed directly. QVariantList findQmlImportsRecursively(const QStringList &qmlDirs, const QStringList &scanFiles) { QVariantList ret; - // scan all app root qml directories for imports + // Scan all app root qml directories for imports for (const QString &qmlDir : qmlDirs) { QVariantList imports = findQmlImportsInDirectory(qmlDir); ret = mergeImports(ret, imports); } - // scan app qml files for imports + // Scan app qml files for imports for (const QString &file : scanFiles) { QVariantList imports = findQmlImportsInFile(file); ret = mergeImports(ret, imports); } - - // get the paths to theimports found in the app qml + // Get the paths to the imports found in the app qml QSet toVisit = importModulePaths(ret); - // recursivly scan for import dependencies. + // Recursively scan for import dependencies. QSet visited; while (!toVisit.isEmpty()) { QString qmlDir = *toVisit.begin(); -- cgit v1.2.3 From 56b3232a7d35fe2b856d1d87a7e1c59906b46681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Thu, 21 Mar 2019 11:05:44 +0100 Subject: Add some missing QT_{BEGIN,END}_NAMESPACE macros Change-Id: I16820387279ca616af6ab379874c247c83df4a2f Reviewed-by: Shawn Rutledge --- src/imports/layouts/qquickstacklayout.cpp | 4 ++++ src/imports/layouts/qquickstacklayout_p.h | 4 ++++ src/quick/handlers/qquickdragaxis.cpp | 3 +++ src/quick/handlers/qquickdragaxis_p.h | 4 ++++ src/quick/items/qquickclipnode.cpp | 3 +++ src/quick/items/qquickclipnode_p.h | 4 ++++ 6 files changed, 22 insertions(+) diff --git a/src/imports/layouts/qquickstacklayout.cpp b/src/imports/layouts/qquickstacklayout.cpp index 0b51d79bef..116e162aa9 100644 --- a/src/imports/layouts/qquickstacklayout.cpp +++ b/src/imports/layouts/qquickstacklayout.cpp @@ -97,6 +97,8 @@ \sa StackView */ +QT_BEGIN_NAMESPACE + QQuickStackLayout::QQuickStackLayout(QQuickItem *parent) : QQuickLayout(*new QQuickStackLayoutPrivate, parent) { @@ -345,4 +347,6 @@ bool QQuickStackLayout::shouldIgnoreItem(QQuickItem *item) const return ignored; } +QT_END_NAMESPACE + #include "moc_qquickstacklayout_p.cpp" diff --git a/src/imports/layouts/qquickstacklayout_p.h b/src/imports/layouts/qquickstacklayout_p.h index 8ba41720aa..46181c6f50 100644 --- a/src/imports/layouts/qquickstacklayout_p.h +++ b/src/imports/layouts/qquickstacklayout_p.h @@ -42,6 +42,8 @@ #include +QT_BEGIN_NAMESPACE + class QQuickStackLayoutPrivate; class QQuickStackLayout : public QQuickLayout @@ -105,4 +107,6 @@ private: bool explicitCurrentIndex; }; +QT_END_NAMESPACE + #endif // QQUICKSTACKLAYOUT_H diff --git a/src/quick/handlers/qquickdragaxis.cpp b/src/quick/handlers/qquickdragaxis.cpp index 5efe19b2fe..88470c8a7d 100644 --- a/src/quick/handlers/qquickdragaxis.cpp +++ b/src/quick/handlers/qquickdragaxis.cpp @@ -39,6 +39,8 @@ #include "qquickdragaxis_p.h" #include +QT_BEGIN_NAMESPACE + QQuickDragAxis::QQuickDragAxis() : m_minimum(-std::numeric_limits::max()) , m_maximum(std::numeric_limits::max()) @@ -73,3 +75,4 @@ void QQuickDragAxis::setEnabled(bool enabled) emit enabledChanged(); } +QT_END_NAMESPACE diff --git a/src/quick/handlers/qquickdragaxis_p.h b/src/quick/handlers/qquickdragaxis_p.h index 16496feee3..a4649d5eb9 100644 --- a/src/quick/handlers/qquickdragaxis_p.h +++ b/src/quick/handlers/qquickdragaxis_p.h @@ -53,6 +53,8 @@ #include +QT_BEGIN_NAMESPACE + class Q_QUICK_PRIVATE_EXPORT QQuickDragAxis : public QObject { Q_OBJECT @@ -83,4 +85,6 @@ private: bool m_enabled; }; +QT_END_NAMESPACE + #endif // QQUICKDRAGAXIS_P_H diff --git a/src/quick/items/qquickclipnode.cpp b/src/quick/items/qquickclipnode.cpp index 747e844172..d90b1f1540 100644 --- a/src/quick/items/qquickclipnode.cpp +++ b/src/quick/items/qquickclipnode.cpp @@ -43,6 +43,8 @@ #include #include +QT_BEGIN_NAMESPACE + QQuickDefaultClipNode::QQuickDefaultClipNode(const QRectF &rect) : m_rect(rect) , m_radius(0) @@ -117,3 +119,4 @@ void QQuickDefaultClipNode::updateGeometry() markDirty(DirtyGeometry); } +QT_END_NAMESPACE diff --git a/src/quick/items/qquickclipnode_p.h b/src/quick/items/qquickclipnode_p.h index ed9e1ae4d8..00914deae8 100644 --- a/src/quick/items/qquickclipnode_p.h +++ b/src/quick/items/qquickclipnode_p.h @@ -54,6 +54,8 @@ #include #include +QT_BEGIN_NAMESPACE + class Q_QUICK_PRIVATE_EXPORT QQuickDefaultClipNode : public QSGClipNode { public: @@ -78,4 +80,6 @@ private: QSGGeometry m_geometry; }; +QT_END_NAMESPACE + #endif // QQUICKCLIPNODE_P_H -- cgit v1.2.3