aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4function_p.h
Commit message (Collapse)AuthorAgeFilesLines
* QML: Warn about usage of injected signal parametersUlf Hermann2021-02-121-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | You should declare functions with formal parameters if you want to use parameters passed by the signal. We need to generate two different warnings because there are two code paths by which such parameters are injected. If we compile with qmlcachegen, it simply inserts a lookup instruction in to the byte code. This lookup then triggers our special hack expressly made for signal parameters. If we don't compile using qmlcachegen, a function declaration with formal parameters is synthesized. We mark those formal parameters as injected and warn if we see one of them used. [ChangeLog][QML][Important Behavior Changes] The automatic injection of signal parameters into signal handlers is deprecated. This is because we cannot determine the names of the signal parameters at compile time. Furthermore, also for human readers it is difficult to discern between arguments, context properties, properties of the current object, and properties of the root object of the component. Requiring the signal parameters to be explicitly named resolves some of this confusion. You can turn the deprecation warning off using the "qt.qml.compiler" and "qt.qml.context" logging categories. Task-number: QTBUG-89943 Pick-to: 6.1 Change-Id: If0a5082adb735a73efd793868b3a55bc7d694cbe Reviewed-by: Mitch Curtis <mitch.curtis@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
* Add support for binding ahead-of-time compiled bindings to QPropertiesSimon Hausmann2020-04-221-2/+5
| | | | | | | | | | When the ahead-of-time built binding returns the same type as the QProperty, then we can connect them directly with a small shim and pass through the context and scope objects. Change-Id: I9cb49d1fa35490a4ccb06965397674d5534c067d Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Split compiler and runtime more clearlyUlf Hermann2019-07-111-0/+1
| | | | | | | | Provide different export macros and different top level headers for each, don't include runtime headers from compiler sources. Change-Id: I7dc3f8c95839a00a871ba045ec65af87123154be Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Make QV4::Function::runtimeString() constUlf Hermann2019-07-101-2/+2
| | | | | | | | And use it more often. Change-Id: I980663c2b0375d278d8796f2d3bc41cf7241bf16 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Split CompiledData::CompilationUnit in twoUlf Hermann2019-05-161-8/+25
| | | | | | | | We need a CompilationUnit that only holds the data needed for compilation and another one that is executable by the runtime. Change-Id: I704d859ba028576a18460f5e3a59f210f64535d3 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Remove tracing JIT infrastructureUlf Hermann2019-04-291-25/+0
| | | | | | | | The tracing JIT won't be finished. Therefore, remove the parts that have already been integrated. Change-Id: If72036be904bd7fc17ba9bcba0a317f8ed6cb30d Reviewed-by: Erik Verbruggen <erik.verbruggen@me.com>
* Merge remote-tracking branch 'origin/5.12' into 5.13Qt Forward Merge Bot2019-03-211-1/+0
|\ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Conflicts: src/qml/compiler/qqmltypecompiler.cpp src/qml/compiler/qv4bytecodehandler.cpp src/qml/compiler/qv4codegen.cpp src/qml/compiler/qv4compileddata_p.h src/qml/compiler/qv4compiler.cpp src/qml/compiler/qv4instr_moth.cpp src/qml/compiler/qv4instr_moth_p.h src/qml/jit/qv4baselinejit.cpp src/qml/jit/qv4baselinejit_p.h src/qml/jsruntime/qv4function.cpp src/qml/jsruntime/qv4vme_moth.cpp Change-Id: I8fb4d6f19677bcec0a4593b250f2eda5ae85e3d2
| * Remove dead compile time QML context/scope property and id object codeSimon Hausmann2019-03-201-1/+0
| | | | | | | | | | | | | | | | | | | | | | 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>
* | V4: Collect trace information in the interpreterErik Verbruggen2019-01-251-4/+43
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Collect type information about values used in a function. These include all parameters, and the results of many bytecode instructions. For array loads/stores, it also tracks if the access is in-bounds of a SimpleArrayData. Collection is only enabled when the qml-tracing feature is turned on while configuring. In subsequent patches this is used to generated optimized JITted code. Change-Id: I63985c334c3fdc55fca7fb4addfe3e535989aac5 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* | V4: Generate function tables on 64bit windowsUlf Hermann2018-12-031-1/+4
|/ | | | | | | | | | | | | | In order for global exception handlers to be called reliably, the runtime needs to unwind through JIT-generated code. This can be facilitated by installing a "function table" for each JITed function that specifies "use the frame pointer". Also make sure to generate a function table for JIT'ed regular expressions. Those were forgotten also in the linux case. Fixes: QTBUG-50061 Change-Id: Ib0b8ae9356ed80afe1cab017e36efa4ccbe73f90 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Fix super property accessLars Knoll2018-08-311-0/+1
| | | | | | | | | Super properties work in a rather special way by accessing a 'home object' on the function object, and reading from it's prototype. Change-Id: I666334c9c27048c6c2ba6770dd8c9f56aecbee14 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Refactor initialization code for JS stack framesLars Knoll2018-07-031-4/+1
| | | | | | | | | Move code into qv4stackframe_p.h, so that it can be re-used from different places. Clean up VME::exec and the generatorfunctions using this. Change-Id: Ib4f7eceeb5f55d98dd6ccf2584d13a3b864caea1 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Move the C++ and JS stack frame definitions into it's own fileLars Knoll2018-07-031-5/+3
| | | | | Change-Id: I86e89e07197aec6071809c2d32bd5c98cb7ac6f6 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Minor cleanup with bytecode pointer typesSimon Hausmann2018-05-281-1/+1
| | | | | | | | | | | | Even though we consider the bytecode to be a sequence of unsigned bytes, we store it as const char * (so unsigned except on arm) everywhere, because that makes it convenient to work with QByteArray's constData(). By using const char * consistently we can get rid of at least one more reinterpret_cast. Change-Id: I7a803e4201381c39eec2fdc6497d9bf36a1c2b6b Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Remove unused QV4::Function::code memberSimon Hausmann2018-05-281-3/+1
| | | | | | | | Since commit 831ddc54932d2681712ca9fa3e94484ae11d59f7 we always call the interpreter entry function when calling into JS. Change-Id: Ieeb549f6d144f02f0a919759fd31541a7f636f83 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Add Generator supportLars Knoll2018-05-031-0/+1
| | | | | | | | | | | | | Add support for ES6 generators. Those are currently always executed in the interpreter (we never JIT them), to simplify the initial implementation. Most functionality, except for 'yield *' expressions are supported. 'yield *' will have to wait until we support for(... of ...) Change-Id: I7c059d1e3b301cbcb79e3746b4bec346738fd426 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Cleanup handling of with() statementsLars Knoll2018-05-021-1/+0
| | | | | | | | | | | Add a CompilerContext for with, whose only purpose it is to trigger variable lookup by name. This avoids looking up variables declared inside the with() {} block by name and we do not lookup variables outside the with block by name neither anymore. Change-Id: I52e9fb2daa9601f9e5102714c002dc506ad5ed23 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Add support for arrow functionsLars Knoll2018-04-261-0/+1
| | | | | | | | | | | | | Arrow parameter lists are tricky and require some reparsing by the standard to avoid conflicts in the parser with expression statements. Add an IsArrowFunction flag to the CompiledData::Function. This information is required in the runtime, when creating Function objects, as it does influence their behaviour in subtle ways. Change-Id: I298801b091f98e30a9269d3c77d9ff94e519dabc Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* garbage collect InternalClassLars Knoll2018-04-121-1/+1
| | | | | | | | | | | | | | | | Internal classes are now allocated and collected through the GC. As they are important to the deletion of other objects (because of the vtable pointer living inside the internal class), they need to get destroyed after regular objects have been sweeped. Achieve this by using a separate block allocator for internal class objects. Our lookups do often contain pointers to internal classes, so those need to be marked as well, so we don't accidentally collect them. Change-Id: I4762b054361c70c31f79f920f669ea0e8551601f Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Handle function expressions as signal handlersErik Verbruggen2018-03-201-0/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | There are two ways to use function expressions on the right-hand side of bindings: property var somethingPressed somethingPressed: function() { /* ..press something else.. */ } signal buttonPressed onButtonPressed: function() { /* ..handle buttonPress.. */ } In the former case, it declares a property that holds a function. So on initialization, the right-hand side of the binding returns a closure that gets assigned to the property 'somethingPressed'. In the latter case, the signal handler is explicitly marked as a function for clarity. So, the handler should not be returning the closure, but the handler should *be* the closure. In general, it is not possible to detect if the left-hand side is a property or a signal handler when generating QML cache files ahead of time. So for this case, we mark the function as only returning a closure. Then when instantiating the object, we check if it is a signal handler, and if the handler is marked as only returning a closure. If so, we set that closure to be the signal handler. Task-number: QTBUG-57043 Task-number: QTBUG-50328 Change-Id: I3008ddd847e30b7d0adef07344a326f84d85f1ba Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Merge remote-tracking branch 'origin/5.10' into devLiang Qi2018-02-021-0/+1
|\ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Conflicts: src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp src/qml/compiler/qqmlirbuilder.cpp src/qml/compiler/qqmlirbuilder_p.h src/qml/compiler/qqmltypecompiler.cpp src/qml/compiler/qv4codegen.cpp src/qml/compiler/qv4codegen_p.h src/qml/compiler/qv4compileddata_p.h src/qml/compiler/qv4compiler.cpp src/qml/compiler/qv4compilercontext_p.h src/qml/compiler/qv4isel_moth.cpp src/qml/compiler/qv4jsir.cpp src/qml/compiler/qv4jsir_p.h src/qml/jit/qv4isel_masm.cpp src/qml/jsruntime/qv4engine.cpp src/qml/jsruntime/qv4functionobject.cpp src/qml/jsruntime/qv4runtimecodegen.cpp src/qml/jsruntime/qv4script.cpp src/qml/jsruntime/qv4script_p.h src/qml/qml/qqmltypeloader.cpp src/quick/items/qquickanimatedimage.cpp src/quick/items/qquickanimatedimage_p_p.h src/quick/scenegraph/compressedtexture/qsgpkmhandler.cpp tests/auto/qml/qmlplugindump/qmlplugindump.pro tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp tools/qmlcachegen/qmlcachegen.cpp tools/qmljs/qmljs.cpp Done-with: Shawn Rutledge <shawn.rutledge@qt.io> Done-with: Lars Knoll <lars.knoll@qt.io> Done-with: Ulf Hermann <ulf.hermann@qt.io> Change-Id: I010e6525440a85f3b9a10bb9083f8e4352751b1d
| * Merge remote-tracking branch 'origin/5.9' into 5.10Liang Qi2018-01-241-0/+1
| |\ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Conflicts: .qmake.conf src/qml/compiler/qv4codegen.cpp src/qml/compiler/qv4compileddata_p.h src/qml/debugger/qqmlprofiler_p.h src/qml/jsruntime/qv4engine.cpp src/qml/memory/qv4mm.cpp src/qml/qml/qqmlcomponent.cpp src/qml/qml/qqmlobjectcreator.cpp src/qml/qml/qqmlobjectcreator_p.h src/qml/types/qqmldelegatemodel.cpp src/quick/items/qquickitem_p.h src/quick/items/qquickwindow.cpp tests/auto/quick/touchmouse/BLACKLIST tests/benchmarks/qml/holistic/tst_holistic.cpp Change-Id: I520f349ab4b048dd337d9647113564fc257865c2
| | * Use potentially intercepted URL as ID for compilation unitsUlf Hermann2017-12-211-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | We generally have to pass a URL and a file name everywhere because the logical URL might be something else than the actual file being loaded. For example a QQmlFileSelector might modify the URL to be loaded for a specific file. This resulting URL, however, should not be used to resolve further URLs defined in the file loaded that way. As we need to access QQmlTypeLoader::m_url as string more often now, cache it and avoid frequent translations between QUrl and QString. Furthermore, QQmlDataBlob's URLs are changed to follow the same semantics. The finalUrl is the one that should be used to resolve further URLs, the url is the one used to load the content, and subject to any redirects or interceptions. This changes the semantics of URL redirects. Previously a redirected URL was used as the base URL for furher URL resolution. This doesn't work because redirection occurs after interception and interception should not influence the resolution of further URLs. We now use the original URL as base URL for resolution of further URLs and rely on the server to redirect those, too. Task-number: QTBUG-61209 Change-Id: I93822f820bed2515995de3cb118099218b510ca4 Reviewed-by: Michael Brasser <michael.brasser@live.com>
* | | V4: Only start JITting after a minimum of 3 callsErik Verbruggen2017-12-141-0/+1
| | | | | | | | | | | | | | | | | | Change-Id: I748e06041f3085980ce48391ba2d829a9d86a727 Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* | | V4: Add a baseline JITErik Verbruggen2017-11-171-0/+8
| | | | | | | | | | | | | | | | | | | | | | | | This patch add a JIT back in for all platforms that supported JITting before, with the exception of MIPS. Change-Id: I51bc5ce3a2ac40e0510bd72a563af897c5b60343 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* | | Cut out one more C++ layer when doing JS function callsLars Knoll2017-11-131-4/+4
| | | | | | | | | | | | | | | Change-Id: I0e2ac30b7e6d77fe41deb84a97b0a7f220437c6a Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | | Finally get rid of the QV4::Function pointer in the contextLars Knoll2017-11-131-8/+0
| | | | | | | | | | | | | | | Change-Id: Iad6018f67faa956d385087865fca9d73419e363e Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | | Get rid of the unusued canUseSimpleCall flagLars Knoll2017-11-071-3/+0
| | | | | | | | | | | | | | | Change-Id: I5230342db4647bd95793475f751213f0725d6965 Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
* | | Get rid of the hack for named expressionsLars Knoll2017-09-021-1/+0
| | | | | | | | | | | | | | | | | | | | | | | | Instead simply use the pointer to the FunctionObject we have in the CallData now. Change-Id: I6d7ed8af22e89e0217bef427110611b661ac7965 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | | CleanupsLars Knoll2017-09-011-10/+1
| | | | | | | | | | | | | | | Change-Id: Iba5a238c98617f99049dc0e529e642b924e42755 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | | Move CallContext construction into a interpreter instructionLars Knoll2017-09-011-3/+0
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This will allow us to further cut down on function call overhead. To make this work, introduce a proper distinction between EvalCode and GlobalCode and use the correct compilation mode in all places. Change-Id: I070621142159b7416026347c9239200c5ed7a56b Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | | Use the context member in CallDataLars Knoll2017-09-011-8/+8
| | | | | | | | | | | | | | | | | | | | | | | | Store the current context in the context member instead of passing it along as arguments. Change-Id: If3dd0d32eddb2a02bcbf65fe6e8d15142403170e Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | | Get rid of the FunctionObject parameter to VME::exec()Lars Knoll2017-09-011-8/+8
| | | | | | | | | | | | | | | Change-Id: I5b833d1f76899a5b8fceb0f4fc109b77b1b431fc Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | | Remove one more layer of function calls when entering JS functionsLars Knoll2017-08-101-1/+7
| | | | | | | | | | | | | | | Change-Id: I7d8b2e16d2eacf5e0eafb8b8574de51527fd0ac2 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | | Always create a valid CallData object for interpreter callsLars Knoll2017-08-101-1/+11
| | | | | | | | | | | | | | | | | | | | | | | | This will allow removing a few more special cases and to simplify the code further. Change-Id: I3a958e9f68e3c103ea4f2ee6825f893e5931b11d Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | | Refactor context handlingLars Knoll2017-08-101-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Fix the push/pop context instructions to not modify the JS stack anymore, as that can cause conflicts with the VME (and was an ugly hack in any case). Instead, these instructions not return the old context, that is then stored in a temporary. Get rid of Engine::current and Engine::currentContext. The StackFrame structures do now contain the only and authoritive data. This finally gives us a nice setup where we create and destroy frames on the stack when entering/leaving functions. Change-Id: If161e3e941f59865c47ecfe1e094faf62b52bfa0 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | | Avoid creating a CallContext for simple functionsLars Knoll2017-08-101-1/+2
| | | | | | | | | | | | | | | | | | | | | | | | This cuts out quite a bit of overhead when entering and leaving functions. Change-Id: I32670c98a4087ea3b2d45853d9cabff9066399e8 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | | Introduce a JS stack frame that corresponds to the C++ stack frameLars Knoll2017-08-101-3/+3
| | | | | | | | | | | | | | | | | | | | | | | | The frame currently contains the function itself and the current context. Change-Id: I7d3402627fbc90e860a7bdc277585f365f5b4cb5 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | | No need to pass the Engine pointer to VME::exec()Lars Knoll2017-08-031-2/+2
| | | | | | | | | | | | | | | Change-Id: I1e43305e26833a6d9b714e89f59ccead6bd12605 Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
* | | Get rid of the compilation unit related members in ExecutionContextLars Knoll2017-08-031-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | And change the signature for VME::exec to take the QV4::Function that should be executed. This is in preparation to being able to run functions that will not need to allocate an execution context on their own. Change-Id: I34538a8723006f4ec24583805e88a66e750100c3 Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
* | | Unify SimpleCallContext and CallContextLars Knoll2017-07-051-1/+1
|/ / | | | | | | | | | | | | Plan is to completely remove the need for the simple call context. Change-Id: Ie5e4673a6746dc110adbf526e45188f218fd7bfc Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
* | Get rid of QV4::Function::needsActivation()Lars Knoll2017-03-091-4/+0
| | | | | | | | | | | | | | | | We can just as well simply check whether we have a simple or regular CallContext instead. Change-Id: Iddd4ca249ab6b3b13d7ef0a732c22a26bcb23dbb Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | Separate SimpleCallData and CallDataLars Knoll2017-03-091-1/+1
|/ | | | | | | | | | SimpleCallData doesn't need any loca variables, so move it into a separate CallData Heap object. This also allows getting rid of the manual markObjects() implementation for CallContext. Change-Id: I9014eb2f815d3e2fe63a951a9d126c38e8aaa0a3 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Get rid of SimpleScriptFunctionLars Knoll2016-12-111-8/+2
| | | | | | | | | | Now that the code paths are very similar, we can simply to the check whether to do a fast or slow function call in ScriptFunction::call/contruct. To make this fast, cache the result of the required check in QV4::Function Change-Id: I03085ca2beb83b1721b60b0d7b2ab4c9266d1e48 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Move the check whether a function is simple to QV4::FunctionLars Knoll2016-12-091-0/+9
| | | | | | | This allows re-using the check in the QQmlJavascriptExpression code. Change-Id: I647a6edb4844911f540f08c4a067d055676dd0ed Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Use QV4::Function instead of the FunctionObject in CallContextLars Knoll2016-12-061-0/+8
| | | | | | | | The prepares for being able to call binding code without having to create a full FunctionObject. Change-Id: I5f0dcaa4d1ae8876554cac82597351801588bc02 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Add a sourceLocation() accessor to QV4::FunctionLars Knoll2016-12-061-0/+6
| | | | | Change-Id: I3a38ee44ce46c2416ceef153ce631bc15fd461fe Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Precalculate and cache hasQmlDependenciesErik Verbruggen2016-12-011-0/+1
| | | | | Change-Id: I62b5e167847871f7ead39168ac281ba10e7f7008 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Updated license headersJani Heikkinen2016-01-191-14/+20
| | | | | | | | | | | From Qt 5.7 -> LGPL v2.1 isn't an option anymore, see http://blog.qt.io/blog/2016/01/13/new-agreement-with-the-kde-free-qt-foundation/ Updated license headers to use new LGPL header instead of LGPL21 one (in those files which will be under LGPL v3) Change-Id: Ic36f1a0a1436fe6ac6eeca8c2375a79857e9cb12 Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
* Add missing "We mean it" comments to private headers.Friedemann Kleint2015-10-061-0/+11
| | | | | | Task-number: QTBUG-48594 Change-Id: Ifc207938de7f0c8995fc712df92665f222612647 Reviewed-by: Alan Alpert <aalpert@blackberry.com>