| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the QtQml module of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:LGPL$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU Lesser General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | 
| 21 | ** packaging of this file. Please review the following information to | 
| 22 | ** ensure the GNU Lesser General Public License version 3 requirements | 
| 23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | 
| 24 | ** | 
| 25 | ** GNU General Public License Usage | 
| 26 | ** Alternatively, this file may be used under the terms of the GNU | 
| 27 | ** General Public License version 2.0 or (at your option) the GNU General | 
| 28 | ** Public license version 3 or any later version approved by the KDE Free | 
| 29 | ** Qt Foundation. The licenses are as published by the Free Software | 
| 30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | 
| 31 | ** included in the packaging of this file. Please review the following | 
| 32 | ** information to ensure the GNU General Public License requirements will | 
| 33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | 
| 34 | ** https://www.gnu.org/licenses/gpl-3.0.html. | 
| 35 | ** | 
| 36 | ** $QT_END_LICENSE$ | 
| 37 | ** | 
| 38 | ****************************************************************************/ | 
| 39 |  | 
| 40 | #ifndef QQMLPROFILER_P_H | 
| 41 | #define QQMLPROFILER_P_H | 
| 42 |  | 
| 43 | // | 
| 44 | //  W A R N I N G | 
| 45 | //  ------------- | 
| 46 | // | 
| 47 | // This file is not part of the Qt API.  It exists purely as an | 
| 48 | // implementation detail.  This header file may change from version to | 
| 49 | // version without notice, or even be removed. | 
| 50 | // | 
| 51 | // We mean it. | 
| 52 | // | 
| 53 |  | 
| 54 | #include <private/qv4function_p.h> | 
| 55 | #include <private/qqmlboundsignal_p.h> | 
| 56 | #include <private/qfinitestack_p.h> | 
| 57 | #include <private/qqmlbinding_p.h> | 
| 58 | #if QT_CONFIG(qml_debug) | 
| 59 | #include "qqmlprofilerdefinitions_p.h" | 
| 60 | #include "qqmlabstractprofileradapter_p.h" | 
| 61 | #endif | 
| 62 |  | 
| 63 | #include <QUrl> | 
| 64 | #include <QString> | 
| 65 |  | 
| 66 | QT_BEGIN_NAMESPACE | 
| 67 |  | 
| 68 | #if !QT_CONFIG(qml_debug) | 
| 69 |  | 
| 70 | #define Q_QML_PROFILE_IF_ENABLED(feature, profiler, Code) | 
| 71 | #define Q_QML_PROFILE(feature, profiler, Method) | 
| 72 | #define Q_QML_OC_PROFILE(member, Code) | 
| 73 |  | 
| 74 | class QQmlProfiler {}; | 
| 75 |  | 
| 76 | struct QQmlBindingProfiler | 
| 77 | { | 
| 78 |     QQmlBindingProfiler(quintptr, QV4::Function *) {} | 
| 79 | }; | 
| 80 |  | 
| 81 | struct QQmlHandlingSignalProfiler | 
| 82 | { | 
| 83 |     QQmlHandlingSignalProfiler(quintptr, QQmlBoundSignalExpression *) {} | 
| 84 | }; | 
| 85 |  | 
| 86 | struct QQmlCompilingProfiler | 
| 87 | { | 
| 88 |     QQmlCompilingProfiler(quintptr, QQmlDataBlob *) {} | 
| 89 | }; | 
| 90 |  | 
| 91 | struct QQmlVmeProfiler { | 
| 92 |     QQmlVmeProfiler() {} | 
| 93 |  | 
| 94 |     void init(quintptr, int) {} | 
| 95 |  | 
| 96 |     const QV4::CompiledData::Object *pop() { return nullptr; } | 
| 97 |     void push(const QV4::CompiledData::Object *) {} | 
| 98 |  | 
| 99 |     static const quintptr profiler = 0; | 
| 100 | }; | 
| 101 |  | 
| 102 | struct QQmlObjectCreationProfiler | 
| 103 | { | 
| 104 |     QQmlObjectCreationProfiler(quintptr, const QV4::CompiledData::Object *) {} | 
| 105 |     void update(QV4::CompiledData::CompilationUnit *, const QV4::CompiledData::Object *, | 
| 106 |                 const QString &, const QUrl &) {} | 
| 107 | }; | 
| 108 |  | 
| 109 | struct QQmlObjectCompletionProfiler | 
| 110 | { | 
| 111 |     QQmlObjectCompletionProfiler(QQmlVmeProfiler *) {} | 
| 112 | }; | 
| 113 |  | 
| 114 | #else | 
| 115 |  | 
| 116 | #define Q_QML_PROFILE_IF_ENABLED(feature, profiler, Code)\ | 
| 117 |     if (profiler && (profiler->featuresEnabled & (1 << feature))) {\ | 
| 118 |         Code;\ | 
| 119 |     } else\ | 
| 120 |         (void)0 | 
| 121 |  | 
| 122 | #define Q_QML_PROFILE(feature, profiler, Method)\ | 
| 123 |     Q_QML_PROFILE_IF_ENABLED(feature, profiler, profiler->Method) | 
| 124 |  | 
| 125 | #define Q_QML_OC_PROFILE(member, Code)\ | 
| 126 |     Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, member.profiler, Code) | 
| 127 |  | 
| 128 | // This struct is somewhat dangerous to use: | 
| 129 | // The messageType is a bit field. You can pack multiple messages into | 
| 130 | // one object, e.g. RangeStart and RangeLocation. Each one will be read | 
| 131 | // independently when converting to QByteArrays. Thus you can only pack | 
| 132 | // messages if their data doesn't overlap. It's up to you to figure that | 
| 133 | // out. | 
| 134 | struct Q_AUTOTEST_EXPORT QQmlProfilerData : public QQmlProfilerDefinitions | 
| 135 | { | 
| 136 |     QQmlProfilerData(qint64 time = -1, int messageType = -1, | 
| 137 |                      RangeType detailType = MaximumRangeType, quintptr locationId = 0) : | 
| 138 |         time(time), locationId(locationId), messageType(messageType), detailType(detailType) | 
| 139 |     {} | 
| 140 |  | 
| 141 |     qint64 time; | 
| 142 |     quintptr locationId; | 
| 143 |  | 
| 144 |     int messageType;        //bit field of QQmlProfilerService::Message | 
| 145 |     RangeType detailType; | 
| 146 | }; | 
| 147 |  | 
| 148 | Q_DECLARE_TYPEINFO(QQmlProfilerData, Q_MOVABLE_TYPE); | 
| 149 |  | 
| 150 | class Q_QML_PRIVATE_EXPORT QQmlProfiler : public QObject, public QQmlProfilerDefinitions { | 
| 151 |     Q_OBJECT | 
| 152 | public: | 
| 153 |  | 
| 154 |     struct Location { | 
| 155 |         Location(const QQmlSourceLocation &location = QQmlSourceLocation(), | 
| 156 |                  const QUrl &url = QUrl()) : | 
| 157 |             location(location), url(url) {} | 
| 158 |         QQmlSourceLocation location; | 
| 159 |         QUrl url; | 
| 160 |     }; | 
| 161 |  | 
| 162 |     // Unfortunately we have to resolve the locations right away because the QML context might not | 
| 163 |     // be available anymore when we send the data. | 
| 164 |     struct RefLocation : public Location { | 
| 165 |         RefLocation() | 
| 166 |             : Location(), locationType(MaximumRangeType), something(nullptr), sent(false) | 
| 167 |         { | 
| 168 |         } | 
| 169 |  | 
| 170 |         RefLocation(QV4::Function *ref) | 
| 171 |             : Location(ref->sourceLocation()), locationType(Binding), sent(false) | 
| 172 |         { | 
| 173 |             function = ref; | 
| 174 |             function->executableCompilationUnit()->addref(); | 
| 175 |         } | 
| 176 |  | 
| 177 |         RefLocation(QV4::ExecutableCompilationUnit *ref, const QUrl &url, | 
| 178 |                     const QV4::CompiledData::Object *obj, const QString &type) | 
| 179 |             : Location(QQmlSourceLocation(type, obj->location.line, obj->location.column), url), | 
| 180 |               locationType(Creating), sent(false) | 
| 181 |         { | 
| 182 |             unit = ref; | 
| 183 |             unit->addref(); | 
| 184 |         } | 
| 185 |  | 
| 186 |         RefLocation(QQmlBoundSignalExpression *ref) | 
| 187 |             : Location(ref->sourceLocation()), locationType(HandlingSignal), sent(false) | 
| 188 |         { | 
| 189 |             boundSignal = ref; | 
| 190 |             boundSignal->addref(); | 
| 191 |         } | 
| 192 |  | 
| 193 |         RefLocation(QQmlDataBlob *ref) | 
| 194 |             : Location(QQmlSourceLocation(), ref->url()), locationType(Compiling), sent(false) | 
| 195 |         { | 
| 196 |             blob = ref; | 
| 197 |             blob->addref(); | 
| 198 |         } | 
| 199 |  | 
| 200 |         RefLocation(const RefLocation &other) | 
| 201 |             : Location(other), | 
| 202 |               locationType(other.locationType), | 
| 203 |               function(other.function), | 
| 204 |               sent(other.sent) | 
| 205 |         { | 
| 206 |             addref(); | 
| 207 |         } | 
| 208 |  | 
| 209 |         RefLocation &operator=(const RefLocation &other) | 
| 210 |         { | 
| 211 |             if (this != &other) { | 
| 212 |                 release(); | 
| 213 |                 Location::operator=(other); | 
| 214 |                 locationType = other.locationType; | 
| 215 |                 function = other.function; | 
| 216 |                 sent = other.sent; | 
| 217 |                 addref(); | 
| 218 |             } | 
| 219 |             return *this; | 
| 220 |         } | 
| 221 |  | 
| 222 |         ~RefLocation() | 
| 223 |         { | 
| 224 |             release(); | 
| 225 |         } | 
| 226 |  | 
| 227 |         void addref() | 
| 228 |         { | 
| 229 |             if (isNull()) | 
| 230 |                 return; | 
| 231 |  | 
| 232 |             switch (locationType) { | 
| 233 |             case Binding: | 
| 234 |                 function->executableCompilationUnit()->addref(); | 
| 235 |                 break; | 
| 236 |             case Creating: | 
| 237 |                 unit->addref(); | 
| 238 |                 break; | 
| 239 |             case HandlingSignal: | 
| 240 |                 boundSignal->addref(); | 
| 241 |                 break; | 
| 242 |             case Compiling: | 
| 243 |                 blob->addref(); | 
| 244 |                 break; | 
| 245 |             default: | 
| 246 |                 Q_ASSERT(locationType == MaximumRangeType); | 
| 247 |                 break; | 
| 248 |             } | 
| 249 |         } | 
| 250 |  | 
| 251 |         void release() | 
| 252 |         { | 
| 253 |             if (isNull()) | 
| 254 |                 return; | 
| 255 |  | 
| 256 |             switch (locationType) { | 
| 257 |             case Binding: | 
| 258 |                 function->executableCompilationUnit()->release(); | 
| 259 |                 break; | 
| 260 |             case Creating: | 
| 261 |                 unit->release(); | 
| 262 |                 break; | 
| 263 |             case HandlingSignal: | 
| 264 |                 boundSignal->release(); | 
| 265 |                 break; | 
| 266 |             case Compiling: | 
| 267 |                 blob->release(); | 
| 268 |                 break; | 
| 269 |             default: | 
| 270 |                 Q_ASSERT(locationType == MaximumRangeType); | 
| 271 |                 break; | 
| 272 |             } | 
| 273 |         } | 
| 274 |  | 
| 275 |         bool isValid() const | 
| 276 |         { | 
| 277 |             return locationType != MaximumRangeType; | 
| 278 |         } | 
| 279 |  | 
| 280 |         bool isNull() const | 
| 281 |         { | 
| 282 |             return !something; | 
| 283 |         } | 
| 284 |  | 
| 285 |         RangeType locationType; | 
| 286 |         union { | 
| 287 |             QV4::Function *function; | 
| 288 |             QV4::ExecutableCompilationUnit *unit; | 
| 289 |             QQmlBoundSignalExpression *boundSignal; | 
| 290 |             QQmlDataBlob *blob; | 
| 291 |             void *something; | 
| 292 |         }; | 
| 293 |         bool sent; | 
| 294 |     }; | 
| 295 |  | 
| 296 |     typedef QHash<quintptr, Location> LocationHash; | 
| 297 |  | 
| 298 |     void startBinding(QV4::Function *function) | 
| 299 |     { | 
| 300 |         // Use the QV4::Function as ID, as that is common among different instances of the same | 
| 301 |         // component. QQmlBinding is per instance. | 
| 302 |         // Add 1 to the ID, to make it different from the IDs the V4 and signal handling profilers | 
| 303 |         // produce. The +1 makes the pointer point into the middle of the QV4::Function. Thus it | 
| 304 |         // still points to valid memory but we cannot accidentally create a duplicate key from | 
| 305 |         // another object. | 
| 306 |         // If there is no function, use a static but valid address: The profiler itself. | 
| 307 |         quintptr locationId = function ? id(pointer: function) + 1 : id(pointer: this); | 
| 308 |         m_data.append(t: QQmlProfilerData(m_timer.nsecsElapsed(), | 
| 309 |                                        (1 << RangeStart | 1 << RangeLocation), Binding, | 
| 310 |                                        locationId)); | 
| 311 |  | 
| 312 |         RefLocation &location = m_locations[locationId]; | 
| 313 |         if (!location.isValid()) { | 
| 314 |             if (function) | 
| 315 |                 location = RefLocation(function); | 
| 316 |             else // Make it valid without actually providing a location | 
| 317 |                 location.locationType = Binding; | 
| 318 |         } | 
| 319 |     } | 
| 320 |  | 
| 321 |     // Have toByteArrays() construct another RangeData event from the same QString later. | 
| 322 |     // This is somewhat pointless but important for backwards compatibility. | 
| 323 |     void startCompiling(QQmlDataBlob *blob) | 
| 324 |     { | 
| 325 |         quintptr locationId(id(pointer: blob)); | 
| 326 |         m_data.append(t: QQmlProfilerData(m_timer.nsecsElapsed(), | 
| 327 |                                        (1 << RangeStart | 1 << RangeLocation | 1 << RangeData), | 
| 328 |                                        Compiling, locationId)); | 
| 329 |  | 
| 330 |         RefLocation &location = m_locations[locationId]; | 
| 331 |         if (!location.isValid()) | 
| 332 |             location = RefLocation(blob); | 
| 333 |     } | 
| 334 |  | 
| 335 |     void startHandlingSignal(QQmlBoundSignalExpression *expression) | 
| 336 |     { | 
| 337 |         // Use the QV4::Function as ID, as that is common among different instances of the same | 
| 338 |         // component. QQmlBoundSignalExpression is per instance. | 
| 339 |         // Add 2 to the ID, to make it different from the IDs the V4 and binding profilers produce. | 
| 340 |         // The +2 makes the pointer point into the middle of the QV4::Function. Thus it still points | 
| 341 |         // to valid memory but we cannot accidentally create a duplicate key from another object. | 
| 342 |         quintptr locationId(id(pointer: expression->function()) + 2); | 
| 343 |         m_data.append(t: QQmlProfilerData(m_timer.nsecsElapsed(), | 
| 344 |                                        (1 << RangeStart | 1 << RangeLocation), HandlingSignal, | 
| 345 |                                        locationId)); | 
| 346 |  | 
| 347 |         RefLocation &location = m_locations[locationId]; | 
| 348 |         if (!location.isValid()) | 
| 349 |             location = RefLocation(expression); | 
| 350 |     } | 
| 351 |  | 
| 352 |     void startCreating(const QV4::CompiledData::Object *obj) | 
| 353 |     { | 
| 354 |         m_data.append(t: QQmlProfilerData(m_timer.nsecsElapsed(), | 
| 355 |                                        (1 << RangeStart | 1 << RangeLocation | 1 << RangeData), | 
| 356 |                                        Creating, id(pointer: obj))); | 
| 357 |     } | 
| 358 |  | 
| 359 |     void updateCreating(const QV4::CompiledData::Object *obj, | 
| 360 |                         QV4::ExecutableCompilationUnit *ref, | 
| 361 |                         const QUrl &url, const QString &type) | 
| 362 |     { | 
| 363 |         quintptr locationId(id(pointer: obj)); | 
| 364 |         RefLocation &location = m_locations[locationId]; | 
| 365 |         if (!location.isValid()) | 
| 366 |             location = RefLocation(ref, url, obj, type); | 
| 367 |     } | 
| 368 |  | 
| 369 |     template<RangeType Range> | 
| 370 |     void endRange() | 
| 371 |     { | 
| 372 |         m_data.append(t: QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeEnd, Range)); | 
| 373 |     } | 
| 374 |  | 
| 375 |     QQmlProfiler(); | 
| 376 |  | 
| 377 |     quint64 featuresEnabled; | 
| 378 |  | 
| 379 |     template<typename Object> | 
| 380 |     static quintptr id(const Object *pointer) | 
| 381 |     { | 
| 382 |         return reinterpret_cast<quintptr>(pointer); | 
| 383 |     } | 
| 384 |  | 
| 385 |     void startProfiling(quint64 features); | 
| 386 |     void stopProfiling(); | 
| 387 |     void reportData(); | 
| 388 |     void setTimer(const QElapsedTimer &timer) { m_timer = timer; } | 
| 389 |  | 
| 390 | signals: | 
| 391 |     void dataReady(const QVector<QQmlProfilerData> &, const QQmlProfiler::LocationHash &); | 
| 392 |  | 
| 393 | protected: | 
| 394 |     QElapsedTimer m_timer; | 
| 395 |     QHash<quintptr, RefLocation> m_locations; | 
| 396 |     QVector<QQmlProfilerData> m_data; | 
| 397 | }; | 
| 398 |  | 
| 399 | // | 
| 400 | // RAII helper structs | 
| 401 | // | 
| 402 |  | 
| 403 | struct QQmlProfilerHelper : public QQmlProfilerDefinitions { | 
| 404 |     QQmlProfiler *profiler; | 
| 405 |     QQmlProfilerHelper(QQmlProfiler *profiler) : profiler(profiler) {} | 
| 406 | }; | 
| 407 |  | 
| 408 | struct QQmlBindingProfiler : public QQmlProfilerHelper { | 
| 409 |     QQmlBindingProfiler(QQmlProfiler *profiler, QV4::Function *function) : | 
| 410 |         QQmlProfilerHelper(profiler) | 
| 411 |     { | 
| 412 |         Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileBinding, profiler, | 
| 413 |                       startBinding(function)); | 
| 414 |     } | 
| 415 |  | 
| 416 |     ~QQmlBindingProfiler() | 
| 417 |     { | 
| 418 |         Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileBinding, profiler, | 
| 419 |                       endRange<Binding>()); | 
| 420 |     } | 
| 421 | }; | 
| 422 |  | 
| 423 | struct QQmlHandlingSignalProfiler : public QQmlProfilerHelper { | 
| 424 |     QQmlHandlingSignalProfiler(QQmlProfiler *profiler, QQmlBoundSignalExpression *expression) : | 
| 425 |         QQmlProfilerHelper(profiler) | 
| 426 |     { | 
| 427 |         Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileHandlingSignal, profiler, | 
| 428 |                       startHandlingSignal(expression)); | 
| 429 |     } | 
| 430 |  | 
| 431 |     ~QQmlHandlingSignalProfiler() | 
| 432 |     { | 
| 433 |         Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileHandlingSignal, profiler, | 
| 434 |                       endRange<QQmlProfiler::HandlingSignal>()); | 
| 435 |     } | 
| 436 | }; | 
| 437 |  | 
| 438 | struct QQmlCompilingProfiler : public QQmlProfilerHelper { | 
| 439 |     QQmlCompilingProfiler(QQmlProfiler *profiler, QQmlDataBlob *blob) : | 
| 440 |         QQmlProfilerHelper(profiler) | 
| 441 |     { | 
| 442 |         Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCompiling, profiler, startCompiling(blob)); | 
| 443 |     } | 
| 444 |  | 
| 445 |     ~QQmlCompilingProfiler() | 
| 446 |     { | 
| 447 |         Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCompiling, profiler, endRange<Compiling>()); | 
| 448 |     } | 
| 449 | }; | 
| 450 |  | 
| 451 | struct QQmlVmeProfiler : public QQmlProfilerDefinitions { | 
| 452 | public: | 
| 453 |  | 
| 454 |     QQmlVmeProfiler() : profiler(nullptr) {} | 
| 455 |  | 
| 456 |     void init(QQmlProfiler *p, int maxDepth) | 
| 457 |     { | 
| 458 |         profiler = p; | 
| 459 |         ranges.allocate(size: maxDepth); | 
| 460 |     } | 
| 461 |  | 
| 462 |     const QV4::CompiledData::Object *pop() | 
| 463 |     { | 
| 464 |         if (ranges.count() > 0) | 
| 465 |             return ranges.pop(); | 
| 466 |         else | 
| 467 |             return nullptr; | 
| 468 |     } | 
| 469 |  | 
| 470 |     void push(const QV4::CompiledData::Object *object) | 
| 471 |     { | 
| 472 |         if (ranges.capacity() > ranges.count()) | 
| 473 |             ranges.push(o: object); | 
| 474 |     } | 
| 475 |  | 
| 476 |     QQmlProfiler *profiler; | 
| 477 |  | 
| 478 | private: | 
| 479 |     QFiniteStack<const QV4::CompiledData::Object *> ranges; | 
| 480 | }; | 
| 481 |  | 
| 482 | class QQmlObjectCreationProfiler { | 
| 483 | public: | 
| 484 |  | 
| 485 |     QQmlObjectCreationProfiler(QQmlProfiler *profiler, const QV4::CompiledData::Object *obj) | 
| 486 |         : profiler(profiler) | 
| 487 |     { | 
| 488 |         Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, startCreating(obj)); | 
| 489 |     } | 
| 490 |  | 
| 491 |     ~QQmlObjectCreationProfiler() | 
| 492 |     { | 
| 493 |         Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, endRange<QQmlProfilerDefinitions::Creating>()); | 
| 494 |     } | 
| 495 |  | 
| 496 |     void update(QV4::ExecutableCompilationUnit *ref, const QV4::CompiledData::Object *obj, | 
| 497 |                 const QString &typeName, const QUrl &url) | 
| 498 |     { | 
| 499 |         profiler->updateCreating(obj, ref, url, type: typeName); | 
| 500 |     } | 
| 501 |  | 
| 502 | private: | 
| 503 |     QQmlProfiler *profiler; | 
| 504 | }; | 
| 505 |  | 
| 506 | class QQmlObjectCompletionProfiler { | 
| 507 | public: | 
| 508 |     QQmlObjectCompletionProfiler(QQmlVmeProfiler *parent) : | 
| 509 |         profiler(parent->profiler) | 
| 510 |     { | 
| 511 |         Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler, { | 
| 512 |             profiler->startCreating(parent->pop()); | 
| 513 |         }); | 
| 514 |     } | 
| 515 |  | 
| 516 |     ~QQmlObjectCompletionProfiler() | 
| 517 |     { | 
| 518 |         Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, | 
| 519 |                       endRange<QQmlProfilerDefinitions::Creating>()); | 
| 520 |     } | 
| 521 | private: | 
| 522 |     QQmlProfiler *profiler; | 
| 523 | }; | 
| 524 |  | 
| 525 | #endif // QT_CONFIG(qml_debug) | 
| 526 |  | 
| 527 | QT_END_NAMESPACE | 
| 528 |  | 
| 529 | #if QT_CONFIG(qml_debug) | 
| 530 |  | 
| 531 | Q_DECLARE_METATYPE(QVector<QQmlProfilerData>) | 
| 532 | Q_DECLARE_METATYPE(QQmlProfiler::LocationHash) | 
| 533 |  | 
| 534 | #endif // QT_CONFIG(qml_debug) | 
| 535 |  | 
| 536 | #endif // QQMLPROFILER_P_H | 
| 537 |  |