1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qqmlvme_p.h"
44 #include "qqmlcompiler_p.h"
45 #include "qqmlboundsignal_p.h"
46 #include "qqmlstringconverters_p.h"
47 #include <private/qmetaobjectbuilder_p.h>
48 #include "qqmldata_p.h"
50 #include "qqmlcustomparser_p.h"
51 #include "qqmlengine.h"
52 #include "qqmlcontext.h"
53 #include "qqmlcomponent.h"
54 #include "qqmlcomponentattached_p.h"
55 #include "qqmlbinding_p.h"
56 #include "qqmlengine_p.h"
57 #include "qqmlcomponent_p.h"
58 #include "qqmlvmemetaobject_p.h"
59 #include "qqmlcontext_p.h"
60 #include <private/qv4bindings_p.h>
61 #include <private/qv8bindings_p.h>
62 #include "qqmlglobal_p.h"
63 #include <private/qfinitestack_p.h>
64 #include "qqmlscriptstring.h"
65 #include "qqmlscriptstring_p.h"
66 #include "qqmlpropertyvalueinterceptor_p.h"
67 #include "qqmlvaluetypeproxybinding_p.h"
73 #include <QtCore/qdebug.h>
74 #include <QtCore/qvarlengtharray.h>
75 #include <QtCore/qcoreapplication.h>
76 #include <QtCore/qdatetime.h>
77 #include <QtCore/qvarlengtharray.h>
78 #include <QtQml/qjsvalue.h>
82 using namespace QQmlVMETypes;
84 #define VME_EXCEPTION(desc, line) \
87 error.setDescription(desc.trimmed()); \
88 error.setLine(line); \
89 error.setUrl(COMP->url); \
94 void QQmlVME::init(QQmlContextData *ctxt, QQmlCompiledData *comp, int start,
95 QQmlContextData *creation)
103 creationContext = creation;
107 initState.context = ctxt;
108 initState.compiledData = comp;
109 initState.instructionStream = comp->bytecode.constData() + start;
110 states.push(initState);
112 typedef QQmlInstruction I;
113 I *i = (I *)initState.instructionStream;
115 Q_ASSERT(comp->instructionType(i) == I::Init);
117 objects.allocate(i->init.objectStackSize);
118 lists.allocate(i->init.listStackSize);
119 bindValues.allocate(i->init.bindingsSize);
120 parserStatus.allocate(i->init.parserStatusSize);
122 #ifdef QML_ENABLE_TRACE
123 parserStatusData.allocate(i->init.parserStatusSize);
124 rootComponent = comp;
128 engine = ctxt->engine;
131 bool QQmlVME::initDeferred(QObject *object)
133 QQmlData *data = QQmlData::get(object);
135 if (!data || !data->context || !data->compiledData)
138 QQmlContextData *ctxt = data->context;
139 QQmlCompiledData *comp = data->compiledData;
140 int start = data->deferredIdx;
143 initState.flags = State::Deferred;
144 initState.context = ctxt;
145 initState.compiledData = comp;
146 initState.instructionStream = comp->bytecode.constData() + start;
147 states.push(initState);
149 typedef QQmlInstruction I;
150 I *i = (I *)initState.instructionStream;
152 Q_ASSERT(comp->instructionType(i) == I::DeferInit);
154 objects.allocate(i->deferInit.objectStackSize);
155 lists.allocate(i->deferInit.listStackSize);
156 bindValues.allocate(i->deferInit.bindingsSize);
157 parserStatus.allocate(i->deferInit.parserStatusSize);
159 objects.push(object);
161 #ifdef QML_ENABLE_TRACE
162 parserStatusData.allocate(i->deferInit.parserStatusSize);
163 rootComponent = comp;
167 engine = ctxt->engine;
173 struct ActiveVMERestorer
175 ActiveVMERestorer(QQmlVME *me, QQmlEnginePrivate *ep)
176 : ep(ep), oldVME(ep->activeVME) { ep->activeVME = me; }
177 ~ActiveVMERestorer() { ep->activeVME = oldVME; }
179 QQmlEnginePrivate *ep;
184 QObject *QQmlVME::execute(QList<QQmlError> *errors, const Interrupt &interrupt)
186 Q_ASSERT(states.count() >= 1);
188 #ifdef QML_ENABLE_TRACE
189 QQmlTrace trace("VME Execute");
190 trace.addDetail("URL", rootComponent->url);
193 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(states.at(0).context->engine);
195 ActiveVMERestorer restore(this, ep);
197 QObject *rv = run(errors, interrupt);
202 inline bool fastHasBinding(QObject *o, int index)
204 QQmlData *ddata = static_cast<QQmlData *>(QObjectPrivate::get(o)->declarativeData);
206 index &= 0x0000FFFF; // To handle value types
208 return ddata && (ddata->bindingBitsSize > index) &&
209 (ddata->bindingBits[index / 32] & (1 << (index % 32)));
212 static void removeBindingOnProperty(QObject *o, int index)
214 int coreIndex = index & 0x0000FFFF;
215 int valueTypeIndex = (index & 0xFFFF0000 ? index >> 16 : -1);
217 QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(o, coreIndex, valueTypeIndex, 0);
218 if (binding) binding->destroy();
221 static QVariant variantFromString(const QString &string)
223 return QQmlStringConverters::variantFromString(string);
226 // XXX we probably need some form of "work count" here to prevent us checking this
227 // for every instruction.
228 #define QML_BEGIN_INSTR_COMMON(I) { \
229 const QQmlInstructionMeta<(int)QQmlInstruction::I>::DataType &instr = QQmlInstructionMeta<(int)QQmlInstruction::I>::data(*genericInstr); \
230 INSTRUCTIONSTREAM += QQmlInstructionMeta<(int)QQmlInstruction::I>::Size; \
233 #ifdef QML_THREADED_VME_INTERPRETER
234 # define QML_BEGIN_INSTR(I) op_##I: \
235 QML_BEGIN_INSTR_COMMON(I)
237 # define QML_NEXT_INSTR(I) { \
238 if (watcher.hasRecursed()) return 0; \
239 genericInstr = reinterpret_cast<const QQmlInstruction *>(INSTRUCTIONSTREAM); \
240 goto *genericInstr->common.code; \
243 # define QML_END_INSTR(I) } \
244 if (watcher.hasRecursed()) return 0; \
245 genericInstr = reinterpret_cast<const QQmlInstruction *>(INSTRUCTIONSTREAM); \
246 if (interrupt.shouldInterrupt()) return 0; \
247 goto *genericInstr->common.code;
250 # define QML_BEGIN_INSTR(I) \
251 case QQmlInstruction::I: \
252 QML_BEGIN_INSTR_COMMON(I)
254 # define QML_NEXT_INSTR(I) { \
255 if (watcher.hasRecursed()) return 0; \
259 # define QML_END_INSTR(I) \
260 if (watcher.hasRecursed() || interrupt.shouldInterrupt()) return 0; \
264 #define QML_STORE_VALUE(name, cpptype, value) \
265 QML_BEGIN_INSTR(name) \
267 void *a[] = { (void *)&v, 0, &status, &flags }; \
268 QObject *target = objects.top(); \
269 CLEAN_PROPERTY(target, instr.propertyIndex); \
270 QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.propertyIndex, a); \
273 #define QML_STORE_PROVIDER_VALUE(name, type, value) \
274 QML_BEGIN_INSTR(name) \
275 struct { void *data[4]; } buffer; \
276 if (QQml_valueTypeProvider()->storeValueType(type, &value, &buffer, sizeof(buffer))) { \
277 void *a[] = { reinterpret_cast<void *>(&buffer), 0, &status, &flags }; \
278 QObject *target = objects.top(); \
279 CLEAN_PROPERTY(target, instr.propertyIndex); \
280 QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.propertyIndex, a); \
284 #define QML_STORE_LIST(name, cpptype, value) \
285 QML_BEGIN_INSTR(name) \
288 void *a[] = { (void *)&v, 0, &status, &flags }; \
289 QObject *target = objects.top(); \
290 CLEAN_PROPERTY(target, instr.propertyIndex); \
291 QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.propertyIndex, a); \
294 #define QML_STORE_VAR(name, value) \
295 QML_BEGIN_INSTR(name) \
296 v8::Handle<v8::Value> v8value = value; \
297 QObject *target = objects.top(); \
298 CLEAN_PROPERTY(target, instr.propertyIndex); \
299 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(target); \
301 vmemo->setVMEProperty(instr.propertyIndex, v8value); \
304 #define QML_STORE_POINTER(name, value) \
305 QML_BEGIN_INSTR(name) \
306 void *a[] = { (void *)value, 0, &status, &flags }; \
307 QObject *target = objects.top(); \
308 CLEAN_PROPERTY(target, instr.propertyIndex); \
309 QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.propertyIndex, a); \
312 #define CLEAN_PROPERTY(o, index) \
313 if (fastHasBinding(o, index)) \
314 removeBindingOnProperty(o, index)
316 QObject *QQmlVME::run(QList<QQmlError> *errors,
317 const Interrupt &interrupt
318 #ifdef QML_THREADED_VME_INTERPRETER
319 , void ***storeJumpTable
323 #ifdef QML_THREADED_VME_INTERPRETER
324 if (storeJumpTable) {
325 #define QML_INSTR_ADDR(I, FMT) &&op_##I,
326 static void *jumpTable[] = {
327 FOR_EACH_QML_INSTR(QML_INSTR_ADDR)
329 #undef QML_INSTR_ADDR
330 *storeJumpTable = jumpTable;
334 Q_ASSERT(errors->isEmpty());
335 Q_ASSERT(states.count() >= 1);
337 QQmlEngine *engine = states.at(0).context->engine;
338 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
340 // Need a v8 handle scope and execution context for StoreVar instructions.
341 v8::HandleScope handleScope;
342 v8::Context::Scope contextScope(ep->v8engine()->context());
344 int status = -1; // needed for dbus
345 QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::BypassInterceptor |
346 QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
348 QRecursionWatcher<QQmlVME, &QQmlVME::recursion> watcher(this);
350 #define COMP states.top().compiledData
351 #define CTXT states.top().context
352 #define INSTRUCTIONSTREAM states.top().instructionStream
353 #define BINDINGSKIPLIST states.top().bindingSkipList
355 #define TYPES COMP->types
356 #define PRIMITIVES COMP->primitives
357 #define DATAS COMP->datas
358 #define PROGRAMS COMP->programs
359 #define PROPERTYCACHES COMP->propertyCaches
360 #define SCRIPTS COMP->scripts
361 #define URLS COMP->urls
363 #ifdef QML_THREADED_VME_INTERPRETER
364 const QQmlInstruction *genericInstr = reinterpret_cast<const QQmlInstruction *>(INSTRUCTIONSTREAM);
365 goto *genericInstr->common.code;
368 const QQmlInstruction *genericInstr = reinterpret_cast<const QQmlInstruction *>(INSTRUCTIONSTREAM);
370 switch (genericInstr->common.instructionType) {
373 // Store a created object in a property. These all pop from the objects stack.
374 QML_STORE_VALUE(StoreObject, QObject *, objects.pop());
375 QML_STORE_VALUE(StoreVariantObject, QVariant, QVariant::fromValue(objects.pop()));
376 QML_STORE_VAR(StoreVarObject, ep->v8engine()->newQObject(objects.pop()));
378 // Store a literal value in a corresponding property
379 QML_STORE_VALUE(StoreFloat, float, instr.value);
380 QML_STORE_VALUE(StoreDouble, double, instr.value);
381 QML_STORE_VALUE(StoreBool, bool, instr.value);
382 QML_STORE_VALUE(StoreInteger, int, instr.value);
383 QML_STORE_PROVIDER_VALUE(StoreColor, QMetaType::QColor, instr.value);
384 QML_STORE_VALUE(StoreDate, QDate, QDate::fromJulianDay(instr.value));
385 QML_STORE_VALUE(StoreDateTime, QDateTime,
386 QDateTime(QDate::fromJulianDay(instr.date), *(QTime *)&instr.time));
387 QML_STORE_POINTER(StoreTime, (QTime *)&instr.time);
388 QML_STORE_POINTER(StorePoint, (QPoint *)&instr.point);
389 QML_STORE_POINTER(StorePointF, (QPointF *)&instr.point);
390 QML_STORE_POINTER(StoreSize, (QSize *)&instr.size);
391 QML_STORE_POINTER(StoreSizeF, (QSizeF *)&instr.size);
392 QML_STORE_POINTER(StoreRect, (QRect *)&instr.rect);
393 QML_STORE_POINTER(StoreRectF, (QRectF *)&instr.rect);
394 QML_STORE_PROVIDER_VALUE(StoreVector3D, QMetaType::QVector3D, instr.vector);
395 QML_STORE_PROVIDER_VALUE(StoreVector4D, QMetaType::QVector4D, instr.vector);
396 QML_STORE_POINTER(StoreString, &PRIMITIVES.at(instr.value));
397 QML_STORE_POINTER(StoreByteArray, &DATAS.at(instr.value));
398 QML_STORE_POINTER(StoreUrl, &URLS.at(instr.value));
399 QML_STORE_VALUE(StoreTrString, QString,
400 QCoreApplication::translate(DATAS.at(instr.context).constData(),
401 DATAS.at(instr.text).constData(),
402 DATAS.at(instr.comment).constData(),
404 QML_STORE_VALUE(StoreTrIdString, QString, qtTrId(DATAS.at(instr.text).constData(), instr.n));
406 // Store a literal value in a QList
407 QML_STORE_LIST(StoreStringList, QStringList, PRIMITIVES.at(instr.value));
408 QML_STORE_LIST(StoreStringQList, QList<QString>, PRIMITIVES.at(instr.value));
409 QML_STORE_LIST(StoreUrlQList, QList<QUrl>, URLS.at(instr.value));
410 QML_STORE_LIST(StoreDoubleQList, QList<double>, instr.value);
411 QML_STORE_LIST(StoreBoolQList, QList<bool>, instr.value);
412 QML_STORE_LIST(StoreIntegerQList, QList<int>, instr.value);
414 // Store a literal value in a QVariant property
415 QML_STORE_VALUE(StoreVariant, QVariant, variantFromString(PRIMITIVES.at(instr.value)));
416 QML_STORE_VALUE(StoreVariantInteger, QVariant, QVariant(instr.value));
417 QML_STORE_VALUE(StoreVariantDouble, QVariant, QVariant(instr.value));
418 QML_STORE_VALUE(StoreVariantBool, QVariant, QVariant(instr.value));
420 // Store a literal value in a var property.
421 // We deliberately do not use string converters here
422 QML_STORE_VAR(StoreVar, ep->v8engine()->fromVariant(PRIMITIVES.at(instr.value)));
423 QML_STORE_VAR(StoreVarInteger, v8::Integer::New(instr.value));
424 QML_STORE_VAR(StoreVarDouble, v8::Number::New(instr.value));
425 QML_STORE_VAR(StoreVarBool, v8::Boolean::New(instr.value));
427 // Store a literal value in a QJSValue property.
428 QML_STORE_VALUE(StoreJSValueString, QJSValue, QJSValue(PRIMITIVES.at(instr.value)));
429 QML_STORE_VALUE(StoreJSValueInteger, QJSValue, QJSValue(instr.value));
430 QML_STORE_VALUE(StoreJSValueDouble, QJSValue, QJSValue(instr.value));
431 QML_STORE_VALUE(StoreJSValueBool, QJSValue, QJSValue(instr.value));
433 QML_BEGIN_INSTR(Init)
434 // Ensure that the compiled data has been initialized
435 if (!COMP->isInitialized()) COMP->initialize(engine);
437 QQmlContextData *parentCtxt = CTXT;
438 CTXT = new QQmlContextData;
439 CTXT->isInternal = true;
440 CTXT->url = COMP->url;
441 CTXT->urlString = COMP->name;
442 CTXT->imports = COMP->importCache;
443 CTXT->imports->addref();
444 CTXT->setParent(parentCtxt);
445 if (instr.contextCache != -1)
446 CTXT->setIdPropertyData(COMP->contextCaches.at(instr.contextCache));
447 if (instr.compiledBinding != -1) {
448 const char *v4data = DATAS.at(instr.compiledBinding).constData();
449 CTXT->v4bindings = new QV4Bindings(v4data, CTXT);
451 if (states.count() == 1) {
453 rootContext->activeVMEData = data;
454 rootContext->isRootObjectInCreation = true;
456 if (states.count() == 1 && !creationContext.isNull()) {
457 // A component that is logically created within another component instance shares the
458 // same instances of script imports. For example:
460 // import QtQuick 2.0
461 // import "test.js" as Test
463 // model: Test.getModel()
464 // delegate: Component {
465 // Text { text: Test.getValue(index); }
469 // Has the same "Test" instance. To implement this, we simply copy the v8 handles into
470 // the inner context. We have to create a fresh persistent handle for each to prevent
471 // double dispose. It is possible we could do this more efficiently using some form of
472 // referencing instead.
473 CTXT->importedScripts = creationContext->importedScripts;
474 for (int ii = 0; ii < CTXT->importedScripts.count(); ++ii)
475 CTXT->importedScripts[ii] = qPersistentNew<v8::Object>(CTXT->importedScripts[ii]);
479 QML_BEGIN_INSTR(DeferInit)
480 QML_END_INSTR(DeferInit)
482 QML_BEGIN_INSTR(Done)
485 if (states.isEmpty())
489 QML_BEGIN_INSTR(CreateQMLObject)
490 const QQmlCompiledData::TypeReference &type = TYPES.at(instr.type);
491 Q_ASSERT(type.component);
493 states.push(State());
495 State *cState = &states[states.count() - 2];
496 State *nState = &states[states.count() - 1];
498 nState->context = cState->context;
499 nState->compiledData = type.component;
500 nState->instructionStream = type.component->bytecode.constData();
502 if (instr.bindingBits != -1) {
503 const QByteArray &bits = cState->compiledData->datas.at(instr.bindingBits);
504 nState->bindingSkipList = QBitField((const quint32*)bits.constData(),
508 nState->bindingSkipList = nState->bindingSkipList.united(cState->bindingSkipList);
510 // As the state in the state stack changed, execution will continue in the new program.
511 QML_END_INSTR(CreateQMLObject)
513 QML_BEGIN_INSTR(CompleteQMLObject)
514 QObject *o = objects.top();
517 QQmlData *ddata = QQmlData::get(o);
520 if (states.count() == 1) {
521 // Keep a reference to the compiled data we rely on.
522 // Only the top-level component instance needs to add a reference - higher-level
523 // components add a reference to the components they depend on, so an instance
524 // of the top-level component keeps them all referenced.
525 ddata->compiledData = states[0].compiledData;
526 ddata->compiledData->addref();
530 if (ddata->context) {
531 Q_ASSERT(ddata->context != CTXT);
532 Q_ASSERT(ddata->outerContext);
533 Q_ASSERT(ddata->outerContext != CTXT);
534 QQmlContextData *c = ddata->context;
535 while (c->linkedContext) c = c->linkedContext;
536 c->linkedContext = CTXT;
541 ddata->ownContext = true;
542 } else if (!ddata->context) {
546 ddata->setImplicitDestructible();
547 ddata->outerContext = CTXT;
548 ddata->lineNumber = instr.line;
549 ddata->columnNumber = instr.column;
550 QML_END_INSTR(CompleteQMLObject)
552 QML_BEGIN_INSTR(CreateCppObject)
553 const QQmlCompiledData::TypeReference &type = TYPES.at(instr.type);
558 type.type->create(&o, &memory, sizeof(QQmlData));
559 QQmlData *ddata = new (memory) QQmlData;
560 ddata->ownMemory = false;
561 QObjectPrivate::get(o)->declarativeData = ddata;
563 if (rootContext && rootContext->isRootObjectInCreation) {
564 ddata->rootObjectInCreation = true;
565 rootContext->isRootObjectInCreation = false;
568 if (type.typePropertyCache && !ddata->propertyCache) {
569 ddata->propertyCache = type.typePropertyCache;
570 ddata->propertyCache->addref();
574 VME_EXCEPTION(tr("Unable to create object of type %1").arg(type.type->elementName()),
577 if (states.count() == 1) {
578 // Keep a reference to the compiled data we rely on
579 ddata->compiledData = states[0].compiledData;
580 ddata->compiledData->addref();
584 if (ddata->context) {
585 Q_ASSERT(ddata->context != CTXT);
586 Q_ASSERT(ddata->outerContext);
587 Q_ASSERT(ddata->outerContext != CTXT);
588 QQmlContextData *c = ddata->context;
589 while (c->linkedContext) c = c->linkedContext;
590 c->linkedContext = CTXT;
595 ddata->ownContext = true;
596 } else if (!ddata->context) {
600 ddata->setImplicitDestructible();
601 ddata->outerContext = CTXT;
602 ddata->lineNumber = instr.line;
603 ddata->columnNumber = instr.column;
605 if (instr.data != -1) {
606 QQmlCustomParser *customParser =
607 TYPES.at(instr.type).type->customParser();
608 customParser->setCustomData(o, DATAS.at(instr.data));
610 if (!objects.isEmpty()) {
611 QObject *parent = objects.at(objects.count() - 1 - (instr.parentToSuper?1:0));
612 #if 0 // ### refactor
613 if (o->isWidgetType() && parent->isWidgetType())
614 static_cast<QWidget*>(o)->setParent(static_cast<QWidget*>(parent));
617 QQml_setParent_noEvent(o, parent);
618 ddata->parentFrozen = true;
621 QML_END_INSTR(CreateCppObject)
623 QML_BEGIN_INSTR(CreateSimpleObject)
624 QObject *o = (QObject *)operator new(instr.typeSize + sizeof(QQmlData));
625 ::memset(o, 0, instr.typeSize + sizeof(QQmlData));
628 QQmlData *ddata = (QQmlData *)(((const char *)o) + instr.typeSize);
629 const QQmlCompiledData::TypeReference &ref = TYPES.at(instr.type);
630 if (!ddata->propertyCache && ref.typePropertyCache) {
631 ddata->propertyCache = ref.typePropertyCache;
632 ddata->propertyCache->addref();
634 ddata->lineNumber = instr.line;
635 ddata->columnNumber = instr.column;
637 QObjectPrivate::get(o)->declarativeData = ddata;
638 ddata->context = ddata->outerContext = CTXT;
639 ddata->nextContextObject = CTXT->contextObjects;
640 if (ddata->nextContextObject)
641 ddata->nextContextObject->prevContextObject = &ddata->nextContextObject;
642 ddata->prevContextObject = &CTXT->contextObjects;
643 CTXT->contextObjects = ddata;
645 QObject *parent = objects.at(objects.count() - 1 - (instr.parentToSuper?1:0));
646 QQml_setParent_noEvent(o, parent);
648 ddata->parentFrozen = true;
650 QML_END_INSTR(CreateSimpleObject)
652 QML_BEGIN_INSTR(SetId)
653 QObject *target = objects.top();
654 CTXT->setIdProperty(instr.index, target);
657 QML_BEGIN_INSTR(SetDefault)
658 CTXT->contextObject = objects.top();
659 QML_END_INSTR(SetDefault)
661 QML_BEGIN_INSTR(CreateComponent)
662 QQmlComponent *qcomp =
663 new QQmlComponent(CTXT->engine, COMP, INSTRUCTIONSTREAM - COMP->bytecode.constData(),
664 objects.isEmpty() ? 0 : objects.top());
666 QQmlData *ddata = QQmlData::get(qcomp, true);
669 CTXT->addObject(qcomp);
671 if (states.count() == 1) {
672 // Keep a reference to the compiled data we rely on
673 ddata->compiledData = states[0].compiledData;
674 ddata->compiledData->addref();
678 ddata->ownContext = true;
680 ddata->setImplicitDestructible();
681 ddata->outerContext = CTXT;
682 ddata->lineNumber = instr.line;
683 ddata->columnNumber = instr.column;
685 QQmlComponentPrivate::get(qcomp)->creationContext = CTXT;
688 INSTRUCTIONSTREAM += instr.count;
689 QML_END_INSTR(CreateComponent)
691 QML_BEGIN_INSTR(StoreMetaObject)
692 QObject *target = objects.top();
694 QQmlPropertyCache *propertyCache = PROPERTYCACHES.at(instr.propertyCache);
696 const QQmlVMEMetaData *data =
697 (const QQmlVMEMetaData *)DATAS.at(instr.aliasData).constData();
699 (void)new QQmlVMEMetaObject(target, propertyCache, data);
701 QQmlData *ddata = QQmlData::get(target, true);
702 if (ddata->propertyCache) ddata->propertyCache->release();
703 ddata->propertyCache = propertyCache;
704 ddata->propertyCache->addref();
706 QML_END_INSTR(StoreMetaObject)
708 QML_BEGIN_INSTR(AssignCustomType)
709 QObject *target = objects.top();
710 CLEAN_PROPERTY(target, instr.propertyIndex);
712 const QString &primitive = PRIMITIVES.at(instr.primitive);
713 int type = instr.type;
714 QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type);
715 QVariant v = (*converter)(primitive);
718 target->metaObject()->property(instr.propertyIndex);
719 if (v.isNull() || ((int)prop.type() != type && prop.userType() != type))
720 VME_EXCEPTION(tr("Cannot assign value %1 to property %2").arg(primitive).arg(QString::fromUtf8(prop.name())), instr.line);
722 void *a[] = { (void *)v.data(), 0, &status, &flags };
723 QMetaObject::metacall(target, QMetaObject::WriteProperty,
724 instr.propertyIndex, a);
725 QML_END_INSTR(AssignCustomType)
727 QML_BEGIN_INSTR(AssignSignalObject)
730 QObject *assign = objects.pop();
731 QObject *target = objects.top();
732 int sigIdx = instr.signal;
733 const QString &pr = PRIMITIVES.at(sigIdx);
735 QQmlProperty prop(target, pr);
736 if (prop.type() & QQmlProperty::SignalProperty) {
738 QMetaMethod method = QQmlMetaType::defaultMethod(assign);
739 if (!method.isValid())
740 VME_EXCEPTION(tr("Cannot assign object type %1 with no default method").arg(QString::fromLatin1(assign->metaObject()->className())), instr.line);
742 if (!QMetaObject::checkConnectArgs(prop.method(), method)) {
743 VME_EXCEPTION(tr("Cannot connect mismatched signal/slot %1 %vs. %2")
744 .arg(QString::fromLatin1(method.methodSignature().constData()))
745 .arg(QString::fromLatin1(prop.method().methodSignature().constData())), instr.line);
748 QQmlPropertyPrivate::connect(target, prop.index(), assign, method.methodIndex());
751 VME_EXCEPTION(tr("Cannot assign an object to signal property %1").arg(pr), instr.line);
755 QML_END_INSTR(AssignSignalObject)
757 QML_BEGIN_INSTR(StoreSignal)
758 QObject *target = objects.top();
759 QObject *context = objects.at(objects.count() - 1 - instr.context);
761 QQmlBoundSignal *bs = new QQmlBoundSignal(target, instr.signalIndex, target, engine);
762 QQmlBoundSignalExpression *expr =
763 new QQmlBoundSignalExpression(target, instr.signalIndex,
764 CTXT, context, DATAS.at(instr.value),
765 true, COMP->name, instr.line, instr.column);
766 expr->setParameterCountForJS(instr.parameterCount);
767 bs->takeExpression(expr);
768 QML_END_INSTR(StoreSignal)
770 QML_BEGIN_INSTR(StoreImportedScript)
771 CTXT->importedScripts << run(CTXT, SCRIPTS.at(instr.value));
772 QML_END_INSTR(StoreImportedScript)
774 QML_BEGIN_INSTR(StoreScriptString)
775 QObject *target = objects.top();
776 QObject *scope = objects.at(objects.count() - 1 - instr.scope);
777 QQmlScriptString ss(PRIMITIVES.at(instr.value), CTXT->asQQmlContext(), scope);
778 ss.d.data()->bindingId = instr.bindingId;
779 ss.d.data()->lineNumber = qmlSourceCoordinate(instr.line);
780 ss.d.data()->columnNumber = qmlSourceCoordinate(instr.column);
781 ss.d.data()->isStringLiteral = instr.isStringLiteral;
782 ss.d.data()->isNumberLiteral = instr.isNumberLiteral;
783 ss.d.data()->numberValue = instr.numberValue;
785 void *a[] = { &ss, 0, &status, &flags };
786 QMetaObject::metacall(target, QMetaObject::WriteProperty,
787 instr.propertyIndex, a);
788 QML_END_INSTR(StoreScriptString)
790 QML_BEGIN_INSTR(BeginObject)
791 QObject *target = objects.top();
792 QQmlParserStatus *status = reinterpret_cast<QQmlParserStatus *>(reinterpret_cast<char *>(target) + instr.castValue);
793 parserStatus.push(status);
794 #ifdef QML_ENABLE_TRACE
795 Q_ASSERT(QObjectPrivate::get(target)->declarativeData);
796 parserStatusData.push(static_cast<QQmlData *>(QObjectPrivate::get(target)->declarativeData));
798 status->d = &parserStatus.top();
800 status->classBegin();
801 QML_END_INSTR(BeginObject)
803 QML_BEGIN_INSTR(InitV8Bindings)
804 CTXT->v8bindings = new QV8Bindings(&PROGRAMS[instr.programIndex], instr.line, CTXT);
805 QML_END_INSTR(InitV8Bindings)
807 QML_BEGIN_INSTR(StoreBinding)
809 objects.at(objects.count() - 1 - instr.owner);
811 objects.at(objects.count() - 1 - instr.context);
813 if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex))
814 QML_NEXT_INSTR(StoreBinding);
816 QQmlBinding *bind = new QQmlBinding(PRIMITIVES.at(instr.value), true,
817 context, CTXT, COMP->name, instr.line,
819 bindValues.push(bind);
820 bind->m_mePtr = &bindValues.top();
821 bind->setTarget(target, instr.property, CTXT);
824 QQmlAbstractBinding *old =
825 QQmlPropertyPrivate::setBindingNoEnable(target,
826 instr.property.coreIndex,
827 instr.property.getValueTypeCoreIndex(),
829 if (old) { old->destroy(); }
831 typedef QQmlPropertyPrivate QDPP;
832 Q_ASSERT(bind->propertyIndex() == QDPP::bindingIndex(instr.property));
833 Q_ASSERT(bind->object() == target);
835 CLEAN_PROPERTY(target, QDPP::bindingIndex(instr.property));
839 QML_END_INSTR(StoreBinding)
841 QML_BEGIN_INSTR(StoreV4Binding)
843 objects.at(objects.count() - 1 - instr.owner);
845 objects.at(objects.count() - 1 - instr.context);
847 int propertyIdx = (instr.property & 0x0000FFFF);
849 if (instr.isRoot && BINDINGSKIPLIST.testBit(propertyIdx))
850 QML_NEXT_INSTR(StoreV4Binding);
852 QQmlAbstractBinding *binding = CTXT->v4bindings->configBinding(target, scope, &instr);
853 bindValues.push(binding);
854 binding->m_mePtr = &bindValues.top();
857 QQmlAbstractBinding *old =
858 QQmlPropertyPrivate::setBindingNoEnable(target,
860 instr.propType ? (instr.property >> 16) : -1,
862 if (old) { old->destroy(); }
864 Q_ASSERT(binding->propertyIndex() == instr.property);
865 Q_ASSERT(binding->object() == target);
867 CLEAN_PROPERTY(target, instr.property);
869 binding->addToObject();
871 QML_END_INSTR(StoreV4Binding)
873 QML_BEGIN_INSTR(StoreV8Binding)
875 objects.at(objects.count() - 1 - instr.owner);
877 objects.at(objects.count() - 1 - instr.context);
879 if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex))
880 QML_NEXT_INSTR(StoreV8Binding);
882 QQmlAbstractBinding *binding = CTXT->v8bindings->configBinding(target, scope,
884 if (binding && !instr.isFallback) {
885 bindValues.push(binding);
886 binding->m_mePtr = &bindValues.top();
889 QQmlAbstractBinding *old =
890 QQmlPropertyPrivate::setBindingNoEnable(target,
891 instr.property.coreIndex,
892 instr.property.getValueTypeCoreIndex(),
894 if (old) { old->destroy(); }
896 typedef QQmlPropertyPrivate QDPP;
897 Q_ASSERT(binding->propertyIndex() == QDPP::bindingIndex(instr.property));
898 Q_ASSERT(binding->object() == target);
900 CLEAN_PROPERTY(target, QDPP::bindingIndex(instr.property));
902 binding->addToObject();
905 QML_END_INSTR(StoreV8Binding)
907 QML_BEGIN_INSTR(StoreValueSource)
908 QObject *obj = objects.pop();
909 QQmlPropertyValueSource *vs = reinterpret_cast<QQmlPropertyValueSource *>(reinterpret_cast<char *>(obj) + instr.castValue);
910 QObject *target = obj->parent();
911 vs->setTarget(QQmlPropertyPrivate::restore(target, instr.property, CTXT));
912 QML_END_INSTR(StoreValueSource)
914 QML_BEGIN_INSTR(StoreValueInterceptor)
915 QObject *obj = objects.pop();
916 QQmlPropertyValueInterceptor *vi = reinterpret_cast<QQmlPropertyValueInterceptor *>(reinterpret_cast<char *>(obj) + instr.castValue);
917 QObject *target = obj->parent();
919 QQmlPropertyPrivate::restore(target, instr.property, CTXT);
921 QQmlVMEMetaObject *mo = QQmlVMEMetaObject::get(target);
923 mo->registerInterceptor(prop.index(), QQmlPropertyPrivate::valueTypeCoreIndex(prop), vi);
924 QML_END_INSTR(StoreValueInterceptor)
926 QML_BEGIN_INSTR(StoreObjectQList)
927 QObject *assign = objects.pop();
929 const List &list = lists.top();
930 list.qListProperty.append((QQmlListProperty<void>*)&list.qListProperty, assign);
931 QML_END_INSTR(StoreObjectQList)
933 QML_BEGIN_INSTR(AssignObjectList)
934 // This is only used for assigning interfaces
935 QObject *assign = objects.pop();
936 const List &list = lists.top();
938 int type = list.type;
942 const char *iid = QQmlMetaType::interfaceIId(type);
944 ptr = assign->qt_metacast(iid);
946 VME_EXCEPTION(tr("Cannot assign object to list"), instr.line);
949 list.qListProperty.append((QQmlListProperty<void>*)&list.qListProperty, ptr);
950 QML_END_INSTR(AssignObjectList)
952 QML_BEGIN_INSTR(StoreInterface)
953 QObject *assign = objects.pop();
954 QObject *target = objects.top();
955 CLEAN_PROPERTY(target, instr.propertyIndex);
957 int coreIdx = instr.propertyIndex;
958 QMetaProperty prop = target->metaObject()->property(coreIdx);
959 int t = prop.userType();
960 const char *iid = QQmlMetaType::interfaceIId(t);
963 void *ptr = assign->qt_metacast(iid);
965 void *a[] = { &ptr, 0, &status, &flags };
966 QMetaObject::metacall(target,
967 QMetaObject::WriteProperty,
974 VME_EXCEPTION(tr("Cannot assign object to interface property"), instr.line);
975 QML_END_INSTR(StoreInterface)
977 QML_BEGIN_INSTR(FetchAttached)
978 QObject *target = objects.top();
980 QObject *qmlObject = qmlAttachedPropertiesObjectById(instr.id, target);
983 VME_EXCEPTION(tr("Unable to create attached object"), instr.line);
985 objects.push(qmlObject);
986 QML_END_INSTR(FetchAttached)
988 QML_BEGIN_INSTR(FetchQList)
989 QObject *target = objects.top();
991 lists.push(List(instr.type));
994 a[0] = (void *)&(lists.top().qListProperty);
995 QMetaObject::metacall(target, QMetaObject::ReadProperty,
997 QML_END_INSTR(FetchQList)
999 QML_BEGIN_INSTR(FetchObject)
1000 QObject *target = objects.top();
1003 // NOTE: This assumes a cast to QObject does not alter the
1007 QMetaObject::metacall(target, QMetaObject::ReadProperty,
1011 VME_EXCEPTION(tr("Cannot set properties on %1 as it is null").arg(QString::fromUtf8(target->metaObject()->property(instr.property).name())), instr.line);
1014 QML_END_INSTR(FetchObject)
1016 QML_BEGIN_INSTR(PopQList)
1018 QML_END_INSTR(PopQList)
1020 QML_BEGIN_INSTR(Defer)
1021 if (instr.deferCount) {
1022 QObject *target = objects.top();
1023 QQmlData *data = QQmlData::get(target, true);
1024 data->compiledData = COMP;
1025 data->compiledData->addref(); // Keep this data referenced until we're initialized
1026 data->deferredIdx = INSTRUCTIONSTREAM - COMP->bytecode.constData();
1027 Q_ASSERT(data->deferredIdx != 0);
1028 INSTRUCTIONSTREAM += instr.deferCount;
1030 QML_END_INSTR(Defer)
1032 QML_BEGIN_INSTR(PopFetchedObject)
1034 QML_END_INSTR(PopFetchedObject)
1036 QML_BEGIN_INSTR(FetchValueType)
1037 QObject *target = objects.top();
1039 if (instr.bindingSkipList != 0) {
1040 // Possibly need to clear bindings
1041 QQmlData *targetData = QQmlData::get(target);
1043 QQmlAbstractBinding *binding =
1044 QQmlPropertyPrivate::binding(target, instr.property, -1);
1046 if (binding && binding->bindingType() != QQmlAbstractBinding::ValueTypeProxy) {
1047 QQmlPropertyPrivate::setBinding(target, instr.property, -1, 0);
1049 } else if (binding) {
1050 QQmlValueTypeProxyBinding *proxy =
1051 static_cast<QQmlValueTypeProxyBinding *>(binding);
1052 proxy->removeBindings(instr.bindingSkipList);
1057 QQmlValueType *valueHandler = QQmlValueTypeFactory::valueType(instr.type);
1058 Q_ASSERT(valueHandler);
1059 valueHandler->read(target, instr.property);
1060 objects.push(valueHandler);
1061 QML_END_INSTR(FetchValueType)
1063 QML_BEGIN_INSTR(PopValueType)
1064 QQmlValueType *valueHandler =
1065 static_cast<QQmlValueType *>(objects.pop());
1066 QObject *target = objects.top();
1067 valueHandler->write(target, instr.property, QQmlPropertyPrivate::BypassInterceptor);
1068 QML_END_INSTR(PopValueType)
1070 #ifdef QML_THREADED_VME_INTERPRETER
1074 qFatal("QQmlCompiledData: Internal error - unknown instruction %d", genericInstr->common.instructionType);
1081 Q_ASSERT(!states.isEmpty());
1082 Q_ASSERT(!errors->isEmpty());
1089 Q_ASSERT(objects.count() == 1);
1091 QObject *rv = objects.top();
1093 objects.deallocate();
1100 void QQmlVME::reset()
1102 Q_ASSERT(!states.isEmpty() || objects.isEmpty());
1104 QRecursionWatcher<QQmlVME, &QQmlVME::recursion> watcher(this);
1106 if (!objects.isEmpty() && !(states.at(0).flags & State::Deferred))
1107 delete objects.at(0);
1109 if (!rootContext.isNull())
1110 rootContext->activeVMEData = 0;
1112 // Remove the QQmlParserStatus and QQmlAbstractBinding back pointers
1113 blank(parserStatus);
1116 while (componentAttached) {
1117 QQmlComponentAttached *a = componentAttached;
1122 objects.deallocate();
1124 bindValues.deallocate();
1125 parserStatus.deallocate();
1126 #ifdef QML_ENABLE_TRACE
1127 parserStatusData.deallocate();
1129 finalizeCallbacks.clear();
1132 creationContext = 0;
1135 // Must be called with a handle scope and context
1136 void QQmlScriptData::initialize(QQmlEngine *engine)
1138 Q_ASSERT(m_program.IsEmpty());
1140 Q_ASSERT(!hasEngine());
1142 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
1143 QV8Engine *v8engine = ep->v8engine();
1145 // If compilation throws an error, a surrounding v8::TryCatch will record it.
1146 v8::Local<v8::Script> program = v8engine->qmlModeCompile(m_programSource.constData(),
1147 m_programSource.length(), urlString, 1);
1148 if (program.IsEmpty())
1151 m_program = qPersistentNew<v8::Script>(program);
1152 m_programSource.clear(); // We don't need this anymore
1154 addToEngine(engine);
1159 v8::Persistent<v8::Object> QQmlVME::run(QQmlContextData *parentCtxt, QQmlScriptData *script)
1161 if (script->m_loaded)
1162 return qPersistentNew<v8::Object>(script->m_value);
1164 v8::Persistent<v8::Object> rv;
1166 Q_ASSERT(parentCtxt && parentCtxt->engine);
1167 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(parentCtxt->engine);
1168 QV8Engine *v8engine = ep->v8engine();
1170 if (script->hasError()) {
1171 ep->warning(script->error());
1175 bool shared = script->pragmas & QQmlScript::Object::ScriptBlock::Shared;
1177 QQmlContextData *effectiveCtxt = parentCtxt;
1181 // Create the script context if required
1182 QQmlContextData *ctxt = new QQmlContextData;
1183 ctxt->isInternal = true;
1184 ctxt->isJSContext = true;
1186 ctxt->isPragmaLibraryContext = true;
1188 ctxt->isPragmaLibraryContext = parentCtxt->isPragmaLibraryContext;
1189 ctxt->url = script->url;
1190 ctxt->urlString = script->urlString;
1192 // For backward compatibility, if there are no imports, we need to use the
1193 // imports from the parent context. See QTBUG-17518.
1194 if (!script->importCache->isEmpty()) {
1195 ctxt->imports = script->importCache;
1196 } else if (effectiveCtxt) {
1197 ctxt->imports = effectiveCtxt->imports;
1198 ctxt->importedScripts = effectiveCtxt->importedScripts;
1199 for (int ii = 0; ii < ctxt->importedScripts.count(); ++ii)
1200 ctxt->importedScripts[ii] = qPersistentNew<v8::Object>(ctxt->importedScripts[ii]);
1203 if (ctxt->imports) {
1204 ctxt->imports->addref();
1207 if (effectiveCtxt) {
1208 ctxt->setParent(effectiveCtxt, true);
1210 ctxt->engine = parentCtxt->engine; // Fix for QTBUG-21620
1213 for (int ii = 0; ii < script->scripts.count(); ++ii) {
1214 ctxt->importedScripts << run(ctxt, script->scripts.at(ii)->scriptData());
1217 v8::HandleScope handle_scope;
1218 v8::Context::Scope scope(v8engine->context());
1220 v8::TryCatch try_catch;
1221 if (!script->isInitialized())
1222 script->initialize(parentCtxt->engine);
1224 v8::Local<v8::Object> qmlglobal = v8engine->qmlScope(ctxt, 0);
1226 if (!script->m_program.IsEmpty()) {
1227 script->m_program->Run(qmlglobal);
1229 // Compilation failed.
1230 Q_ASSERT(try_catch.HasCaught());
1233 if (try_catch.HasCaught()) {
1234 v8::Local<v8::Message> message = try_catch.Message();
1235 if (!message.IsEmpty()) {
1237 QQmlExpressionPrivate::exceptionToError(message, error);
1242 rv = qPersistentNew<v8::Object>(qmlglobal);
1244 script->m_value = qPersistentNew<v8::Object>(qmlglobal);
1245 script->m_loaded = true;
1251 #ifdef QML_THREADED_VME_INTERPRETER
1252 void **QQmlVME::instructionJumpTable()
1254 static void **jumpTable = 0;
1257 QQmlVME::Interrupt i;
1258 dummy.run(0, i, &jumpTable);
1264 QQmlContextData *QQmlVME::complete(const Interrupt &interrupt)
1267 (bindValues.isEmpty() &&
1268 parserStatus.isEmpty() &&
1269 componentAttached == 0 &&
1270 rootContext.isNull() &&
1271 finalizeCallbacks.isEmpty()));
1276 QQmlTrace trace("VME Complete");
1277 #ifdef QML_ENABLE_TRACE
1278 trace.addDetail("URL", rootComponent->url);
1281 ActiveVMERestorer restore(this, QQmlEnginePrivate::get(engine));
1282 QRecursionWatcher<QQmlVME, &QQmlVME::recursion> watcher(this);
1285 QQmlTrace trace("VME Binding Enable");
1286 trace.event("begin binding eval");
1287 while (!bindValues.isEmpty()) {
1288 QQmlAbstractBinding *b = bindValues.pop();
1292 b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
1293 QQmlPropertyPrivate::DontRemoveBinding);
1296 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1299 bindValues.deallocate();
1303 QQmlTrace trace("VME Component Complete");
1304 while (!parserStatus.isEmpty()) {
1305 QQmlParserStatus *status = parserStatus.pop();
1306 #ifdef QML_ENABLE_TRACE
1307 QQmlData *data = parserStatusData.pop();
1310 if (status && status->d) {
1312 #ifdef QML_ENABLE_TRACE
1313 QQmlTrace trace("Component complete");
1314 trace.addDetail("URL", data->outerContext->url);
1315 trace.addDetail("Line", data->lineNumber);
1317 status->componentComplete();
1320 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1323 parserStatus.deallocate();
1327 QQmlTrace trace("VME Finalize Callbacks");
1328 for (int ii = 0; ii < finalizeCallbacks.count(); ++ii) {
1329 QQmlEnginePrivate::FinalizeCallback callback = finalizeCallbacks.at(ii);
1330 QObject *obj = callback.first;
1332 void *args[] = { 0 };
1333 QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args);
1335 if (watcher.hasRecursed())
1338 finalizeCallbacks.clear();
1342 QQmlTrace trace("VME Component.onCompleted Callbacks");
1343 while (componentAttached) {
1344 QQmlComponentAttached *a = componentAttached;
1346 QQmlData *d = QQmlData::get(a->parent());
1348 Q_ASSERT(d->context);
1349 a->add(&d->context->componentAttached);
1350 emit a->completed();
1352 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1357 QQmlContextData *rv = rootContext;
1361 if (rv) rv->activeVMEData = data;
1366 void QQmlVME::blank(QFiniteStack<QQmlAbstractBinding *> &bs)
1368 for (int ii = 0; ii < bs.count(); ++ii) {
1369 QQmlAbstractBinding *b = bs.at(ii);
1370 if (b) b->m_mePtr = 0;
1374 void QQmlVME::blank(QFiniteStack<QQmlParserStatus *> &pss)
1376 for (int ii = 0; ii < pss.count(); ++ii) {
1377 QQmlParserStatus *ps = pss.at(ii);
1382 QQmlVMEGuard::QQmlVMEGuard()
1383 : m_objectCount(0), m_objects(0), m_contextCount(0), m_contexts(0)
1387 QQmlVMEGuard::~QQmlVMEGuard()
1392 void QQmlVMEGuard::guard(QQmlVME *vme)
1396 m_objectCount = vme->objects.count();
1397 m_objects = new QQmlGuard<QObject>[m_objectCount];
1398 for (int ii = 0; ii < m_objectCount; ++ii)
1399 m_objects[ii] = vme->objects[ii];
1401 m_contextCount = (vme->rootContext.isNull()?0:1) + vme->states.count();
1402 m_contexts = new QQmlGuardedContextData[m_contextCount];
1403 for (int ii = 0; ii < vme->states.count(); ++ii)
1404 m_contexts[ii] = vme->states.at(ii).context;
1405 if (!vme->rootContext.isNull())
1406 m_contexts[m_contextCount - 1] = vme->rootContext.contextData();
1409 void QQmlVMEGuard::clear()
1411 delete [] m_objects;
1412 delete [] m_contexts;
1420 bool QQmlVMEGuard::isOK() const
1422 for (int ii = 0; ii < m_objectCount; ++ii)
1423 if (m_objects[ii].isNull())
1426 for (int ii = 0; ii < m_contextCount; ++ii)
1427 if (m_contexts[ii].isNull())