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