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