aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qv4codegen.cpp
Commit message (Collapse)AuthorAgeFilesLines
* Remove dead compile time QML context/scope property and id object codeSimon Hausmann2019-03-201-69/+2
| | | | | | | | | | | 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 <ulf.hermann@qt.io>
* Implement dummy QML lookups for "global" variablesSimon Hausmann2019-03-201-10/+25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 <ulf.hermann@qt.io>
* Fix up global name determination when compiling ahead of timeSimon Hausmann2019-03-151-2/+2
| | | | | | | | 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 <ulf.hermann@qt.io>
* Unify the JavaScript parsing recursion checksUlf Hermann2019-03-151-9/+28
| | | | | | | | | | | | | 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 <simon.hausmann@qt.io>
* Save some stack space during code generationUlf Hermann2019-03-141-121/+100
| | | | | | | | | | | | | | 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 <simon.hausmann@qt.io>
* V4: Rotate loop in ArrayPattern and eliminate "done" labelErik Verbruggen2019-02-251-11/+5
| | | | | | | | | | This prevents jumping over the resetting of the unwind handler when an exception occurs. (cherry-picked from commit 0282b89ec672e25a465a8e51bc74c7fd58a624b1) Fixes: QTBUG-73985 Change-Id: I4a4da815f54c13980d239e0492f9b013991cfbd5 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* V4: Fix unwind handling when destructuring listsErik Verbruggen2019-02-251-14/+1
| | | | | | | | | | | If there was a rest element in the list, the generated code would jump over the clean-up (closing of the iterator). However, this would also jump over any resetting of the unwind handler. (cherry-picked from commit 3310f173c1c6208cb0f6541578419196bc29831f) Task-number: QTBUG-73985 Change-Id: I9a1bcb9e69fd98975fe9c89e23a4568b0dafdf83 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Don't optimize global lookups if fast QML lookups are disabledUlf Hermann2019-02-131-1/+1
| | | | | | | | | | | If fast QML lookups are disabled, we generally want to look up by string. If the name then happens to be a member of the global JavaScript object, we still don't want to directly access that, as the name could have been overridden in a deeper context. Fixes: QTBUG-73750 Change-Id: Id16110969123d91501064ba46bfad4c2a39e4650 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* V4: Fix unwind handler reset after for-in loopErik Verbruggen2019-01-311-5/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Consider this JavaScript snippet: function f() { for (var i in []) {} } This generates the following bytecode sequence: 2 0: 14 00 09 MoveConst r3, C0 3: ec 00 00 DefineArray (function), 0 6: da 00 GetIterator 0 8: 18 08 StoreReg r2 10: c0 0f SetUnwindHandler 27 12: 50 04 Jump 18 14: 16 0a LoadReg r4 16: 18 07 StoreReg r1 3 18: 16 08 LoadReg r2 20: dc 0a 09 IteratorNext r4, r3 23: 54 f5 JumpFalse 14 25: 50 03 Jump 30 27: c0 00 SetUnwindHandler <null> 29: c2 UnwindDispatch 4 30: 0e LoadUndefined 31: 02 Ret The problem is a normal loop exit: instruction 23 will not jump back, but fall through, and then instruction 25 will jump over the instructions resetting the unwind handler (27 + 29). Removing this jump fixes the issue. Change-Id: Ic9f03555ebebc27144490bce04e9a4166ed7c97c Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Correctly scope unwind handlers for try blocksLars Knoll2019-01-301-3/+0
| | | | | | | | | | | | | Make sure the unwind handler is always reset when leaving the try block. This exposes a couple of failures in the ECMAScript test suite that were before passing by pure luck. Task-number: QTBUG-72858 Change-Id: I014b1e37c2beff136ecd53a665a2f10933f7e12c Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
* Merge remote-tracking branch 'origin/5.12.0' into 5.12Qt Forward Merge Bot2018-12-071-0/+70
|\ | | | | | | | | | | | | | | Conflicts: src/qml/jsruntime/qv4script.cpp src/qml/parser/qqmljslexer.cpp Change-Id: I82252a8c504a4b77c45f4f8efe849ff9acb949fd
| * Generate lookups into the global object more aggressivelyLars Knoll2018-11-161-0/+70
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Since change 9333ea8649838d7e0400b0e94c8cbd4fa5d216b0, we lookup properties in the QML context object before the global object to have proper scoping rules for QML. Unfortunately this lead to a performance regression when using global properties such as Math in imported script files, as the lookup would always go through the qml context first. This can be fixed, as we know that the global object is frozen in qml mode, and the standard names of properties in the global object are illegal to use in QML. So simply check for those names in the code generator and create lookups into the global object for those. Change-Id: I4b2089178c9e5f9440abdfd834cf7d92c3c0e2c3 Fixes: QTBUG-71591 Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
* | JS: Limit expression and statement nesting levelErik Verbruggen2018-11-291-2/+6
| | | | | | | | | | | | | | | | | | This is to prevent extremely deeply nested expressions and statements make the code-generator run out of (native) stack space. Task-number: QTBUG-71087 Change-Id: I8e1a20a361bff3e49101e535754546475a63ca18 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | JS: Check pattern target to be an lvalueErik Verbruggen2018-11-191-0/+4
| | | | | | | | | | Change-Id: If9468b93b08ad355f07d1436ca88e8d36be22070 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* | JS: Handle check for dangling jump gracefullyErik Verbruggen2018-11-191-1/+3
| | | | | | | | | | | | | | | | | | | | | | The destructor for the Jump object will check if it is linked somewhere. So when doing an early-exit after generating a jump (and before linking it) and after an error occurred, make sure to call link anyway. At this point no code will be generated, so where the jump points to is kinda pointless. Change-Id: I09fa03d4224805a838088acd0c5c83d02b328045 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* | Merge remote-tracking branch 'origin/5.12.0' into 5.12Qt Forward Merge Bot2018-11-161-25/+27
|\| | | | | | | Change-Id: I7623438dde316ae1e97802f91991f2e7ccc205a5
| * Stop codegen after errorErik Verbruggen2018-11-131-25/+27
| | | | | | | | | | | | | | | | | | | | We won't use the bytecode anyway, and it prevents consistency checks that come after the error from failing. Specifically: there might be jumps that have no label defined. Fixes: QTBUG-71738 Change-Id: I62a7e943b0156d42caccfa40507853de79e3b1ce Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* | Create proper template objects for tagged templatesLars Knoll2018-11-051-64/+14
| | | | | | | | | | | | | | | | If a tagged template gets evaluated multiple times, the underlying template object is shared. Change-Id: Ie2f476fbc93d5991322ce1087c42719a8d8333ae Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | Create proper template objectsLars Knoll2018-11-021-14/+40
|/ | | | | | | | | Create the proper template object for a tagged template. This fixes quite a few use cases (esp. String.raw), but is not yet 100% spec compliant. Change-Id: I69eaee22c384c0d1bd2c6c56ad711d29521b0b86 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Clone ContextType::Global as ContextType::ScriptImportedByQMLJüri Valdmann2018-11-011-1/+1
| | | | | | | | | | Add new enum value QV4::Compiler::ContextType::ScriptImportedByQML, which behaves exactly the same as ContextType::Global. A follow-up patch will change the behavior slightly. Task-number: QTBUG-69408 Change-Id: I20d27804fd1433f2229704546bcd78a0ac108c01 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* JS: Check if the rhs of an assignment had errors before using itErik Verbruggen2018-10-151-1/+4
| | | | | Change-Id: I34d70759732433b6f0ecccc5ae175d33ec8e1577 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* JS: Check lhs of an 'in' expression to be an lvalueErik Verbruggen2018-10-151-0/+4
| | | | | | | | | For example: 'for (foo() in something) {}' is not valid: a call expression is not an lvalue. Task-number: QTBUG-71086 Change-Id: Ia1498cd38526b073afb8e4524ceaea14dca3d65f Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Remove useless assertErik Verbruggen2018-10-151-2/+0
| | | | | | | | There is a {{Q_UNREACHABLE}} right after it. Change-Id: Id69fb1403a5f99912e6fbcb4a397a78a9d6948d7 Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Abort parsing on errorLars Knoll2018-10-151-17/+14
| | | | | | | | | | The visit() methods need to return false on parse errors, so that we don't continue iterating into that subtree of the AST, but rather exit as quickly as possible. Task-number: QTBUG-71090 Change-Id: I1912d955a0ffc86389a4cbbb3b6ac0209c3c556a Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* JS: Check expressions inside template literals for validityErik Verbruggen2018-10-121-0/+4
| | | | | | | | | And not use (a possibly invalid result) blindly, because this will cause assertion failures down the line. Task-number: QTBUG-71081 Change-Id: Id10149c55026094a355bd747f66014119c0e24f5 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* JS: Check array subscripts for validity when generating codeErik Verbruggen2018-10-111-0/+2
| | | | | | Task-number: QTBUG-71079 Change-Id: I999130f3994f513bb9d2ca8ddaa94688451937fc Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Make Codegen::Reference movableErik Verbruggen2018-10-071-64/+0
| | | | | | | | This removes the call to Reference::operator= and allows the constructor and assignment to be inlined. Change-Id: I173ae47127cc5c939300c1178c4c8637882f1c49 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Trim some #includesErik Verbruggen2018-10-071-4/+4
| | | | | Change-Id: I5346fc36c89b7969c2bef3069f256f33bd4d9eb9 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* ES7: Detect Tail Position Calls and pass that to the runtimeErik Verbruggen2018-10-041-32/+104
| | | | | | | Doing the tail call in the runtime will come in a follow-up patch Change-Id: I8224aac0edbdc765ee9b97703948edd52fd33f3e Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Cleanups in Value/PrimitiveLars Knoll2018-09-171-16/+16
| | | | | | | | | | | | Get rid of Primitive and move the corresponding methods directly into Value. Mark many methods in Value as constexpr and turn Value into a POD type again. Keep Primitive as a pure alias to Value for source compatibility of other modules that might be using it. Change-Id: Icb47458947dd3482c8852e95782123ea4346f5ec Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Use the correct enum value instead of hard coded intsLars Knoll2018-09-071-4/+4
| | | | | Change-Id: I2d65fe6fb3d9f299f5aeff1542c7dc1d2db8b012 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Don't evaluate the switch expression inside the switch blockLars Knoll2018-09-071-2/+2
| | | | | Change-Id: I6cbe0610b65c9f9d7381bc1c70ae17e10486d5c3 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Add support for yield*Lars Knoll2018-09-071-8/+47
| | | | | Change-Id: I5b054b59519ed825459a5b0b0a7cd2c6fc8a3797 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Throw a type error when trying to destructure null or undefinedLars Knoll2018-09-071-0/+4
| | | | | Change-Id: Id1bba1a729124bccb8a90dcf40252fe5c69d27a3 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Fix exception handling while destructuringLars Knoll2018-09-071-48/+49
| | | | | | | | | | | | | | | When an exception happens during destructuring, IteratorClose needs to be called, unless the exception happened inside the IteratorNext call (in that case the iterator is assumed to be invalid and we shouldn't call close on it). Implement this, by ensuring that we set the done return variable of IteratorNext to true whenever IteratorNext throws an exception. IteratorClose will check the done state and not do anything in that case. Change-Id: I73a27f855f2c4d3134b8cc8980e64bf797d03886 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Some fixes when unwinding inside for-of loopsLars Knoll2018-09-071-19/+21
| | | | | | | | This is not perfect yet, as the two regressions in TestExpectations show, but it's an improvement over the current situation. Change-Id: I82c0ef0f69619562037c573bea1026abc53c1ab3 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Fix new.target access from eval()Lars Knoll2018-09-071-2/+7
| | | | | Change-Id: I1855eb303225d1784b019f8eebab0ad8bf2cdf5e Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* fix accesses to this in arrow functionsLars Knoll2018-09-051-0/+6
| | | | | Change-Id: I4c0cfc3a120fc0b246760886b576e92d3f7623ff Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Enable lookups for global properties in QMLLars Knoll2018-09-051-2/+2
| | | | | | Task-number: QTBUG-70315 Change-Id: I2408c7a8561a000cb161e0bad066e5754be3b7ef Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Add missing returnErik Verbruggen2018-09-051-1/+1
| | | | | Change-Id: I9d656b631935286c4b550be3318329487693de44 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Fix thisObject when calling super propertiesLars Knoll2018-08-311-3/+29
| | | | | Change-Id: Ia520d43ea2c29c16cfc8ffc86a32187a78848502 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Correctly create methods for functions in object literalsLars Knoll2018-08-311-6/+18
| | | | | | | | | | Methods behave slightly different than normal functions as they have a home object and define how super property access is being done. To implement this correctly, we need to create these methods during object initialization time. Change-Id: Ib3f670c8790b882c6472de786938ca4f0b73f66f Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Pass the correct new.target to super callsLars Knoll2018-08-291-4/+3
| | | | | Change-Id: I648e173a156ffd47564192ecdcb81a03281fdcb4 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Fix TDZ check for referencesLars Knoll2018-08-291-5/+19
| | | | | | | | | | So far we've not been doing the TDZ check for expressions such as x.name, a[x] and super[x] correctly. Fix this by adding a second boolean that states whether a tdz check for the subscript is required and use the first boolean to check the base of these references. Change-Id: I658cd5b69f001fbdc714f252914ad9749734f027 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Optimize access to lexically scoped variablesSimon Hausmann2018-08-291-5/+5
| | | | | | | | | | | | | If we access a lexically scoped variable after the initializer, then we know it's either initialized or at least undefined, so we don't need to do the TDZ check anymore. The ES tests ensure that we don't optimize too much and the newly revived tst_v4misc test ensures that we do not generate the TDZ check instruction for certain scenarios. Change-Id: I6706d1feb22217f323124ee698ebadb70324693b Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Implement the dead temporal zoneSimon Hausmann2018-08-281-4/+23
| | | | | | | | | | | | | | With const and let it is possible to access the declared member before initialization. This is expected to throw a type reference error at run-time. We initialize such variables with the empty value when entering their scope and check upon access for that. For locals we place the lexically scoped variables at the end. For register allocated lexical variables we group them into one batch and remember the index/size. Change-Id: Icb493ee0de0525bb682e1bc58981a4dfd33f750e Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Remove very dead codeErik Verbruggen2018-08-271-3/+0
| | | | | Change-Id: Ia510efa990b58d19eca635433187d3ffbc6e003a Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Fix initialization of default exported functions and generatorsSimon Hausmann2018-08-151-1/+4
| | | | | | | | | When registering a default export, make sure that the local name points either to an entry that we've entered into the environment or the synthetic entry we create. Change-Id: I37e160dc1e3231214bb68f72d6bb0746d7aee3b3 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Simplify ES module body handlingSimon Hausmann2018-08-141-1/+1
| | | | | | | | | Now that ImportDeclaration and ExportDeclaration are also statements in the AST, we can get rid of the ModuleItemList in the AST. We keep it in the grammar, but map it to a statement list. Change-Id: I4cab29fe9b075e88454fe3b194126f728000856a Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Fix module dependency handlingSimon Hausmann2018-08-141-0/+3
| | | | | | | | | | | | | | | | | | | | | The evaluation of a module can have side-effects by modifying the global object or objects in it. Therefore even a seemingly empty import such as import "./foo.js" needs to be listed in the module requests. It's also important that they are evaluated in the order of declaration. Therefore we collect all module requests separately - even those that don't have import variables to process. This patch also ensures that the export and import declarations are visited in the correct order, by unifying both AST nodes to be hooked into the statement list. The fact that we connect the module list items into a statement list is solely an artifact of re-using defineFunction() which takes a StatementList as body. Change-Id: I75dc357b2aecfc324d9a9fe66952eff1ec1dfd8a Reviewed-by: Lars Knoll <lars.knoll@qt.io>