Adapt to Qt5 meta-object changes
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlvme.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqmlvme_p.h"
43
44 #include "qqmlcompiler_p.h"
45 #include "qqmlboundsignal_p.h"
46 #include "qqmlstringconverters_p.h"
47 #include <private/qmetaobjectbuilder_p.h>
48 #include <private/qfastmetabuilder_p.h>
49 #include "qqmldata_p.h"
50 #include "qqml.h"
51 #include "qqmlcustomparser_p.h"
52 #include "qqmlengine.h"
53 #include "qqmlcontext.h"
54 #include "qqmlcomponent.h"
55 #include "qqmlcomponentattached_p.h"
56 #include "qqmlbinding_p.h"
57 #include "qqmlengine_p.h"
58 #include "qqmlcomponent_p.h"
59 #include "qqmlvmemetaobject_p.h"
60 #include "qqmlbinding_p_p.h"
61 #include "qqmlcontext_p.h"
62 #include <private/qv4bindings_p.h>
63 #include <private/qv8bindings_p.h>
64 #include "qqmlglobal_p.h"
65 #include <private/qfinitestack_p.h>
66 #include "qqmlscriptstring.h"
67 #include "qqmlscriptstring_p.h"
68 #include "qqmlpropertyvalueinterceptor_p.h"
69
70 #include <QStack>
71 #include <QColor>
72 #include <QPointF>
73 #include <QSizeF>
74 #include <QRectF>
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 <QtQml/qjsvalue.h>
81
82 QT_BEGIN_NAMESPACE
83
84 using namespace QQmlVMETypes;
85
86 #define VME_EXCEPTION(desc, line) \
87     { \
88         QQmlError error; \
89         error.setDescription(desc.trimmed()); \
90         error.setLine(line); \
91         error.setUrl(COMP->url); \
92         *errors << error; \
93         goto exceptionExit; \
94     }
95
96 void QQmlVME::init(QQmlContextData *ctxt, QQmlCompiledData *comp, int start,
97                            QQmlContextData *creation)
98 {
99     Q_ASSERT(ctxt);
100     Q_ASSERT(comp);
101
102     if (start == -1) {
103         start = 0;
104     } else {
105         creationContext = creation;
106     }
107
108     State initState;
109     initState.context = ctxt;
110     initState.compiledData = comp;
111     initState.instructionStream = comp->bytecode.constData() + start;
112     states.push(initState);
113
114     typedef QQmlInstruction I;
115     I *i = (I *)initState.instructionStream;
116
117     Q_ASSERT(comp->instructionType(i) == I::Init);
118
119     objects.allocate(i->init.objectStackSize);
120     lists.allocate(i->init.listStackSize);
121     bindValues.allocate(i->init.bindingsSize);
122     parserStatus.allocate(i->init.parserStatusSize);
123
124 #ifdef QML_ENABLE_TRACE
125     parserStatusData.allocate(i->init.parserStatusSize);
126     rootComponent = comp;
127 #endif
128
129     rootContext = 0;
130     engine = ctxt->engine;
131 }
132
133 bool QQmlVME::initDeferred(QObject *object)
134 {
135     QQmlData *data = QQmlData::get(object);
136
137     if (!data || !data->context || !data->deferredComponent)
138         return false;
139
140     QQmlContextData *ctxt = data->context;
141     QQmlCompiledData *comp = data->deferredComponent;
142     int start = data->deferredIdx;
143
144     State initState;
145     initState.flags = State::Deferred;
146     initState.context = ctxt;
147     initState.compiledData = comp;
148     initState.instructionStream = comp->bytecode.constData() + start;
149     states.push(initState);
150
151     typedef QQmlInstruction I;
152     I *i = (I *)initState.instructionStream;
153
154     Q_ASSERT(comp->instructionType(i) == I::DeferInit);
155
156     objects.allocate(i->deferInit.objectStackSize);
157     lists.allocate(i->deferInit.listStackSize);
158     bindValues.allocate(i->deferInit.bindingsSize);
159     parserStatus.allocate(i->deferInit.parserStatusSize);
160
161     objects.push(object);
162
163 #ifdef QML_ENABLE_TRACE
164     parserStatusData.allocate(i->deferInit.parserStatusSize);
165     rootComponent = comp;
166 #endif
167
168     rootContext = 0;
169     engine = ctxt->engine;
170
171     return true;
172 }
173
174 namespace {
175 struct ActiveVMERestorer 
176 {
177     ActiveVMERestorer(QQmlVME *me, QQmlEnginePrivate *ep) 
178     : ep(ep), oldVME(ep->activeVME) { ep->activeVME = me; }
179     ~ActiveVMERestorer() { ep->activeVME = oldVME; }
180
181     QQmlEnginePrivate *ep;
182     QQmlVME *oldVME;
183 };
184 }
185
186 QObject *QQmlVME::execute(QList<QQmlError> *errors, const Interrupt &interrupt)
187 {
188     Q_ASSERT(states.count() >= 1);
189
190 #ifdef QML_ENABLE_TRACE
191     QQmlTrace trace("VME Execute");
192     trace.addDetail("URL", rootComponent->url);
193 #endif
194
195     QQmlEnginePrivate *ep = QQmlEnginePrivate::get(states.at(0).context->engine);
196
197     ActiveVMERestorer restore(this, ep);
198
199     QObject *rv = run(errors, interrupt);
200
201     return rv;
202 }
203
204 inline bool fastHasBinding(QObject *o, int index) 
205 {
206     QQmlData *ddata = static_cast<QQmlData *>(QObjectPrivate::get(o)->declarativeData);
207
208     return ddata && (ddata->bindingBitsSize > index) && 
209            (ddata->bindingBits[index / 32] & (1 << (index % 32)));
210 }
211
212 static void removeBindingOnProperty(QObject *o, int index)
213 {
214     QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(o, index, -1, 0);
215     if (binding) binding->destroy();
216 }
217
218 static QVariant variantFromString(const QString &string)
219 {
220     return QQmlStringConverters::variantFromString(string);
221 }
222
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 QQmlInstructionMeta<(int)QQmlInstruction::I>::DataType &instr = QQmlInstructionMeta<(int)QQmlInstruction::I>::data(*genericInstr); \
227     INSTRUCTIONSTREAM += QQmlInstructionMeta<(int)QQmlInstruction::I>::Size; \
228     Q_UNUSED(instr);
229
230 #ifdef QML_THREADED_VME_INTERPRETER
231 #  define QML_BEGIN_INSTR(I) op_##I: \
232     QML_BEGIN_INSTR_COMMON(I)
233
234 #  define QML_NEXT_INSTR(I) { \
235     if (watcher.hasRecursed()) return 0; \
236     genericInstr = reinterpret_cast<const QQmlInstruction *>(INSTRUCTIONSTREAM); \
237     goto *genericInstr->common.code; \
238     }
239
240 #  define QML_END_INSTR(I) } \
241     if (watcher.hasRecursed()) return 0; \
242     genericInstr = reinterpret_cast<const QQmlInstruction *>(INSTRUCTIONSTREAM); \
243     if (interrupt.shouldInterrupt()) return 0; \
244     goto *genericInstr->common.code;
245
246 #else
247 #  define QML_BEGIN_INSTR(I) \
248     case QQmlInstruction::I: \
249     QML_BEGIN_INSTR_COMMON(I)
250
251 #  define QML_NEXT_INSTR(I) { \
252     if (watcher.hasRecursed()) return 0; \
253     break; \
254     }
255
256 #  define QML_END_INSTR(I) \
257     if (watcher.hasRecursed() || interrupt.shouldInterrupt()) return 0; \
258     } break;
259 #endif
260
261 #define QML_STORE_VALUE(name, cpptype, value) \
262     QML_BEGIN_INSTR(name) \
263         cpptype v = value; \
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); \
268     QML_END_INSTR(name)
269
270 #define QML_STORE_LIST(name, cpptype, value) \
271     QML_BEGIN_INSTR(name) \
272         cpptype v; \
273         v.append(value); \
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); \
278     QML_END_INSTR(name)
279
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         QQmlVMEMetaObject *vmemo = static_cast<QQmlVMEMetaObject *>(mo); \
287         vmemo->setVMEProperty(instr.propertyIndex, v8value); \
288     QML_END_INSTR(name)
289
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); \
296     QML_END_INSTR(name)
297
298 #define CLEAN_PROPERTY(o, index) \
299     if (fastHasBinding(o, index)) \
300         removeBindingOnProperty(o, index)
301
302 QObject *QQmlVME::run(QList<QQmlError> *errors,
303                               const Interrupt &interrupt
304 #ifdef QML_THREADED_VME_INTERPRETER
305                               , void ***storeJumpTable
306 #endif
307                               )
308 {
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)
314         };
315 #undef QML_INSTR_ADDR
316         *storeJumpTable = jumpTable;
317         return 0;
318     }
319 #endif
320     Q_ASSERT(errors->isEmpty());
321     Q_ASSERT(states.count() >= 1);
322
323     QQmlEngine *engine = states.at(0).context->engine;
324     QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
325
326     // Need a v8 handle scope and execution context for StoreVar instructions.
327     v8::HandleScope handleScope;
328     v8::Context::Scope contextScope(ep->v8engine()->context());
329
330     int status = -1; // needed for dbus
331     QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::BypassInterceptor |
332                                                     QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
333
334     QRecursionWatcher<QQmlVME, &QQmlVME::recursion> watcher(this);
335
336 #define COMP states.top().compiledData
337 #define CTXT states.top().context
338 #define INSTRUCTIONSTREAM states.top().instructionStream
339 #define BINDINGSKIPLIST states.top().bindingSkipList
340
341 #define TYPES COMP->types
342 #define PRIMITIVES COMP->primitives
343 #define DATAS COMP->datas
344 #define PROGRAMS COMP->programs
345 #define PROPERTYCACHES COMP->propertyCaches
346 #define SCRIPTS COMP->scripts
347 #define URLS COMP->urls
348
349 #ifdef QML_THREADED_VME_INTERPRETER
350     const QQmlInstruction *genericInstr = reinterpret_cast<const QQmlInstruction *>(INSTRUCTIONSTREAM);
351     goto *genericInstr->common.code;
352 #else
353     for (;;) {
354         const QQmlInstruction *genericInstr = reinterpret_cast<const QQmlInstruction *>(INSTRUCTIONSTREAM);
355
356         switch (genericInstr->common.instructionType) {
357 #endif
358
359         // Store a created object in a property.  These all pop from the objects stack.
360         QML_STORE_VALUE(StoreObject, QObject *, objects.pop());
361         QML_STORE_VALUE(StoreVariantObject, QVariant, QVariant::fromValue(objects.pop()));
362         QML_STORE_VAR(StoreVarObject, ep->v8engine()->newQObject(objects.pop()));
363
364         // Store a literal value in a corresponding property
365         QML_STORE_VALUE(StoreFloat, float, instr.value);
366         QML_STORE_VALUE(StoreDouble, double, instr.value);
367         QML_STORE_VALUE(StoreBool, bool, instr.value);
368         QML_STORE_VALUE(StoreInteger, int, instr.value);
369         QML_STORE_VALUE(StoreColor, QColor, QColor::fromRgba(instr.value));
370         QML_STORE_VALUE(StoreDate, QDate, QDate::fromJulianDay(instr.value));
371         QML_STORE_VALUE(StoreDateTime, QDateTime,
372                         QDateTime(QDate::fromJulianDay(instr.date), *(QTime *)&instr.time));
373         QML_STORE_POINTER(StoreTime, (QTime *)&instr.time);
374         QML_STORE_POINTER(StorePoint, (QPoint *)&instr.point);
375         QML_STORE_POINTER(StorePointF, (QPointF *)&instr.point);
376         QML_STORE_POINTER(StoreSize, (QSize *)&instr.size);
377         QML_STORE_POINTER(StoreSizeF, (QSizeF *)&instr.size);
378         QML_STORE_POINTER(StoreRect, (QRect *)&instr.rect);
379         QML_STORE_POINTER(StoreRectF, (QRectF *)&instr.rect);
380         QML_STORE_POINTER(StoreVector3D, (QVector3D *)&instr.vector);
381         QML_STORE_POINTER(StoreVector4D, (QVector4D *)&instr.vector);
382         QML_STORE_POINTER(StoreString, &PRIMITIVES.at(instr.value));
383         QML_STORE_POINTER(StoreByteArray, &DATAS.at(instr.value));
384         QML_STORE_POINTER(StoreUrl, &URLS.at(instr.value));
385         QML_STORE_VALUE(StoreTrString, QString,
386                         QCoreApplication::translate(DATAS.at(instr.context).constData(),
387                                                     DATAS.at(instr.text).constData(),
388                                                     DATAS.at(instr.comment).constData(),
389                                                     QCoreApplication::UnicodeUTF8,
390                                                     instr.n));
391         QML_STORE_VALUE(StoreTrIdString, QString, qtTrId(DATAS.at(instr.text).constData(), instr.n));
392
393         // Store a literal value in a QList
394         QML_STORE_LIST(StoreStringList, QStringList, PRIMITIVES.at(instr.value));
395         QML_STORE_LIST(StoreStringQList, QList<QString>, PRIMITIVES.at(instr.value));
396         QML_STORE_LIST(StoreUrlQList, QList<QUrl>, URLS.at(instr.value));
397         QML_STORE_LIST(StoreDoubleQList, QList<double>, instr.value);
398         QML_STORE_LIST(StoreBoolQList, QList<bool>, instr.value);
399         QML_STORE_LIST(StoreIntegerQList, QList<int>, instr.value);
400
401         // Store a literal value in a QVariant property
402         QML_STORE_VALUE(StoreVariant, QVariant, variantFromString(PRIMITIVES.at(instr.value)));
403         QML_STORE_VALUE(StoreVariantInteger, QVariant, QVariant(instr.value));
404         QML_STORE_VALUE(StoreVariantDouble, QVariant, QVariant(instr.value));
405         QML_STORE_VALUE(StoreVariantBool, QVariant, QVariant(instr.value));
406
407         // Store a literal value in a var property.
408         // We deliberately do not use string converters here
409         QML_STORE_VAR(StoreVar, ep->v8engine()->fromVariant(PRIMITIVES.at(instr.value)));
410         QML_STORE_VAR(StoreVarInteger, v8::Integer::New(instr.value));
411         QML_STORE_VAR(StoreVarDouble, v8::Number::New(instr.value));
412         QML_STORE_VAR(StoreVarBool, v8::Boolean::New(instr.value));
413
414
415         QML_BEGIN_INSTR(Init)
416             // Ensure that the compiled data has been initialized
417             if (!COMP->isInitialized()) COMP->initialize(engine);
418
419             QQmlContextData *parentCtxt = CTXT;
420             CTXT = new QQmlContextData;
421             CTXT->isInternal = true;
422             CTXT->url = COMP->url;
423             CTXT->urlString = COMP->name;
424             CTXT->imports = COMP->importCache;
425             CTXT->imports->addref();
426             CTXT->setParent(parentCtxt);
427             if (instr.contextCache != -1) 
428                 CTXT->setIdPropertyData(COMP->contextCaches.at(instr.contextCache));
429             if (instr.compiledBinding != -1) {
430                 const char *v4data = DATAS.at(instr.compiledBinding).constData();
431                 CTXT->v4bindings = new QV4Bindings(v4data, CTXT, COMP);
432             }
433             if (states.count() == 1) {
434                 rootContext = CTXT;
435                 rootContext->activeVMEData = data;
436             }
437             if (states.count() == 1 && !creationContext.isNull()) {
438                 // A component that is logically created within another component instance shares the 
439                 // same instances of script imports.  For example:
440                 //
441                 //     import QtQuick 2.0
442                 //     import "test.js" as Test
443                 //     ListView {
444                 //         model: Test.getModel()
445                 //         delegate: Component {
446                 //             Text { text: Test.getValue(index); }
447                 //         }
448                 //     }
449                 //
450                 // Has the same "Test" instance.  To implement this, we simply copy the v8 handles into
451                 // the inner context.  We have to create a fresh persistent handle for each to prevent 
452                 // double dispose.  It is possible we could do this more efficiently using some form of
453                 // referencing instead.
454                 CTXT->importedScripts = creationContext->importedScripts;
455                 for (int ii = 0; ii < CTXT->importedScripts.count(); ++ii)
456                     CTXT->importedScripts[ii] = qPersistentNew<v8::Object>(CTXT->importedScripts[ii]);
457             }
458         QML_END_INSTR(Init)
459
460         QML_BEGIN_INSTR(DeferInit)
461         QML_END_INSTR(DeferInit)
462
463         QML_BEGIN_INSTR(Done)
464             states.pop();
465
466             if (states.isEmpty())
467                 goto normalExit;
468         QML_END_INSTR(Done)
469
470         QML_BEGIN_INSTR(CreateQMLObject)
471             const QQmlCompiledData::TypeReference &type = TYPES.at(instr.type);
472             Q_ASSERT(type.component);
473
474             states.push(State());
475
476             State *cState = &states[states.count() - 2];
477             State *nState = &states[states.count() - 1];
478
479             nState->context = cState->context;
480             nState->compiledData = type.component;
481             nState->instructionStream = type.component->bytecode.constData();
482
483             if (instr.bindingBits != -1) {
484                 const QByteArray &bits = cState->compiledData->datas.at(instr.bindingBits);
485                 nState->bindingSkipList = QBitField((const quint32*)bits.constData(),
486                                                     bits.size() * 8);
487             }
488             if (instr.isRoot)
489                 nState->bindingSkipList = nState->bindingSkipList.united(cState->bindingSkipList);
490
491             // As the state in the state stack changed, execution will continue in the new program.
492         QML_END_INSTR(CreateQMLObject)
493
494         QML_BEGIN_INSTR(CompleteQMLObject)
495             QObject *o = objects.top();
496
497             QQmlData *ddata = QQmlData::get(o);
498             Q_ASSERT(ddata);
499
500             if (instr.isRoot) {
501                 if (ddata->context) {
502                     Q_ASSERT(ddata->context != CTXT);
503                     Q_ASSERT(ddata->outerContext);
504                     Q_ASSERT(ddata->outerContext != CTXT);
505                     QQmlContextData *c = ddata->context;
506                     while (c->linkedContext) c = c->linkedContext;
507                     c->linkedContext = CTXT;
508                 } else {
509                     CTXT->addObject(o);
510                 }
511
512                 ddata->ownContext = true;
513             } else if (!ddata->context) {
514                 CTXT->addObject(o);
515             }
516
517             ddata->setImplicitDestructible();
518             ddata->outerContext = CTXT;
519             ddata->lineNumber = instr.line;
520             ddata->columnNumber = instr.column;
521         QML_END_INSTR(CompleteQMLObject)
522
523         QML_BEGIN_INSTR(CreateCppObject)
524             const QQmlCompiledData::TypeReference &type = TYPES.at(instr.type);
525             Q_ASSERT(type.type);
526
527             QObject *o = 0;
528             void *memory = 0;
529             type.type->create(&o, &memory, sizeof(QQmlData));
530             QQmlData *ddata = new (memory) QQmlData;
531             ddata->ownMemory = false;
532             QObjectPrivate::get(o)->declarativeData = ddata;
533
534             if (type.typePropertyCache && !ddata->propertyCache) {
535                 ddata->propertyCache = type.typePropertyCache;
536                 ddata->propertyCache->addref();
537             }
538
539             if (!o) 
540                 VME_EXCEPTION(tr("Unable to create object of type %1").arg(type.className), instr.line);
541
542             if (instr.isRoot) {
543                 if (ddata->context) {
544                     Q_ASSERT(ddata->context != CTXT);
545                     Q_ASSERT(ddata->outerContext);
546                     Q_ASSERT(ddata->outerContext != CTXT);
547                     QQmlContextData *c = ddata->context;
548                     while (c->linkedContext) c = c->linkedContext;
549                     c->linkedContext = CTXT;
550                 } else {
551                     CTXT->addObject(o);
552                 }
553
554                 ddata->ownContext = true;
555             } else if (!ddata->context) {
556                 CTXT->addObject(o);
557             }
558
559             ddata->setImplicitDestructible();
560             ddata->outerContext = CTXT;
561             ddata->lineNumber = instr.line;
562             ddata->columnNumber = instr.column;
563
564             if (instr.data != -1) {
565                 QQmlCustomParser *customParser =
566                     TYPES.at(instr.type).type->customParser();
567                 customParser->setCustomData(o, DATAS.at(instr.data));
568             }
569             if (!objects.isEmpty()) {
570                 QObject *parent = objects.top();
571 #if 0 // ### refactor
572                 if (o->isWidgetType() && parent->isWidgetType()) 
573                     static_cast<QWidget*>(o)->setParent(static_cast<QWidget*>(parent));
574                 else 
575 #endif
576                     QQml_setParent_noEvent(o, parent);
577             }
578             objects.push(o);
579         QML_END_INSTR(CreateCppObject)
580
581         QML_BEGIN_INSTR(CreateSimpleObject)
582             QObject *o = (QObject *)operator new(instr.typeSize + sizeof(QQmlData));   
583             ::memset(o, 0, instr.typeSize + sizeof(QQmlData));
584             instr.create(o);
585
586             QQmlData *ddata = (QQmlData *)(((const char *)o) + instr.typeSize);
587             const QQmlCompiledData::TypeReference &ref = TYPES.at(instr.type);
588             if (!ddata->propertyCache && ref.typePropertyCache) {
589                 ddata->propertyCache = ref.typePropertyCache;
590                 ddata->propertyCache->addref();
591             }
592             ddata->lineNumber = instr.line;
593             ddata->columnNumber = instr.column;
594
595             QObjectPrivate::get(o)->declarativeData = ddata;                                                      
596             ddata->context = ddata->outerContext = CTXT;
597             ddata->nextContextObject = CTXT->contextObjects; 
598             if (ddata->nextContextObject) 
599                 ddata->nextContextObject->prevContextObject = &ddata->nextContextObject; 
600             ddata->prevContextObject = &CTXT->contextObjects; 
601             CTXT->contextObjects = ddata; 
602
603             QObject *parent = objects.top();                                                                    
604             QQml_setParent_noEvent(o, parent);                                                        
605
606             objects.push(o);
607         QML_END_INSTR(CreateSimpleObject)
608
609         QML_BEGIN_INSTR(SetId)
610             QObject *target = objects.top();
611             CTXT->setIdProperty(instr.index, target);
612         QML_END_INSTR(SetId)
613
614         QML_BEGIN_INSTR(SetDefault)
615             CTXT->contextObject = objects.top();
616         QML_END_INSTR(SetDefault)
617
618         QML_BEGIN_INSTR(CreateComponent)
619             QQmlComponent *qcomp = 
620                 new QQmlComponent(CTXT->engine, COMP, INSTRUCTIONSTREAM - COMP->bytecode.constData(),
621                                           objects.isEmpty() ? 0 : objects.top());
622
623             QQmlData *ddata = QQmlData::get(qcomp, true);
624             Q_ASSERT(ddata);
625
626             CTXT->addObject(qcomp);
627
628             if (instr.isRoot)
629                 ddata->ownContext = true;
630
631             ddata->setImplicitDestructible();
632             ddata->outerContext = CTXT;
633             ddata->lineNumber = instr.line;
634             ddata->columnNumber = instr.column;
635
636             QQmlComponentPrivate::get(qcomp)->creationContext = CTXT;
637
638             objects.push(qcomp);
639             INSTRUCTIONSTREAM += instr.count;
640         QML_END_INSTR(CreateComponent)
641
642         QML_BEGIN_INSTR(StoreMetaObject)
643             QObject *target = objects.top();
644
645             QMetaObject mo;
646             const QByteArray &metadata = DATAS.at(instr.data);
647             QFastMetaBuilder::fromData(&mo, 0, metadata);
648
649             const QQmlVMEMetaData *data = 
650                 (const QQmlVMEMetaData *)DATAS.at(instr.aliasData).constData();
651
652             (void)new QQmlVMEMetaObject(target, &mo, data, COMP);
653
654             if (instr.propertyCache != -1) {
655                 QQmlData *ddata = QQmlData::get(target, true);
656                 if (ddata->propertyCache) ddata->propertyCache->release();
657                 ddata->propertyCache = PROPERTYCACHES.at(instr.propertyCache);
658                 ddata->propertyCache->addref();
659             }
660         QML_END_INSTR(StoreMetaObject)
661
662         QML_BEGIN_INSTR(AssignCustomType)
663             QObject *target = objects.top();
664             CLEAN_PROPERTY(target, instr.propertyIndex);
665
666             const QString &primitive = PRIMITIVES.at(instr.primitive);
667             int type = instr.type;
668             QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type);
669             QVariant v = (*converter)(primitive);
670
671             QMetaProperty prop = 
672                     target->metaObject()->property(instr.propertyIndex);
673             if (v.isNull() || ((int)prop.type() != type && prop.userType() != type)) 
674                 VME_EXCEPTION(tr("Cannot assign value %1 to property %2").arg(primitive).arg(QString::fromUtf8(prop.name())), instr.line);
675
676             void *a[] = { (void *)v.data(), 0, &status, &flags };
677             QMetaObject::metacall(target, QMetaObject::WriteProperty, 
678                                   instr.propertyIndex, a);
679         QML_END_INSTR(AssignCustomType)
680
681         QML_BEGIN_INSTR(AssignSignalObject)
682             // XXX optimize
683
684             QObject *assign = objects.pop();
685             QObject *target = objects.top();
686             int sigIdx = instr.signal;
687             const QString &pr = PRIMITIVES.at(sigIdx);
688
689             QQmlProperty prop(target, pr);
690             if (prop.type() & QQmlProperty::SignalProperty) {
691
692                 QMetaMethod method = QQmlMetaType::defaultMethod(assign);
693                 if (!method.isValid())
694                     VME_EXCEPTION(tr("Cannot assign object type %1 with no default method").arg(QString::fromLatin1(assign->metaObject()->className())), instr.line);
695
696                 if (!QMetaObject::checkConnectArgs(prop.method(), method)) {
697                     VME_EXCEPTION(tr("Cannot connect mismatched signal/slot %1 %vs. %2")
698                                   .arg(QString::fromLatin1(method.methodSignature().constData()))
699                                   .arg(QString::fromLatin1(prop.method().methodSignature().constData())), instr.line);
700                 }
701
702                 QQmlPropertyPrivate::connect(target, prop.index(), assign, method.methodIndex());
703
704             } else {
705                 VME_EXCEPTION(tr("Cannot assign an object to signal property %1").arg(pr), instr.line);
706             }
707
708
709         QML_END_INSTR(AssignSignalObject)
710
711         QML_BEGIN_INSTR(StoreSignal)
712             QObject *target = objects.top();
713             QObject *context = objects.at(objects.count() - 1 - instr.context);
714
715             QMetaMethod signal = target->metaObject()->method(instr.signalIndex);
716
717             QQmlBoundSignal *bs = new QQmlBoundSignal(target, signal, target);
718             QQmlExpression *expr = 
719                 new QQmlExpression(CTXT, context, DATAS.at(instr.value), true, COMP->name, instr.line, instr.column, *new QQmlExpressionPrivate);
720             bs->setExpression(expr);
721         QML_END_INSTR(StoreSignal)
722
723         QML_BEGIN_INSTR(StoreImportedScript)
724             CTXT->importedScripts << run(CTXT, SCRIPTS.at(instr.value));
725         QML_END_INSTR(StoreImportedScript)
726
727         QML_BEGIN_INSTR(StoreScriptString)
728             QObject *target = objects.top();
729             QObject *scope = objects.at(objects.count() - 1 - instr.scope);
730             QQmlScriptString ss;
731             ss.setContext(CTXT->asQQmlContext());
732             ss.setScopeObject(scope);
733             ss.setScript(PRIMITIVES.at(instr.value));
734             ss.d.data()->bindingId = instr.bindingId;
735             ss.d.data()->lineNumber = instr.line;
736             ss.d.data()->columnNumber = instr.column;
737
738             void *a[] = { &ss, 0, &status, &flags };
739             QMetaObject::metacall(target, QMetaObject::WriteProperty, 
740                                   instr.propertyIndex, a);
741         QML_END_INSTR(StoreScriptString)
742
743         QML_BEGIN_INSTR(BeginObject)
744             QObject *target = objects.top();
745             QQmlParserStatus *status = reinterpret_cast<QQmlParserStatus *>(reinterpret_cast<char *>(target) + instr.castValue);
746             parserStatus.push(status);
747 #ifdef QML_ENABLE_TRACE
748             Q_ASSERT(QObjectPrivate::get(target)->declarativeData);
749             parserStatusData.push(static_cast<QQmlData *>(QObjectPrivate::get(target)->declarativeData));
750 #endif
751             status->d = &parserStatus.top();
752
753             status->classBegin();
754         QML_END_INSTR(BeginObject)
755
756         QML_BEGIN_INSTR(InitV8Bindings)
757             CTXT->v8bindings = new QV8Bindings(&PROGRAMS[instr.programIndex], instr.line, CTXT);
758         QML_END_INSTR(InitV8Bindings)
759
760         QML_BEGIN_INSTR(StoreBinding)
761             QObject *target = 
762                 objects.at(objects.count() - 1 - instr.owner);
763             QObject *context = 
764                 objects.at(objects.count() - 1 - instr.context);
765
766             if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex))
767                 QML_NEXT_INSTR(StoreBinding);
768
769             QQmlBinding *bind = new QQmlBinding(PRIMITIVES.at(instr.value), true, 
770                                                                 context, CTXT, COMP->name, instr.line,
771                                                                 instr.column);
772             bindValues.push(bind);
773             bind->m_mePtr = &bindValues.top();
774             bind->setTarget(target, instr.property, CTXT);
775
776             typedef QQmlPropertyPrivate QDPP;
777             Q_ASSERT(bind->propertyIndex() == QDPP::bindingIndex(instr.property));
778             Q_ASSERT(bind->object() == target);
779
780             bind->addToObject();
781         QML_END_INSTR(StoreBinding)
782
783         QML_BEGIN_INSTR(StoreBindingOnAlias)
784             QObject *target = 
785                 objects.at(objects.count() - 1 - instr.owner);
786             QObject *context = 
787                 objects.at(objects.count() - 1 - instr.context);
788
789             if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex))
790                 QML_NEXT_INSTR(StoreBindingOnAlias);
791
792             QQmlBinding *bind = new QQmlBinding(PRIMITIVES.at(instr.value), true,
793                                                                 context, CTXT, COMP->name, instr.line,
794                                                                 instr.column);
795             bindValues.push(bind);
796             bind->m_mePtr = &bindValues.top();
797             bind->setTarget(target, instr.property, CTXT);
798
799             QQmlAbstractBinding *old =
800                 QQmlPropertyPrivate::setBindingNoEnable(target, instr.property.coreIndex,
801                                                                 instr.property.getValueTypeCoreIndex(),
802                                                                 bind);
803             if (old) { old->destroy(); }
804         QML_END_INSTR(StoreBindingOnAlias)
805
806         QML_BEGIN_INSTR(StoreV4Binding)
807             QObject *target = 
808                 objects.at(objects.count() - 1 - instr.owner);
809             QObject *scope = 
810                 objects.at(objects.count() - 1 - instr.context);
811
812             int property = instr.property;
813             if (instr.isRoot && BINDINGSKIPLIST.testBit(property & 0xFFFF))
814                 QML_NEXT_INSTR(StoreV4Binding);
815
816             QQmlAbstractBinding *binding = 
817                 CTXT->v4bindings->configBinding(instr.value, target, scope, property,
818                                                 instr.line, instr.column);
819             bindValues.push(binding);
820             binding->m_mePtr = &bindValues.top();
821
822             Q_ASSERT(binding->propertyIndex() == property);
823             Q_ASSERT(binding->object() == target);
824
825             binding->addToObject();
826         QML_END_INSTR(StoreV4Binding)
827
828         QML_BEGIN_INSTR(StoreV8Binding)
829             QObject *target = 
830                 objects.at(objects.count() - 1 - instr.owner);
831             QObject *scope = 
832                 objects.at(objects.count() - 1 - instr.context);
833
834             if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex))
835                 QML_NEXT_INSTR(StoreV8Binding);
836
837             QQmlAbstractBinding *binding = CTXT->v8bindings->configBinding(target, scope,
838                                                                                    &instr);
839             if (binding) {
840                 bindValues.push(binding);
841                 binding->m_mePtr = &bindValues.top();
842
843                 typedef QQmlPropertyPrivate QDPP;
844                 Q_ASSERT(binding->propertyIndex() == QDPP::bindingIndex(instr.property));
845                 Q_ASSERT(binding->object() == target);
846
847                 binding->addToObject();
848             }
849         QML_END_INSTR(StoreV8Binding)
850
851         QML_BEGIN_INSTR(StoreValueSource)
852             QObject *obj = objects.pop();
853             QQmlPropertyValueSource *vs = reinterpret_cast<QQmlPropertyValueSource *>(reinterpret_cast<char *>(obj) + instr.castValue);
854             QObject *target = objects.at(objects.count() - 1 - instr.owner);
855
856             obj->setParent(target);
857             vs->setTarget(QQmlPropertyPrivate::restore(target, instr.property, CTXT));
858         QML_END_INSTR(StoreValueSource)
859
860         QML_BEGIN_INSTR(StoreValueInterceptor)
861             QObject *obj = objects.pop();
862             QQmlPropertyValueInterceptor *vi = reinterpret_cast<QQmlPropertyValueInterceptor *>(reinterpret_cast<char *>(obj) + instr.castValue);
863             QObject *target = objects.at(objects.count() - 1 - instr.owner);
864             QQmlProperty prop = 
865                 QQmlPropertyPrivate::restore(target, instr.property, CTXT);
866             obj->setParent(target);
867             vi->setTarget(prop);
868             QQmlVMEMetaObject *mo = static_cast<QQmlVMEMetaObject *>((QMetaObject*)target->metaObject());
869             mo->registerInterceptor(prop.index(), QQmlPropertyPrivate::valueTypeCoreIndex(prop), vi);
870         QML_END_INSTR(StoreValueInterceptor)
871
872         QML_BEGIN_INSTR(StoreObjectQList)
873             QObject *assign = objects.pop();
874
875             const List &list = lists.top();
876             list.qListProperty.append((QQmlListProperty<void>*)&list.qListProperty, assign);
877         QML_END_INSTR(StoreObjectQList)
878
879         QML_BEGIN_INSTR(AssignObjectList)
880             // This is only used for assigning interfaces
881             QObject *assign = objects.pop();
882             const List &list = lists.top();
883
884             int type = list.type;
885
886             void *ptr = 0;
887
888             const char *iid = QQmlMetaType::interfaceIId(type);
889             if (iid) 
890                 ptr = assign->qt_metacast(iid);
891             if (!ptr) 
892                 VME_EXCEPTION(tr("Cannot assign object to list"), instr.line);
893
894
895             list.qListProperty.append((QQmlListProperty<void>*)&list.qListProperty, ptr);
896         QML_END_INSTR(AssignObjectList)
897
898         QML_BEGIN_INSTR(StoreInterface)
899             QObject *assign = objects.pop();
900             QObject *target = objects.top();
901             CLEAN_PROPERTY(target, instr.propertyIndex);
902
903             int coreIdx = instr.propertyIndex;
904             QMetaProperty prop = target->metaObject()->property(coreIdx);
905             int t = prop.userType();
906             const char *iid = QQmlMetaType::interfaceIId(t);
907             bool ok = false;
908             if (iid) {
909                 void *ptr = assign->qt_metacast(iid);
910                 if (ptr) {
911                     void *a[] = { &ptr, 0, &status, &flags };
912                     QMetaObject::metacall(target, 
913                                           QMetaObject::WriteProperty,
914                                           coreIdx, a);
915                     ok = true;
916                 }
917             } 
918
919             if (!ok) 
920                 VME_EXCEPTION(tr("Cannot assign object to interface property"), instr.line);
921         QML_END_INSTR(StoreInterface)
922             
923         QML_BEGIN_INSTR(FetchAttached)
924             QObject *target = objects.top();
925
926             QObject *qmlObject = qmlAttachedPropertiesObjectById(instr.id, target);
927
928             if (!qmlObject)
929                 VME_EXCEPTION(tr("Unable to create attached object"), instr.line);
930
931             objects.push(qmlObject);
932         QML_END_INSTR(FetchAttached)
933
934         QML_BEGIN_INSTR(FetchQList)
935             QObject *target = objects.top();
936
937             lists.push(List(instr.type));
938
939             void *a[1];
940             a[0] = (void *)&(lists.top().qListProperty);
941             QMetaObject::metacall(target, QMetaObject::ReadProperty, 
942                                   instr.property, a);
943         QML_END_INSTR(FetchQList)
944
945         QML_BEGIN_INSTR(FetchObject)
946             QObject *target = objects.top();
947
948             QObject *obj = 0;
949             // NOTE: This assumes a cast to QObject does not alter the 
950             // object pointer
951             void *a[1];
952             a[0] = &obj;
953             QMetaObject::metacall(target, QMetaObject::ReadProperty, 
954                                   instr.property, a);
955
956             if (!obj)
957                 VME_EXCEPTION(tr("Cannot set properties on %1 as it is null").arg(QString::fromUtf8(target->metaObject()->property(instr.property).name())), instr.line);
958
959             objects.push(obj);
960         QML_END_INSTR(FetchObject)
961
962         QML_BEGIN_INSTR(PopQList)
963             lists.pop();
964         QML_END_INSTR(PopQList)
965
966         QML_BEGIN_INSTR(Defer)
967             if (instr.deferCount) {
968                 QObject *target = objects.top();
969                 QQmlData *data = 
970                     QQmlData::get(target, true);
971                 COMP->addref();
972                 data->deferredComponent = COMP;
973                 data->deferredIdx = INSTRUCTIONSTREAM - COMP->bytecode.constData();
974                 INSTRUCTIONSTREAM += instr.deferCount;
975             }
976         QML_END_INSTR(Defer)
977
978         QML_BEGIN_INSTR(PopFetchedObject)
979             objects.pop();
980         QML_END_INSTR(PopFetchedObject)
981
982         QML_BEGIN_INSTR(FetchValueType)
983             QObject *target = objects.top();
984
985             if (instr.bindingSkipList != 0) {
986                 // Possibly need to clear bindings
987                 QQmlData *targetData = QQmlData::get(target);
988                 if (targetData) {
989                     QQmlAbstractBinding *binding = 
990                         QQmlPropertyPrivate::binding(target, instr.property, -1);
991
992                     if (binding && binding->bindingType() != QQmlAbstractBinding::ValueTypeProxy) {
993                         QQmlPropertyPrivate::setBinding(target, instr.property, -1, 0);
994                         binding->destroy();
995                     } else if (binding) {
996                         QQmlValueTypeProxyBinding *proxy = 
997                             static_cast<QQmlValueTypeProxyBinding *>(binding);
998                         proxy->removeBindings(instr.bindingSkipList);
999                     }
1000                 }
1001             }
1002
1003             QQmlValueType *valueHandler = ep->valueTypes[instr.type];
1004             valueHandler->read(target, instr.property);
1005             objects.push(valueHandler);
1006         QML_END_INSTR(FetchValueType)
1007
1008         QML_BEGIN_INSTR(PopValueType)
1009             QQmlValueType *valueHandler = 
1010                 static_cast<QQmlValueType *>(objects.pop());
1011             QObject *target = objects.top();
1012             valueHandler->write(target, instr.property, QQmlPropertyPrivate::BypassInterceptor);
1013         QML_END_INSTR(PopValueType)
1014
1015 #ifdef QML_THREADED_VME_INTERPRETER
1016     // nothing to do
1017 #else
1018         default:
1019             qFatal("QQmlCompiledData: Internal error - unknown instruction %d", genericInstr->common.instructionType);
1020             break;
1021         }
1022     }
1023 #endif
1024
1025 exceptionExit:
1026     Q_ASSERT(!states.isEmpty());
1027     Q_ASSERT(!errors->isEmpty());
1028
1029     reset();
1030
1031     return 0;
1032
1033 normalExit:
1034     Q_ASSERT(objects.count() == 1);
1035
1036     QObject *rv = objects.top();
1037
1038     objects.deallocate();
1039     lists.deallocate();
1040     states.clear();
1041
1042     return rv;
1043 }
1044
1045 void QQmlVME::reset()
1046 {
1047     Q_ASSERT(!states.isEmpty() || objects.isEmpty());
1048
1049     QRecursionWatcher<QQmlVME, &QQmlVME::recursion> watcher(this);
1050
1051     if (!objects.isEmpty() && !(states.at(0).flags & State::Deferred))
1052         delete objects.at(0); 
1053     
1054     if (!rootContext.isNull()) 
1055         rootContext->activeVMEData = 0;
1056
1057     // Remove the QQmlParserStatus and QQmlAbstractBinding back pointers
1058     blank(parserStatus);
1059     blank(bindValues);
1060
1061     while (componentAttached) {
1062         QQmlComponentAttached *a = componentAttached;
1063         a->rem();
1064     }
1065     
1066     engine = 0;
1067     objects.deallocate();
1068     lists.deallocate();
1069     bindValues.deallocate();
1070     parserStatus.deallocate();
1071 #ifdef QML_ENABLE_TRACE
1072     parserStatusData.deallocate();
1073 #endif
1074     finalizeCallbacks.clear();
1075     states.clear();
1076     rootContext = 0;
1077     creationContext = 0;
1078 }
1079
1080 // Must be called with a handle scope and context
1081 void QQmlScriptData::initialize(QQmlEngine *engine)
1082 {
1083     Q_ASSERT(m_program.IsEmpty());
1084     Q_ASSERT(engine);
1085     Q_ASSERT(!hasEngine());
1086
1087     QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
1088     QV8Engine *v8engine = ep->v8engine();
1089
1090     // If compilation throws an error, a surrounding v8::TryCatch will record it.
1091     v8::Local<v8::Script> program = v8engine->qmlModeCompile(m_programSource.constData(),
1092                                                              m_programSource.length(), urlString, 1);
1093     if (program.IsEmpty())
1094         return;
1095
1096     m_program = qPersistentNew<v8::Script>(program);
1097     m_programSource.clear(); // We don't need this anymore
1098
1099     addToEngine(engine);
1100
1101     addref();
1102 }
1103
1104 v8::Persistent<v8::Object> QQmlVME::run(QQmlContextData *parentCtxt, QQmlScriptData *script)
1105 {
1106     if (script->m_loaded)
1107         return qPersistentNew<v8::Object>(script->m_value);
1108
1109     Q_ASSERT(parentCtxt && parentCtxt->engine);
1110     QQmlEnginePrivate *ep = QQmlEnginePrivate::get(parentCtxt->engine);
1111     QV8Engine *v8engine = ep->v8engine();
1112
1113     bool shared = script->pragmas & QQmlScript::Object::ScriptBlock::Shared;
1114
1115     QQmlContextData *effectiveCtxt = parentCtxt;
1116     if (shared)
1117         effectiveCtxt = 0;
1118
1119     // Create the script context if required
1120     QQmlContextData *ctxt = new QQmlContextData;
1121     ctxt->isInternal = true;
1122     ctxt->isJSContext = true;
1123     if (shared)
1124         ctxt->isPragmaLibraryContext = true;
1125     else
1126         ctxt->isPragmaLibraryContext = parentCtxt->isPragmaLibraryContext;
1127     ctxt->url = script->url;
1128     ctxt->urlString = script->urlString;
1129
1130     // For backward compatibility, if there are no imports, we need to use the
1131     // imports from the parent context.  See QTBUG-17518.
1132     if (!script->importCache->isEmpty()) {
1133         ctxt->imports = script->importCache;
1134     } else if (effectiveCtxt) {
1135         ctxt->imports = effectiveCtxt->imports;
1136         ctxt->importedScripts = effectiveCtxt->importedScripts;
1137         for (int ii = 0; ii < ctxt->importedScripts.count(); ++ii)
1138             ctxt->importedScripts[ii] = qPersistentNew<v8::Object>(ctxt->importedScripts[ii]);
1139     }
1140
1141     if (ctxt->imports) {
1142         ctxt->imports->addref();
1143     }
1144
1145     if (effectiveCtxt) {
1146         ctxt->setParent(effectiveCtxt, true);
1147     } else {
1148         ctxt->engine = parentCtxt->engine; // Fix for QTBUG-21620
1149     }
1150
1151     for (int ii = 0; ii < script->scripts.count(); ++ii) {
1152         ctxt->importedScripts << run(ctxt, script->scripts.at(ii)->scriptData());
1153     }
1154
1155     v8::HandleScope handle_scope;
1156     v8::Context::Scope scope(v8engine->context());
1157
1158     v8::TryCatch try_catch;
1159     if (!script->isInitialized())
1160         script->initialize(parentCtxt->engine);
1161
1162     v8::Local<v8::Object> qmlglobal = v8engine->qmlScope(ctxt, 0);
1163
1164     if (!script->m_program.IsEmpty()) {
1165         script->m_program->Run(qmlglobal);
1166     } else {
1167         // Compilation failed.
1168         Q_ASSERT(try_catch.HasCaught());
1169     }
1170
1171     v8::Persistent<v8::Object> rv;
1172     
1173     if (try_catch.HasCaught()) {
1174         v8::Local<v8::Message> message = try_catch.Message();
1175         if (!message.IsEmpty()) {
1176             QQmlError error;
1177             QQmlExpressionPrivate::exceptionToError(message, error);
1178             ep->warning(error);
1179         }
1180     } 
1181
1182     rv = qPersistentNew<v8::Object>(qmlglobal);
1183     if (shared) {
1184         script->m_value = qPersistentNew<v8::Object>(qmlglobal);
1185         script->m_loaded = true;
1186     }
1187
1188     return rv;
1189 }
1190
1191 #ifdef QML_THREADED_VME_INTERPRETER
1192 void **QQmlVME::instructionJumpTable()
1193 {
1194     static void **jumpTable = 0;
1195     if (!jumpTable) {
1196         QQmlVME dummy;
1197         QQmlVME::Interrupt i;
1198         dummy.run(0, i, &jumpTable);
1199     }
1200     return jumpTable;
1201 }
1202 #endif
1203
1204 QQmlContextData *QQmlVME::complete(const Interrupt &interrupt)
1205 {
1206     Q_ASSERT(engine ||
1207              (bindValues.isEmpty() &&
1208               parserStatus.isEmpty() &&
1209               componentAttached == 0 &&
1210               rootContext.isNull() &&
1211               finalizeCallbacks.isEmpty()));
1212
1213     if (!engine)
1214         return 0;
1215
1216     QQmlTrace trace("VME Complete");
1217 #ifdef QML_ENABLE_TRACE
1218     trace.addDetail("URL", rootComponent->url);
1219 #endif
1220
1221     ActiveVMERestorer restore(this, QQmlEnginePrivate::get(engine));
1222     QRecursionWatcher<QQmlVME, &QQmlVME::recursion> watcher(this);
1223
1224     {
1225     QQmlTrace trace("VME Binding Enable");
1226     trace.event("begin binding eval");
1227     while (!bindValues.isEmpty()) {
1228         QQmlAbstractBinding *b = bindValues.pop();
1229
1230         if(b) {
1231             b->m_mePtr = 0;
1232             b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor | 
1233                                 QQmlPropertyPrivate::DontRemoveBinding);
1234         }
1235
1236         if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1237             return 0;
1238     }
1239     bindValues.deallocate();
1240     }
1241
1242     {
1243     QQmlTrace trace("VME Component Complete");
1244     while (!parserStatus.isEmpty()) {
1245         QQmlParserStatus *status = parserStatus.pop();
1246 #ifdef QML_ENABLE_TRACE
1247         QQmlData *data = parserStatusData.pop();
1248 #endif
1249
1250         if (status && status->d) {
1251             status->d = 0;
1252 #ifdef QML_ENABLE_TRACE
1253             QQmlTrace trace("Component complete");
1254             trace.addDetail("URL", data->outerContext->url);
1255             trace.addDetail("Line", data->lineNumber);
1256 #endif
1257             status->componentComplete();
1258         }
1259         
1260         if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1261             return 0;
1262     }
1263     parserStatus.deallocate();
1264     }
1265
1266     {
1267     QQmlTrace trace("VME Finalize Callbacks");
1268     for (int ii = 0; ii < finalizeCallbacks.count(); ++ii) {
1269         QQmlEnginePrivate::FinalizeCallback callback = finalizeCallbacks.at(ii);
1270         QObject *obj = callback.first;
1271         if (obj) {
1272             void *args[] = { 0 };
1273             QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args);
1274         }
1275         if (watcher.hasRecursed())
1276             return 0;
1277     }
1278     finalizeCallbacks.clear();
1279     }
1280
1281     {
1282     QQmlTrace trace("VME Component.onCompleted Callbacks");
1283     while (componentAttached) {
1284         QQmlComponentAttached *a = componentAttached;
1285         a->rem();
1286         QQmlData *d = QQmlData::get(a->parent());
1287         Q_ASSERT(d);
1288         Q_ASSERT(d->context);
1289         a->add(&d->context->componentAttached);
1290         emit a->completed();
1291
1292         if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1293             return 0;
1294     }
1295     }
1296
1297     QQmlContextData *rv = rootContext;
1298
1299     reset();
1300
1301     if (rv) rv->activeVMEData = data;
1302
1303     return rv;
1304 }
1305
1306 void QQmlVME::blank(QFiniteStack<QQmlAbstractBinding *> &bs)
1307 {
1308     for (int ii = 0; ii < bs.count(); ++ii) {
1309         QQmlAbstractBinding *b = bs.at(ii);
1310         if (b) b->m_mePtr = 0;
1311     }
1312 }
1313
1314 void QQmlVME::blank(QFiniteStack<QQmlParserStatus *> &pss)
1315 {
1316     for (int ii = 0; ii < pss.count(); ++ii) {
1317         QQmlParserStatus *ps = pss.at(ii);
1318         if(ps) ps->d = 0;
1319     }
1320 }
1321
1322 QQmlVMEGuard::QQmlVMEGuard()
1323 : m_objectCount(0), m_objects(0), m_contextCount(0), m_contexts(0)
1324 {
1325 }
1326
1327 QQmlVMEGuard::~QQmlVMEGuard()
1328 {
1329     clear();
1330 }
1331
1332 void QQmlVMEGuard::guard(QQmlVME *vme)
1333 {
1334     clear();
1335     
1336     m_objectCount = vme->objects.count();
1337     m_objects = new QQmlGuard<QObject>[m_objectCount];
1338     for (int ii = 0; ii < m_objectCount; ++ii)
1339         m_objects[ii] = vme->objects[ii];
1340
1341     m_contextCount = (vme->rootContext.isNull()?0:1) + vme->states.count();
1342     m_contexts = new QQmlGuardedContextData[m_contextCount];
1343     for (int ii = 0; ii < vme->states.count(); ++ii) 
1344         m_contexts[ii] = vme->states.at(ii).context;
1345     if (!vme->rootContext.isNull())
1346         m_contexts[m_contextCount - 1] = vme->rootContext.contextData();
1347 }
1348
1349 void QQmlVMEGuard::clear()
1350 {
1351     delete [] m_objects;
1352     delete [] m_contexts;
1353
1354     m_objectCount = 0;
1355     m_objects = 0;
1356     m_contextCount = 0;
1357     m_contexts = 0;
1358 }
1359
1360 bool QQmlVMEGuard::isOK() const
1361 {
1362     for (int ii = 0; ii < m_objectCount; ++ii)
1363         if (m_objects[ii].isNull())
1364             return false;
1365
1366     for (int ii = 0; ii < m_contextCount; ++ii)
1367         if (m_contexts[ii].isNull())
1368             return false;
1369
1370     return true;
1371 }
1372
1373 QT_END_NAMESPACE