1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdeclarativevme_p.h"
44 #include "qdeclarativecompiler_p.h"
45 #include "qdeclarativeboundsignal_p.h"
46 #include "qdeclarativestringconverters_p.h"
47 #include <private/qmetaobjectbuilder_p.h>
48 #include <private/qfastmetabuilder_p.h>
49 #include "qdeclarativedata_p.h"
50 #include "qdeclarative.h"
51 #include "qdeclarativecustomparser_p.h"
52 #include "qdeclarativeengine.h"
53 #include "qdeclarativecontext.h"
54 #include "qdeclarativecomponent.h"
55 #include "qdeclarativecomponentattached_p.h"
56 #include "qdeclarativebinding_p.h"
57 #include "qdeclarativeengine_p.h"
58 #include "qdeclarativecomponent_p.h"
59 #include "qdeclarativevmemetaobject_p.h"
60 #include "qdeclarativebinding_p_p.h"
61 #include "qdeclarativecontext_p.h"
62 #include <private/qv4bindings_p.h>
63 #include <private/qv8bindings_p.h>
64 #include "qdeclarativeglobal_p.h"
65 #include <private/qfinitestack_p.h>
66 #include "qdeclarativescriptstring.h"
67 #include "qdeclarativescriptstring_p.h"
68 #include "qdeclarativepropertyvalueinterceptor_p.h"
75 #include <QtCore/qdebug.h>
76 #include <QtCore/qvarlengtharray.h>
77 #include <QtCore/qcoreapplication.h>
78 #include <QtCore/qdatetime.h>
79 #include <QtCore/qvarlengtharray.h>
80 #include <QtDeclarative/qjsvalue.h>
84 using namespace QDeclarativeVMETypes;
86 #define VME_EXCEPTION(desc, line) \
88 QDeclarativeError error; \
89 error.setDescription(desc.trimmed()); \
90 error.setLine(line); \
91 error.setUrl(COMP->url); \
96 void QDeclarativeVME::init(QDeclarativeContextData *ctxt, QDeclarativeCompiledData *comp, int start,
97 QDeclarativeContextData *creation)
105 creationContext = creation;
109 initState.context = ctxt;
110 initState.compiledData = comp;
111 initState.instructionStream = comp->bytecode.constData() + start;
112 states.push(initState);
114 typedef QDeclarativeInstruction I;
115 I *i = (I *)initState.instructionStream;
117 Q_ASSERT(comp->instructionType(i) == I::Init);
119 objects.allocate(i->init.objectStackSize);
120 lists.allocate(i->init.listStackSize);
121 bindValues.allocate(i->init.bindingsSize);
122 parserStatus.allocate(i->init.parserStatusSize);
124 #ifdef QML_ENABLE_TRACE
125 parserStatusData.allocate(i->init.parserStatusSize);
126 rootComponent = comp;
130 engine = ctxt->engine;
133 bool QDeclarativeVME::initDeferred(QObject *object)
135 QDeclarativeData *data = QDeclarativeData::get(object);
137 if (!data || !data->context || !data->deferredComponent)
140 QDeclarativeContextData *ctxt = data->context;
141 QDeclarativeCompiledData *comp = data->deferredComponent;
142 int start = data->deferredIdx;
145 initState.flags = State::Deferred;
146 initState.context = ctxt;
147 initState.compiledData = comp;
148 initState.instructionStream = comp->bytecode.constData() + start;
149 states.push(initState);
151 typedef QDeclarativeInstruction I;
152 I *i = (I *)initState.instructionStream;
154 Q_ASSERT(comp->instructionType(i) == I::DeferInit);
156 objects.allocate(i->deferInit.objectStackSize);
157 lists.allocate(i->deferInit.listStackSize);
158 bindValues.allocate(i->deferInit.bindingsSize);
159 parserStatus.allocate(i->deferInit.parserStatusSize);
161 objects.push(object);
163 #ifdef QML_ENABLE_TRACE
164 parserStatusData.allocate(i->deferInit.parserStatusSize);
165 rootComponent = comp;
169 engine = ctxt->engine;
175 struct ActiveVMERestorer
177 ActiveVMERestorer(QDeclarativeVME *me, QDeclarativeEnginePrivate *ep)
178 : ep(ep), oldVME(ep->activeVME) { ep->activeVME = me; }
179 ~ActiveVMERestorer() { ep->activeVME = oldVME; }
181 QDeclarativeEnginePrivate *ep;
182 QDeclarativeVME *oldVME;
186 QObject *QDeclarativeVME::execute(QList<QDeclarativeError> *errors, const Interrupt &interrupt)
188 Q_ASSERT(states.count() >= 1);
190 #ifdef QML_ENABLE_TRACE
191 QDeclarativeTrace trace("VME Execute");
192 trace.addDetail("URL", rootComponent->url);
195 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(states.at(0).context->engine);
197 ActiveVMERestorer restore(this, ep);
199 QObject *rv = run(errors, interrupt);
204 inline bool fastHasBinding(QObject *o, int index)
206 QDeclarativeData *ddata = static_cast<QDeclarativeData *>(QObjectPrivate::get(o)->declarativeData);
208 return ddata && (ddata->bindingBitsSize > index) &&
209 (ddata->bindingBits[index / 32] & (1 << (index % 32)));
212 static void removeBindingOnProperty(QObject *o, int index)
214 QDeclarativeAbstractBinding *binding = QDeclarativePropertyPrivate::setBinding(o, index, -1, 0);
215 if (binding) binding->destroy();
218 static QVariant variantFromString(const QString &string)
220 return QDeclarativeStringConverters::variantFromString(string);
223 // XXX we probably need some form of "work count" here to prevent us checking this
224 // for every instruction.
225 #define QML_BEGIN_INSTR_COMMON(I) { \
226 const QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::DataType &instr = QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::data(*genericInstr); \
227 INSTRUCTIONSTREAM += QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::Size; \
230 #ifdef QML_THREADED_VME_INTERPRETER
231 # define QML_BEGIN_INSTR(I) op_##I: \
232 QML_BEGIN_INSTR_COMMON(I)
234 # define QML_NEXT_INSTR(I) { \
235 if (watcher.hasRecursed()) return 0; \
236 genericInstr = reinterpret_cast<const QDeclarativeInstruction *>(INSTRUCTIONSTREAM); \
237 goto *genericInstr->common.code; \
240 # define QML_END_INSTR(I) } \
241 if (watcher.hasRecursed()) return 0; \
242 genericInstr = reinterpret_cast<const QDeclarativeInstruction *>(INSTRUCTIONSTREAM); \
243 if (interrupt.shouldInterrupt()) return 0; \
244 goto *genericInstr->common.code;
247 # define QML_BEGIN_INSTR(I) \
248 case QDeclarativeInstruction::I: \
249 QML_BEGIN_INSTR_COMMON(I)
251 # define QML_NEXT_INSTR(I) { \
252 if (watcher.hasRecursed()) return 0; \
256 # define QML_END_INSTR(I) \
257 if (watcher.hasRecursed() || interrupt.shouldInterrupt()) return 0; \
261 #define QML_STORE_VALUE(name, cpptype, value) \
262 QML_BEGIN_INSTR(name) \
264 void *a[] = { (void *)&v, 0, &status, &flags }; \
265 QObject *target = objects.top(); \
266 CLEAN_PROPERTY(target, instr.propertyIndex); \
267 QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.propertyIndex, a); \
270 #define QML_STORE_LIST(name, cpptype, value) \
271 QML_BEGIN_INSTR(name) \
274 void *a[] = { (void *)&v, 0, &status, &flags }; \
275 QObject *target = objects.top(); \
276 CLEAN_PROPERTY(target, instr.propertyIndex); \
277 QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.propertyIndex, a); \
280 #define QML_STORE_VAR(name, value) \
281 QML_BEGIN_INSTR(name) \
282 v8::Handle<v8::Value> v8value = value; \
283 QObject *target = objects.top(); \
284 CLEAN_PROPERTY(target, instr.propertyIndex); \
285 QMetaObject *mo = const_cast<QMetaObject *>(target->metaObject()); \
286 QDeclarativeVMEMetaObject *vmemo = static_cast<QDeclarativeVMEMetaObject *>(mo); \
287 vmemo->setVMEProperty(instr.propertyIndex, v8value); \
290 #define QML_STORE_POINTER(name, value) \
291 QML_BEGIN_INSTR(name) \
292 void *a[] = { (void *)value, 0, &status, &flags }; \
293 QObject *target = objects.top(); \
294 CLEAN_PROPERTY(target, instr.propertyIndex); \
295 QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.propertyIndex, a); \
298 #define CLEAN_PROPERTY(o, index) \
299 if (fastHasBinding(o, index)) \
300 removeBindingOnProperty(o, index)
302 QObject *QDeclarativeVME::run(QList<QDeclarativeError> *errors,
303 const Interrupt &interrupt
304 #ifdef QML_THREADED_VME_INTERPRETER
305 , void ***storeJumpTable
309 #ifdef QML_THREADED_VME_INTERPRETER
310 if (storeJumpTable) {
311 #define QML_INSTR_ADDR(I, FMT) &&op_##I,
312 static void *jumpTable[] = {
313 FOR_EACH_QML_INSTR(QML_INSTR_ADDR)
315 #undef QML_INSTR_ADDR
316 *storeJumpTable = jumpTable;
320 Q_ASSERT(errors->isEmpty());
321 Q_ASSERT(states.count() >= 1);
323 QDeclarativeEngine *engine = states.at(0).context->engine;
324 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
326 // Need a v8 handle scope and execution context for StoreVar instructions.
327 v8::HandleScope handleScope;
328 v8::Context::Scope contextScope(ep->v8engine()->context());
330 int status = -1; // needed for dbus
331 QDeclarativePropertyPrivate::WriteFlags flags = QDeclarativePropertyPrivate::BypassInterceptor |
332 QDeclarativePropertyPrivate::RemoveBindingOnAliasWrite;
334 QRecursionWatcher<QDeclarativeVME, &QDeclarativeVME::recursion> watcher(this);
336 #define COMP states.top().compiledData
337 #define CTXT states.top().context
338 #define INSTRUCTIONSTREAM states.top().instructionStream
339 #define BINDINGSKIPLIST states.top().bindingSkipList
341 #define TYPES COMP->types
342 #define PRIMITIVES COMP->primitives
343 #define DATAS COMP->datas
344 #define PROPERTYCACHES COMP->propertyCaches
345 #define SCRIPTS COMP->scripts
346 #define URLS COMP->urls
348 #ifdef QML_THREADED_VME_INTERPRETER
349 const QDeclarativeInstruction *genericInstr = reinterpret_cast<const QDeclarativeInstruction *>(INSTRUCTIONSTREAM);
350 goto *genericInstr->common.code;
353 const QDeclarativeInstruction *genericInstr = reinterpret_cast<const QDeclarativeInstruction *>(INSTRUCTIONSTREAM);
355 switch (genericInstr->common.instructionType) {
358 // Store a created object in a property. These all pop from the objects stack.
359 QML_STORE_VALUE(StoreObject, QObject *, objects.pop());
360 QML_STORE_VALUE(StoreVariantObject, QVariant, QVariant::fromValue(objects.pop()));
361 QML_STORE_VAR(StoreVarObject, ep->v8engine()->newQObject(objects.pop()));
363 // Store a literal value in a corresponding property
364 QML_STORE_VALUE(StoreFloat, float, instr.value);
365 QML_STORE_VALUE(StoreDouble, double, instr.value);
366 QML_STORE_VALUE(StoreBool, bool, instr.value);
367 QML_STORE_VALUE(StoreInteger, int, instr.value);
368 QML_STORE_VALUE(StoreColor, QColor, QColor::fromRgba(instr.value));
369 QML_STORE_VALUE(StoreDate, QDate, QDate::fromJulianDay(instr.value));
370 QML_STORE_VALUE(StoreDateTime, QDateTime,
371 QDateTime(QDate::fromJulianDay(instr.date), *(QTime *)&instr.time));
372 QML_STORE_POINTER(StoreTime, (QTime *)&instr.time);
373 QML_STORE_POINTER(StorePoint, (QPoint *)&instr.point);
374 QML_STORE_POINTER(StorePointF, (QPointF *)&instr.point);
375 QML_STORE_POINTER(StoreSize, (QSize *)&instr.size);
376 QML_STORE_POINTER(StoreSizeF, (QSizeF *)&instr.size);
377 QML_STORE_POINTER(StoreRect, (QRect *)&instr.rect);
378 QML_STORE_POINTER(StoreRectF, (QRectF *)&instr.rect);
379 QML_STORE_POINTER(StoreVector3D, (QVector3D *)&instr.vector);
380 QML_STORE_POINTER(StoreVector4D, (QVector4D *)&instr.vector);
381 QML_STORE_POINTER(StoreString, &PRIMITIVES.at(instr.value));
382 QML_STORE_POINTER(StoreByteArray, &DATAS.at(instr.value));
383 QML_STORE_POINTER(StoreUrl, &URLS.at(instr.value));
385 // Store a literal value in a QList
386 QML_STORE_LIST(StoreStringList, QStringList, PRIMITIVES.at(instr.value));
387 QML_STORE_LIST(StoreStringQList, QList<QString>, PRIMITIVES.at(instr.value));
388 QML_STORE_LIST(StoreUrlQList, QList<QUrl>, URLS.at(instr.value));
389 QML_STORE_LIST(StoreDoubleQList, QList<double>, instr.value);
390 QML_STORE_LIST(StoreBoolQList, QList<bool>, instr.value);
391 QML_STORE_LIST(StoreIntegerQList, QList<int>, instr.value);
393 // Store a literal value in a QVariant property
394 QML_STORE_VALUE(StoreVariant, QVariant, variantFromString(PRIMITIVES.at(instr.value)));
395 QML_STORE_VALUE(StoreVariantInteger, QVariant, QVariant(instr.value));
396 QML_STORE_VALUE(StoreVariantDouble, QVariant, QVariant(instr.value));
397 QML_STORE_VALUE(StoreVariantBool, QVariant, QVariant(instr.value));
399 // Store a literal value in a var property.
400 // We deliberately do not use string converters here
401 QML_STORE_VAR(StoreVar, ep->v8engine()->fromVariant(PRIMITIVES.at(instr.value)));
402 QML_STORE_VAR(StoreVarInteger, v8::Integer::New(instr.value));
403 QML_STORE_VAR(StoreVarDouble, v8::Number::New(instr.value));
404 QML_STORE_VAR(StoreVarBool, v8::Boolean::New(instr.value));
406 QML_BEGIN_INSTR(Init)
407 // Ensure that the compiled data has been initialized
408 if (!COMP->isInitialized()) COMP->initialize(engine);
410 QDeclarativeContextData *parentCtxt = CTXT;
411 CTXT = new QDeclarativeContextData;
412 CTXT->isInternal = true;
413 CTXT->url = COMP->url;
414 CTXT->imports = COMP->importCache;
415 CTXT->imports->addref();
416 CTXT->setParent(parentCtxt);
417 if (instr.contextCache != -1)
418 CTXT->setIdPropertyData(COMP->contextCaches.at(instr.contextCache));
419 if (instr.compiledBinding != -1) {
420 const char *v4data = DATAS.at(instr.compiledBinding).constData();
421 CTXT->v4bindings = new QV4Bindings(v4data, CTXT, COMP);
423 if (states.count() == 1) {
425 rootContext->activeVMEData = data;
427 if (states.count() == 1 && !creationContext.isNull()) {
428 // A component that is logically created within another component instance shares the
429 // same instances of script imports. For example:
431 // import QtQuick 1.0
432 // import "test.js" as Test
434 // model: Test.getModel()
435 // delegate: Component {
436 // Text { text: Test.getValue(index); }
440 // Has the same "Test" instance. To implement this, we simply copy the v8 handles into
441 // the inner context. We have to create a fresh persistent handle for each to prevent
442 // double dispose. It is possible we could do this more efficiently using some form of
443 // referencing instead.
444 CTXT->importedScripts = creationContext->importedScripts;
445 for (int ii = 0; ii < CTXT->importedScripts.count(); ++ii)
446 CTXT->importedScripts[ii] = qPersistentNew<v8::Object>(CTXT->importedScripts[ii]);
450 QML_BEGIN_INSTR(DeferInit)
451 QML_END_INSTR(DeferInit)
453 QML_BEGIN_INSTR(Done)
456 if (states.isEmpty())
460 QML_BEGIN_INSTR(CreateQMLObject)
461 const QDeclarativeCompiledData::TypeReference &type = TYPES.at(instr.type);
462 Q_ASSERT(type.component);
464 states.push(State());
466 State *cState = &states[states.count() - 2];
467 State *nState = &states[states.count() - 1];
469 nState->context = cState->context;
470 nState->compiledData = type.component;
471 nState->instructionStream = type.component->bytecode.constData();
473 if (instr.bindingBits != -1) {
474 const QByteArray &bits = cState->compiledData->datas.at(instr.bindingBits);
475 nState->bindingSkipList = QBitField((const quint32*)bits.constData(),
479 nState->bindingSkipList = nState->bindingSkipList.united(cState->bindingSkipList);
481 // As the state in the state stack changed, execution will continue in the new program.
482 QML_END_INSTR(CreateQMLObject)
484 QML_BEGIN_INSTR(CompleteQMLObject)
485 QObject *o = objects.top();
487 QDeclarativeData *ddata = QDeclarativeData::get(o);
491 if (ddata->context) {
492 Q_ASSERT(ddata->context != CTXT);
493 Q_ASSERT(ddata->outerContext);
494 Q_ASSERT(ddata->outerContext != CTXT);
495 QDeclarativeContextData *c = ddata->context;
496 while (c->linkedContext) c = c->linkedContext;
497 c->linkedContext = CTXT;
502 ddata->ownContext = true;
503 } else if (!ddata->context) {
507 ddata->setImplicitDestructible();
508 ddata->outerContext = CTXT;
509 ddata->lineNumber = instr.line;
510 ddata->columnNumber = instr.column;
511 QML_END_INSTR(CompleteQMLObject)
513 QML_BEGIN_INSTR(CreateCppObject)
514 const QDeclarativeCompiledData::TypeReference &type = TYPES.at(instr.type);
519 type.type->create(&o, &memory, sizeof(QDeclarativeData));
520 QDeclarativeData *ddata = new (memory) QDeclarativeData;
521 ddata->ownMemory = false;
522 QObjectPrivate::get(o)->declarativeData = ddata;
524 if (type.typePropertyCache && !ddata->propertyCache) {
525 ddata->propertyCache = type.typePropertyCache;
526 ddata->propertyCache->addref();
530 VME_EXCEPTION(tr("Unable to create object of type %1").arg(type.className), instr.line);
533 if (ddata->context) {
534 Q_ASSERT(ddata->context != CTXT);
535 Q_ASSERT(ddata->outerContext);
536 Q_ASSERT(ddata->outerContext != CTXT);
537 QDeclarativeContextData *c = ddata->context;
538 while (c->linkedContext) c = c->linkedContext;
539 c->linkedContext = CTXT;
544 ddata->ownContext = true;
545 } else if (!ddata->context) {
549 ddata->setImplicitDestructible();
550 ddata->outerContext = CTXT;
551 ddata->lineNumber = instr.line;
552 ddata->columnNumber = instr.column;
554 if (instr.data != -1) {
555 QDeclarativeCustomParser *customParser =
556 TYPES.at(instr.type).type->customParser();
557 customParser->setCustomData(o, DATAS.at(instr.data));
559 if (!objects.isEmpty()) {
560 QObject *parent = objects.top();
561 #if 0 // ### refactor
562 if (o->isWidgetType() && parent->isWidgetType())
563 static_cast<QWidget*>(o)->setParent(static_cast<QWidget*>(parent));
566 QDeclarative_setParent_noEvent(o, parent);
569 QML_END_INSTR(CreateCppObject)
571 QML_BEGIN_INSTR(CreateSimpleObject)
572 QObject *o = (QObject *)operator new(instr.typeSize + sizeof(QDeclarativeData));
573 ::memset(o, 0, instr.typeSize + sizeof(QDeclarativeData));
576 QDeclarativeData *ddata = (QDeclarativeData *)(((const char *)o) + instr.typeSize);
577 const QDeclarativeCompiledData::TypeReference &ref = TYPES.at(instr.type);
578 if (!ddata->propertyCache && ref.typePropertyCache) {
579 ddata->propertyCache = ref.typePropertyCache;
580 ddata->propertyCache->addref();
582 ddata->lineNumber = instr.line;
583 ddata->columnNumber = instr.column;
585 QObjectPrivate::get(o)->declarativeData = ddata;
586 ddata->context = ddata->outerContext = CTXT;
587 ddata->nextContextObject = CTXT->contextObjects;
588 if (ddata->nextContextObject)
589 ddata->nextContextObject->prevContextObject = &ddata->nextContextObject;
590 ddata->prevContextObject = &CTXT->contextObjects;
591 CTXT->contextObjects = ddata;
593 QObject *parent = objects.top();
594 QDeclarative_setParent_noEvent(o, parent);
597 QML_END_INSTR(CreateSimpleObject)
599 QML_BEGIN_INSTR(SetId)
600 QObject *target = objects.top();
601 CTXT->setIdProperty(instr.index, target);
604 QML_BEGIN_INSTR(SetDefault)
605 CTXT->contextObject = objects.top();
606 QML_END_INSTR(SetDefault)
608 QML_BEGIN_INSTR(CreateComponent)
609 QDeclarativeComponent *qcomp =
610 new QDeclarativeComponent(CTXT->engine, COMP, INSTRUCTIONSTREAM - COMP->bytecode.constData(),
611 objects.isEmpty() ? 0 : objects.top());
613 QDeclarativeData *ddata = QDeclarativeData::get(qcomp, true);
616 CTXT->addObject(qcomp);
619 ddata->ownContext = true;
621 ddata->setImplicitDestructible();
622 ddata->outerContext = CTXT;
623 ddata->lineNumber = instr.line;
624 ddata->columnNumber = instr.column;
626 QDeclarativeComponentPrivate::get(qcomp)->creationContext = CTXT;
629 INSTRUCTIONSTREAM += instr.count;
630 QML_END_INSTR(CreateComponent)
632 QML_BEGIN_INSTR(StoreMetaObject)
633 QObject *target = objects.top();
636 const QByteArray &metadata = DATAS.at(instr.data);
637 QFastMetaBuilder::fromData(&mo, 0, metadata);
639 const QDeclarativeVMEMetaData *data =
640 (const QDeclarativeVMEMetaData *)DATAS.at(instr.aliasData).constData();
642 (void)new QDeclarativeVMEMetaObject(target, &mo, data, COMP);
644 if (instr.propertyCache != -1) {
645 QDeclarativeData *ddata = QDeclarativeData::get(target, true);
646 if (ddata->propertyCache) ddata->propertyCache->release();
647 ddata->propertyCache = PROPERTYCACHES.at(instr.propertyCache);
648 ddata->propertyCache->addref();
650 QML_END_INSTR(StoreMetaObject)
652 QML_BEGIN_INSTR(AssignCustomType)
653 QObject *target = objects.top();
654 CLEAN_PROPERTY(target, instr.propertyIndex);
656 const QString &primitive = PRIMITIVES.at(instr.primitive);
657 int type = instr.type;
658 QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type);
659 QVariant v = (*converter)(primitive);
662 target->metaObject()->property(instr.propertyIndex);
663 if (v.isNull() || ((int)prop.type() != type && prop.userType() != type))
664 VME_EXCEPTION(tr("Cannot assign value %1 to property %2").arg(primitive).arg(QString::fromUtf8(prop.name())), instr.line);
666 void *a[] = { (void *)v.data(), 0, &status, &flags };
667 QMetaObject::metacall(target, QMetaObject::WriteProperty,
668 instr.propertyIndex, a);
669 QML_END_INSTR(AssignCustomType)
671 QML_BEGIN_INSTR(AssignSignalObject)
674 QObject *assign = objects.pop();
675 QObject *target = objects.top();
676 int sigIdx = instr.signal;
677 const QString &pr = PRIMITIVES.at(sigIdx);
679 QDeclarativeProperty prop(target, pr);
680 if (prop.type() & QDeclarativeProperty::SignalProperty) {
682 QMetaMethod method = QDeclarativeMetaType::defaultMethod(assign);
683 if (method.signature() == 0)
684 VME_EXCEPTION(tr("Cannot assign object type %1 with no default method").arg(QString::fromLatin1(assign->metaObject()->className())), instr.line);
686 if (!QMetaObject::checkConnectArgs(prop.method().signature(), method.signature()))
687 VME_EXCEPTION(tr("Cannot connect mismatched signal/slot %1 %vs. %2").arg(QString::fromLatin1(method.signature())).arg(QString::fromLatin1(prop.method().signature())), instr.line);
689 QDeclarativePropertyPrivate::connect(target, prop.index(), assign, method.methodIndex());
692 VME_EXCEPTION(tr("Cannot assign an object to signal property %1").arg(pr), instr.line);
696 QML_END_INSTR(AssignSignalObject)
698 QML_BEGIN_INSTR(StoreSignal)
699 QObject *target = objects.top();
700 QObject *context = objects.at(objects.count() - 1 - instr.context);
702 QMetaMethod signal = target->metaObject()->method(instr.signalIndex);
704 QDeclarativeBoundSignal *bs = new QDeclarativeBoundSignal(target, signal, target);
705 QDeclarativeExpression *expr =
706 new QDeclarativeExpression(CTXT, context, PRIMITIVES.at(instr.value), true, COMP->name, instr.line, *new QDeclarativeExpressionPrivate);
707 bs->setExpression(expr);
708 QML_END_INSTR(StoreSignal)
710 QML_BEGIN_INSTR(StoreImportedScript)
711 CTXT->importedScripts << run(CTXT, SCRIPTS.at(instr.value));
712 QML_END_INSTR(StoreImportedScript)
714 QML_BEGIN_INSTR(StoreScriptString)
715 QObject *target = objects.top();
716 QObject *scope = objects.at(objects.count() - 1 - instr.scope);
717 QDeclarativeScriptString ss;
718 ss.setContext(CTXT->asQDeclarativeContext());
719 ss.setScopeObject(scope);
720 ss.setScript(PRIMITIVES.at(instr.value));
721 ss.d.data()->bindingId = instr.bindingId;
722 ss.d.data()->lineNumber = instr.line;
724 void *a[] = { &ss, 0, &status, &flags };
725 QMetaObject::metacall(target, QMetaObject::WriteProperty,
726 instr.propertyIndex, a);
727 QML_END_INSTR(StoreScriptString)
729 QML_BEGIN_INSTR(BeginObject)
730 QObject *target = objects.top();
731 QDeclarativeParserStatus *status = reinterpret_cast<QDeclarativeParserStatus *>(reinterpret_cast<char *>(target) + instr.castValue);
732 parserStatus.push(status);
733 #ifdef QML_ENABLE_TRACE
734 Q_ASSERT(QObjectPrivate::get(target)->declarativeData);
735 parserStatusData.push(static_cast<QDeclarativeData *>(QObjectPrivate::get(target)->declarativeData));
737 status->d = &parserStatus.top();
739 status->classBegin();
740 QML_END_INSTR(BeginObject)
742 QML_BEGIN_INSTR(InitV8Bindings)
743 CTXT->v8bindings = new QV8Bindings(PRIMITIVES.at(instr.program), instr.programIndex,
744 instr.line, COMP, CTXT);
745 QML_END_INSTR(InitV8Bindings)
747 QML_BEGIN_INSTR(StoreBinding)
749 objects.at(objects.count() - 1 - instr.owner);
751 objects.at(objects.count() - 1 - instr.context);
753 if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex))
754 QML_NEXT_INSTR(StoreBinding);
756 QDeclarativeBinding *bind = new QDeclarativeBinding(PRIMITIVES.at(instr.value), true,
757 context, CTXT, COMP->name, instr.line,
759 bindValues.push(bind);
760 bind->m_mePtr = &bindValues.top();
761 bind->setTarget(target, instr.property, CTXT);
763 bind->addToObject(target, QDeclarativePropertyPrivate::bindingIndex(instr.property));
764 QML_END_INSTR(StoreBinding)
766 QML_BEGIN_INSTR(StoreBindingOnAlias)
768 objects.at(objects.count() - 1 - instr.owner);
770 objects.at(objects.count() - 1 - instr.context);
772 if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex))
773 QML_NEXT_INSTR(StoreBindingOnAlias);
775 QDeclarativeBinding *bind = new QDeclarativeBinding(PRIMITIVES.at(instr.value), true,
776 context, CTXT, COMP->name, instr.line,
778 bindValues.push(bind);
779 bind->m_mePtr = &bindValues.top();
780 bind->setTarget(target, instr.property, CTXT);
782 QDeclarativeAbstractBinding *old =
783 QDeclarativePropertyPrivate::setBindingNoEnable(target, instr.property.coreIndex,
784 instr.property.getValueTypeCoreIndex(),
786 if (old) { old->destroy(); }
787 QML_END_INSTR(StoreBindingOnAlias)
789 QML_BEGIN_INSTR(StoreV4Binding)
791 objects.at(objects.count() - 1 - instr.owner);
793 objects.at(objects.count() - 1 - instr.context);
795 int property = instr.property;
796 if (instr.isRoot && BINDINGSKIPLIST.testBit(property & 0xFFFF))
797 QML_NEXT_INSTR(StoreV4Binding);
799 QDeclarativeAbstractBinding *binding =
800 CTXT->v4bindings->configBinding(instr.value, target, scope, property,
801 instr.line, instr.column);
802 bindValues.push(binding);
803 binding->m_mePtr = &bindValues.top();
804 binding->addToObject(target, property);
805 QML_END_INSTR(StoreV4Binding)
807 QML_BEGIN_INSTR(StoreV8Binding)
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(StoreV8Binding);
816 QDeclarativeAbstractBinding *binding =
817 CTXT->v8bindings->configBinding(instr.value, target, scope,
818 instr.property, instr.line,
820 bindValues.push(binding);
821 binding->m_mePtr = &bindValues.top();
822 binding->addToObject(target, QDeclarativePropertyPrivate::bindingIndex(instr.property));
823 QML_END_INSTR(StoreV8Binding)
825 QML_BEGIN_INSTR(StoreValueSource)
826 QObject *obj = objects.pop();
827 QDeclarativePropertyValueSource *vs = reinterpret_cast<QDeclarativePropertyValueSource *>(reinterpret_cast<char *>(obj) + instr.castValue);
828 QObject *target = objects.at(objects.count() - 1 - instr.owner);
830 obj->setParent(target);
831 vs->setTarget(QDeclarativePropertyPrivate::restore(target, instr.property, CTXT));
832 QML_END_INSTR(StoreValueSource)
834 QML_BEGIN_INSTR(StoreValueInterceptor)
835 QObject *obj = objects.pop();
836 QDeclarativePropertyValueInterceptor *vi = reinterpret_cast<QDeclarativePropertyValueInterceptor *>(reinterpret_cast<char *>(obj) + instr.castValue);
837 QObject *target = objects.at(objects.count() - 1 - instr.owner);
838 QDeclarativeProperty prop =
839 QDeclarativePropertyPrivate::restore(target, instr.property, CTXT);
840 obj->setParent(target);
842 QDeclarativeVMEMetaObject *mo = static_cast<QDeclarativeVMEMetaObject *>((QMetaObject*)target->metaObject());
843 mo->registerInterceptor(prop.index(), QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), vi);
844 QML_END_INSTR(StoreValueInterceptor)
846 QML_BEGIN_INSTR(StoreObjectQList)
847 QObject *assign = objects.pop();
849 const List &list = lists.top();
850 list.qListProperty.append((QDeclarativeListProperty<void>*)&list.qListProperty, assign);
851 QML_END_INSTR(StoreObjectQList)
853 QML_BEGIN_INSTR(AssignObjectList)
854 // This is only used for assigning interfaces
855 QObject *assign = objects.pop();
856 const List &list = lists.top();
858 int type = list.type;
862 const char *iid = QDeclarativeMetaType::interfaceIId(type);
864 ptr = assign->qt_metacast(iid);
866 VME_EXCEPTION(tr("Cannot assign object to list"), instr.line);
869 list.qListProperty.append((QDeclarativeListProperty<void>*)&list.qListProperty, ptr);
870 QML_END_INSTR(AssignObjectList)
872 QML_BEGIN_INSTR(StoreInterface)
873 QObject *assign = objects.pop();
874 QObject *target = objects.top();
875 CLEAN_PROPERTY(target, instr.propertyIndex);
877 int coreIdx = instr.propertyIndex;
878 QMetaProperty prop = target->metaObject()->property(coreIdx);
879 int t = prop.userType();
880 const char *iid = QDeclarativeMetaType::interfaceIId(t);
883 void *ptr = assign->qt_metacast(iid);
885 void *a[] = { &ptr, 0, &status, &flags };
886 QMetaObject::metacall(target,
887 QMetaObject::WriteProperty,
894 VME_EXCEPTION(tr("Cannot assign object to interface property"), instr.line);
895 QML_END_INSTR(StoreInterface)
897 QML_BEGIN_INSTR(FetchAttached)
898 QObject *target = objects.top();
900 QObject *qmlObject = qmlAttachedPropertiesObjectById(instr.id, target);
903 VME_EXCEPTION(tr("Unable to create attached object"), instr.line);
905 objects.push(qmlObject);
906 QML_END_INSTR(FetchAttached)
908 QML_BEGIN_INSTR(FetchQList)
909 QObject *target = objects.top();
911 lists.push(List(instr.type));
914 a[0] = (void *)&(lists.top().qListProperty);
915 QMetaObject::metacall(target, QMetaObject::ReadProperty,
917 QML_END_INSTR(FetchQList)
919 QML_BEGIN_INSTR(FetchObject)
920 QObject *target = objects.top();
923 // NOTE: This assumes a cast to QObject does not alter the
927 QMetaObject::metacall(target, QMetaObject::ReadProperty,
931 VME_EXCEPTION(tr("Cannot set properties on %1 as it is null").arg(QString::fromUtf8(target->metaObject()->property(instr.property).name())), instr.line);
934 QML_END_INSTR(FetchObject)
936 QML_BEGIN_INSTR(PopQList)
938 QML_END_INSTR(PopQList)
940 QML_BEGIN_INSTR(Defer)
941 if (instr.deferCount) {
942 QObject *target = objects.top();
943 QDeclarativeData *data =
944 QDeclarativeData::get(target, true);
946 data->deferredComponent = COMP;
947 data->deferredIdx = INSTRUCTIONSTREAM - COMP->bytecode.constData();
948 INSTRUCTIONSTREAM += instr.deferCount;
952 QML_BEGIN_INSTR(PopFetchedObject)
954 QML_END_INSTR(PopFetchedObject)
956 QML_BEGIN_INSTR(FetchValueType)
957 QObject *target = objects.top();
959 if (instr.bindingSkipList != 0) {
960 // Possibly need to clear bindings
961 QDeclarativeData *targetData = QDeclarativeData::get(target);
963 QDeclarativeAbstractBinding *binding =
964 QDeclarativePropertyPrivate::binding(target, instr.property, -1);
966 if (binding && binding->bindingType() != QDeclarativeAbstractBinding::ValueTypeProxy) {
967 QDeclarativePropertyPrivate::setBinding(target, instr.property, -1, 0);
969 } else if (binding) {
970 QDeclarativeValueTypeProxyBinding *proxy =
971 static_cast<QDeclarativeValueTypeProxyBinding *>(binding);
972 proxy->removeBindings(instr.bindingSkipList);
977 QDeclarativeValueType *valueHandler = ep->valueTypes[instr.type];
978 valueHandler->read(target, instr.property);
979 objects.push(valueHandler);
980 QML_END_INSTR(FetchValueType)
982 QML_BEGIN_INSTR(PopValueType)
983 QDeclarativeValueType *valueHandler =
984 static_cast<QDeclarativeValueType *>(objects.pop());
985 QObject *target = objects.top();
986 valueHandler->write(target, instr.property, QDeclarativePropertyPrivate::BypassInterceptor);
987 QML_END_INSTR(PopValueType)
989 #ifdef QML_THREADED_VME_INTERPRETER
993 qFatal("QDeclarativeCompiledData: Internal error - unknown instruction %d", genericInstr->common.instructionType);
1000 Q_ASSERT(!states.isEmpty());
1001 Q_ASSERT(!errors->isEmpty());
1008 Q_ASSERT(objects.count() == 1);
1010 QObject *rv = objects.top();
1012 objects.deallocate();
1019 void QDeclarativeVME::reset()
1021 Q_ASSERT(!states.isEmpty() || objects.isEmpty());
1023 QRecursionWatcher<QDeclarativeVME, &QDeclarativeVME::recursion> watcher(this);
1025 if (!objects.isEmpty() && !(states.at(0).flags & State::Deferred))
1026 delete objects.at(0);
1028 if (!rootContext.isNull())
1029 rootContext->activeVMEData = 0;
1031 // Remove the QDeclarativeParserStatus and QDeclarativeAbstractBinding back pointers
1032 blank(parserStatus);
1035 while (componentAttached) {
1036 QDeclarativeComponentAttached *a = componentAttached;
1041 objects.deallocate();
1043 bindValues.deallocate();
1044 parserStatus.deallocate();
1045 #ifdef QML_ENABLE_TRACE
1046 parserStatusData.deallocate();
1048 finalizeCallbacks.clear();
1051 creationContext = 0;
1054 // Must be called with a handle scope and context
1055 void QDeclarativeScriptData::initialize(QDeclarativeEngine *engine)
1057 Q_ASSERT(m_program.IsEmpty());
1059 Q_ASSERT(!hasEngine());
1061 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
1062 QV8Engine *v8engine = ep->v8engine();
1064 // If compilation throws an error, a surrounding v8::TryCatch will record it.
1065 v8::Local<v8::Script> program = v8engine->qmlModeCompile(m_programSource, url.toString(), 1);
1066 if (program.IsEmpty())
1069 m_program = qPersistentNew<v8::Script>(program);
1071 addToEngine(engine);
1076 v8::Persistent<v8::Object> QDeclarativeVME::run(QDeclarativeContextData *parentCtxt, QDeclarativeScriptData *script)
1078 if (script->m_loaded)
1079 return qPersistentNew<v8::Object>(script->m_value);
1081 Q_ASSERT(parentCtxt && parentCtxt->engine);
1082 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(parentCtxt->engine);
1083 QV8Engine *v8engine = ep->v8engine();
1085 bool shared = script->pragmas & QDeclarativeScript::Object::ScriptBlock::Shared;
1087 QDeclarativeContextData *effectiveCtxt = parentCtxt;
1091 // Create the script context if required
1092 QDeclarativeContextData *ctxt = new QDeclarativeContextData;
1093 ctxt->isInternal = true;
1094 ctxt->isJSContext = true;
1096 ctxt->isPragmaLibraryContext = true;
1098 ctxt->isPragmaLibraryContext = parentCtxt->isPragmaLibraryContext;
1099 ctxt->url = script->url;
1101 // For backward compatibility, if there are no imports, we need to use the
1102 // imports from the parent context. See QTBUG-17518.
1103 if (!script->importCache->isEmpty()) {
1104 ctxt->imports = script->importCache;
1105 } else if (effectiveCtxt) {
1106 ctxt->imports = effectiveCtxt->imports;
1107 ctxt->importedScripts = effectiveCtxt->importedScripts;
1108 for (int ii = 0; ii < ctxt->importedScripts.count(); ++ii)
1109 ctxt->importedScripts[ii] = qPersistentNew<v8::Object>(ctxt->importedScripts[ii]);
1112 if (ctxt->imports) {
1113 ctxt->imports->addref();
1116 if (effectiveCtxt) {
1117 ctxt->setParent(effectiveCtxt, true);
1119 ctxt->engine = parentCtxt->engine; // Fix for QTBUG-21620
1122 for (int ii = 0; ii < script->scripts.count(); ++ii) {
1123 ctxt->importedScripts << run(ctxt, script->scripts.at(ii)->scriptData());
1126 v8::HandleScope handle_scope;
1127 v8::Context::Scope scope(v8engine->context());
1129 v8::TryCatch try_catch;
1130 if (!script->isInitialized())
1131 script->initialize(parentCtxt->engine);
1133 v8::Local<v8::Object> qmlglobal = v8engine->qmlScope(ctxt, 0);
1135 if (!script->m_program.IsEmpty()) {
1136 script->m_program->Run(qmlglobal);
1138 // Compilation failed.
1139 Q_ASSERT(try_catch.HasCaught());
1142 v8::Persistent<v8::Object> rv;
1144 if (try_catch.HasCaught()) {
1145 v8::Local<v8::Message> message = try_catch.Message();
1146 if (!message.IsEmpty()) {
1147 QDeclarativeError error;
1148 QDeclarativeExpressionPrivate::exceptionToError(message, error);
1153 rv = qPersistentNew<v8::Object>(qmlglobal);
1155 script->m_value = qPersistentNew<v8::Object>(qmlglobal);
1156 script->m_loaded = true;
1162 #ifdef QML_THREADED_VME_INTERPRETER
1163 void **QDeclarativeVME::instructionJumpTable()
1165 static void **jumpTable = 0;
1167 QDeclarativeVME dummy;
1168 QDeclarativeVME::Interrupt i;
1169 dummy.run(0, i, &jumpTable);
1175 QDeclarativeContextData *QDeclarativeVME::complete(const Interrupt &interrupt)
1178 (bindValues.isEmpty() &&
1179 parserStatus.isEmpty() &&
1180 componentAttached == 0 &&
1181 rootContext.isNull() &&
1182 finalizeCallbacks.isEmpty()));
1187 QDeclarativeTrace trace("VME Complete");
1188 #ifdef QML_ENABLE_TRACE
1189 trace.addDetail("URL", rootComponent->url);
1192 ActiveVMERestorer restore(this, QDeclarativeEnginePrivate::get(engine));
1193 QRecursionWatcher<QDeclarativeVME, &QDeclarativeVME::recursion> watcher(this);
1196 QDeclarativeTrace trace("VME Binding Enable");
1197 trace.event("begin binding eval");
1198 while (!bindValues.isEmpty()) {
1199 QDeclarativeAbstractBinding *b = bindValues.pop();
1203 b->setEnabled(true, QDeclarativePropertyPrivate::BypassInterceptor |
1204 QDeclarativePropertyPrivate::DontRemoveBinding);
1207 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1210 bindValues.deallocate();
1214 QDeclarativeTrace trace("VME Component Complete");
1215 while (!parserStatus.isEmpty()) {
1216 QDeclarativeParserStatus *status = parserStatus.pop();
1217 #ifdef QML_ENABLE_TRACE
1218 QDeclarativeData *data = parserStatusData.pop();
1221 if (status && status->d) {
1223 #ifdef QML_ENABLE_TRACE
1224 QDeclarativeTrace trace("Component complete");
1225 trace.addDetail("URL", data->outerContext->url);
1226 trace.addDetail("Line", data->lineNumber);
1228 status->componentComplete();
1231 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1234 parserStatus.deallocate();
1238 QDeclarativeTrace trace("VME Finalize Callbacks");
1239 for (int ii = 0; ii < finalizeCallbacks.count(); ++ii) {
1240 QDeclarativeEnginePrivate::FinalizeCallback callback = finalizeCallbacks.at(ii);
1241 QObject *obj = callback.first;
1243 void *args[] = { 0 };
1244 QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args);
1246 if (watcher.hasRecursed())
1249 finalizeCallbacks.clear();
1253 QDeclarativeTrace trace("VME Component.onCompleted Callbacks");
1254 while (componentAttached) {
1255 QDeclarativeComponentAttached *a = componentAttached;
1257 QDeclarativeData *d = QDeclarativeData::get(a->parent());
1259 Q_ASSERT(d->context);
1260 a->add(&d->context->componentAttached);
1261 emit a->completed();
1263 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1268 QDeclarativeContextData *rv = rootContext;
1272 if (rv) rv->activeVMEData = data;
1277 void QDeclarativeVME::blank(QFiniteStack<QDeclarativeAbstractBinding *> &bs)
1279 for (int ii = 0; ii < bs.count(); ++ii) {
1280 QDeclarativeAbstractBinding *b = bs.at(ii);
1281 if (b) b->m_mePtr = 0;
1285 void QDeclarativeVME::blank(QFiniteStack<QDeclarativeParserStatus *> &pss)
1287 for (int ii = 0; ii < pss.count(); ++ii) {
1288 QDeclarativeParserStatus *ps = pss.at(ii);
1293 QDeclarativeVMEGuard::QDeclarativeVMEGuard()
1294 : m_objectCount(0), m_objects(0), m_contextCount(0), m_contexts(0)
1298 QDeclarativeVMEGuard::~QDeclarativeVMEGuard()
1303 void QDeclarativeVMEGuard::guard(QDeclarativeVME *vme)
1307 m_objectCount = vme->objects.count();
1308 m_objects = new QDeclarativeGuard<QObject>[m_objectCount];
1309 for (int ii = 0; ii < m_objectCount; ++ii)
1310 m_objects[ii] = vme->objects[ii];
1312 m_contextCount = (vme->rootContext.isNull()?0:1) + vme->states.count();
1313 m_contexts = new QDeclarativeGuardedContextData[m_contextCount];
1314 for (int ii = 0; ii < vme->states.count(); ++ii)
1315 m_contexts[ii] = vme->states.at(ii).context;
1316 if (!vme->rootContext.isNull())
1317 m_contexts[m_contextCount - 1] = vme->rootContext.contextData();
1320 void QDeclarativeVMEGuard::clear()
1322 delete [] m_objects;
1323 delete [] m_contexts;
1331 bool QDeclarativeVMEGuard::isOK() const
1333 for (int ii = 0; ii < m_objectCount; ++ii)
1334 if (m_objects[ii].isNull())
1337 for (int ii = 0; ii < m_contextCount; ++ii)
1338 if (m_contexts[ii].isNull())