From 837c5d6284eeec8adb9b2caa3a0ce82b0da019a1 Mon Sep 17 00:00:00 2001 From: Filipe Azevedo Date: Fri, 5 Aug 2016 13:18:44 +0200 Subject: Fix crash when cache property can not be found For some reason if a cache property is not found this cause an application crash instead of just reporting an error. Now instead of a crash we get this kind of error visible: qrc:///the_file.qml line 64 column 30: Cannot assign object to property Change-Id: Ic420713df30603f1d164da439cba30a18af8f2bc Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmltypecompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 7e4ee344ff..82332dfc35 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -1414,7 +1414,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI continue; QQmlPropertyCache *pc = enginePrivate->rawPropertyCacheForType(pd->propType); - const QMetaObject *mo = pc->firstCppMetaObject(); + const QMetaObject *mo = pc ? pc->firstCppMetaObject() : 0; while (mo) { if (mo == &QQmlComponent::staticMetaObject) break; -- cgit v1.2.3 From 68bfc9332cd65c1eb88d1ec87164447b0db43237 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 25 Jul 2016 16:07:16 +0200 Subject: Fix crash with Component.onDestruction A call to a handler of Component.onDestruction may end up causing WeakValues such as QQmlData::jsWrapper to be set again, even though they've been set to undefined in an earlier iteration of the loop that walks through the weak references. That in turn may result in invalid object references to objects that are scheduled for destruction by the collector. So after calling all destroy handlers for QObjects, reset all of the weak values again. Task-number: QTBUG-54939 Change-Id: I00ebabb76274e296fb1bd90d8d3e21dbbb920b57 Reviewed-by: Lars Knoll --- src/qml/memory/qv4mm.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src/qml') diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 7ab6d15041..4592dd5c9b 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -428,7 +428,7 @@ void MemoryManager::sweep(bool lastSweep) Managed *m = (*it).as(); if (m->markBit()) continue; - // we need to call detroyObject on qobjectwrappers now, so that they can emit the destroyed + // we need to call destroyObject on qobjectwrappers now, so that they can emit the destroyed // signal before we start sweeping the heap if (QObjectWrapper *qobjectWrapper = (*it).as()) qobjectWrapper->destroyObject(lastSweep); @@ -436,6 +436,17 @@ void MemoryManager::sweep(bool lastSweep) (*it) = Primitive::undefinedValue(); } + // onDestruction handlers may have accessed other QObject wrappers and reset their value, so ensure + // that they are all set to undefined. + for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) { + if (!(*it).isManaged()) + continue; + Managed *m = (*it).as(); + if (m->markBit()) + continue; + (*it) = Primitive::undefinedValue(); + } + // Now it is time to free QV4::QObjectWrapper Value, we must check the Value's tag to make sure its object has been destroyed const int pendingCount = m_pendingFreedObjectWrapperValue.count(); if (pendingCount) { -- cgit v1.2.3 From 13a427475d3638de843f33145378587037841a86 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Fri, 5 Aug 2016 12:33:03 +0200 Subject: Clarify doc on modification of the global object in JS imported by QML Currently, reading the documentation for modification of the global object in JavaScript can be confusing. http://doc.qt.io/qt-5/qtqml-javascript-hostenvironment.html says: JavaScript code cannot modify the global object. In QML, the global object is constant - existing properties cannot be modified or deleted, and no new properties may be created. ... Any attempt to modify the global object - either implicitly or explicitly - will cause an exception. If uncaught, this will result in a warning being printed, that includes the file and line number of the offending code. http://doc.qt.io/qt-5/qjsengine.html#globalObject says: Returns this engine's Global Object. By default, the Global Object contains the built-in objects that are part of ECMA-262, such as Math, Date and String. Additionally, you can set properties of the Global Object to make your own extensions available to all script code. Non-local variables in script code will be created as properties of the Global Object, as well as local variables in global code. If QQmlEngine "is-a" QJSEngine, and QJSEngine can have its global object modified, it might seem reasonable to expect that imported JavaScript code should be able to modify the global object. This patch aims to be more explicit about the restrictions and give examples of how libraries should expose their APIs correctly for use by QML code. Change-Id: I11beb894a88d52038be90ffe6baa9337943810db Reviewed-by: Simon Hausmann --- src/qml/doc/src/javascript/hostenvironment.qdoc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/qml') diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc index de8b967d72..1e33f2f641 100644 --- a/src/qml/doc/src/javascript/hostenvironment.qdoc +++ b/src/qml/doc/src/javascript/hostenvironment.qdoc @@ -80,7 +80,10 @@ Note that QML makes the following modifications to native objects: QML implements the following restrictions for JavaScript code: \list -\li JavaScript code cannot modify the global object. +\li JavaScript code written in a \c .qml file cannot modify the global object. + JavaScript code in a .js file can modify the global object, + and those modifications will be visible to the .qml file when + \l {Importing a JavaScript Resource from a QML Document}{imported}. In QML, the global object is constant - existing properties cannot be modified or deleted, and no new properties may be created. -- cgit v1.2.3 From 35597f301480ffc59f598be4de2c2074543725be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Thu, 2 Jun 2016 12:08:29 +0200 Subject: Fix char conversions in QML This is a partial revert of 90b06e2773842, as it had unwanted side effects. The original intention was to make assignment from char to string possible, or more specifically, we wanted a solution where a QChar could be assigned to a QString, as a character and not a string representation of its value. While this behavior is desirable for QChar, we most likely want the opposite for the regular character types. Task-number: QTBUG-49232 Change-Id: I82d5f72b900fe984c4db1478fd52a9eb69ad2ee6 Reviewed-by: Michael Brasser Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4engine.cpp | 13 +++++++++---- src/qml/qml/qqmlproperty.cpp | 25 ++----------------------- 2 files changed, 11 insertions(+), 27 deletions(-) (limited to 'src/qml') diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 5dc3e6151f..557b678ef8 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1143,8 +1143,13 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return value.integerValue(); if (value.isNumber()) return value.asDouble(); - if (value.isString()) - return value.stringValue()->toQString(); + if (value.isString()) { + const QString &str = value.toQString(); + // QChars are stored as a strings + if (typeHint == QVariant::Char && str.size() == 1) + return str.at(0); + return str; + } if (const QV4::QQmlLocaleData *ld = value.as()) return ld->d()->locale; if (const QV4::DateObject *d = value.as()) @@ -1284,9 +1289,9 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant) case QMetaType::UShort: return QV4::Encode((int)*reinterpret_cast(ptr)); case QMetaType::Char: - return newString(QChar::fromLatin1(*reinterpret_cast(ptr)))->asReturnedValue(); + return QV4::Encode((int)*reinterpret_cast(ptr)); case QMetaType::UChar: - return newString(QChar::fromLatin1(*reinterpret_cast(ptr)))->asReturnedValue(); + return QV4::Encode((int)*reinterpret_cast(ptr)); case QMetaType::QChar: return newString(*reinterpret_cast(ptr))->asReturnedValue(); case QMetaType::QDateTime: diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 1b78ada698..1eaff6b600 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -1327,29 +1327,8 @@ bool QQmlPropertyPrivate::write(QObject *object, bool ok = false; QVariant v; - if (variantType == QVariant::String) { - const QString &str = value.toString(); - const bool targetIsChar = (propertyType == qMetaTypeId() - || propertyType == qMetaTypeId() - || propertyType == qMetaTypeId()); - // If the string contains only one character and the target is a char, try converting it. - if (targetIsChar) { - if (str.size() != 1) - return false; // We can only convert if the string contains exactly one character. - - const QChar &qChar = str.at(0); - if (propertyType == qMetaTypeId()) { - v = qChar; - ok = true; - } else if (propertyType == qMetaTypeId() || propertyType == qMetaTypeId()) { - const char c = qChar.toLatin1(); - v = c; - ok = (qChar == c); - } - } else { - v = QQmlStringConverters::variantFromString(str, propertyType, &ok); - } - } + if (variantType == QVariant::String) + v = QQmlStringConverters::variantFromString(value.toString(), propertyType, &ok); if (!ok) { v = value; -- cgit v1.2.3 From fdd8bf7dbf91b8e8ce84c990a03767c0b8ba064a Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 8 Jun 2016 10:02:29 +0200 Subject: QQmlObjectCreator: initialize _bindingTarget Coverity (CID 163180) noticed _bindingTarget wasn't initialized. Change-Id: Ia727d00a161e514c437a72084b6ef01a7ebf4abc Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlobjectcreator.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 0c13a7a017..c06e1827ac 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -114,6 +114,7 @@ void QQmlObjectCreator::init(QQmlContextData *providedParentContext) context = 0; _qobject = 0; _scopeObject = 0; + _bindingTarget = 0; _valueTypeProperty = 0; _compiledObject = 0; _compiledObjectIndex = -1; -- cgit v1.2.3 From b054a700576f61d9fbd196987f42fdea7a806db1 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 8 Jun 2016 10:03:37 +0200 Subject: QQmlObjectCreator: prefer initializer syntax over assignment Greater uniformity; also opens the door to potential const-ing, should this ever be worht considering. Change-Id: I91b44472cb7d84f85b3033f14a763beeea837459 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlobjectcreator.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index c06e1827ac..8fa1f48d18 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -68,12 +68,12 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile , resolvedTypes(compiledData->resolvedTypes) , propertyCaches(compiledData->propertyCaches) , vmeMetaObjectData(compiledData->metaObjects) + , sharedState(new QQmlObjectCreatorSharedState) + , topLevelCreator(true) , activeVMEDataForRootContext(activeVMEDataForRootContext) { init(parentContext); - sharedState = new QQmlObjectCreatorSharedState; - topLevelCreator = true; sharedState->componentAttached = 0; sharedState->allCreatedBindings.allocate(compiledData->totalBindingsCount); sharedState->allParserStatusCallbacks.allocate(compiledData->totalParserStatusCount); @@ -93,12 +93,11 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile , resolvedTypes(compiledData->resolvedTypes) , propertyCaches(compiledData->propertyCaches) , vmeMetaObjectData(compiledData->metaObjects) + , sharedState(inheritedSharedState) + , topLevelCreator(false) , activeVMEDataForRootContext(0) { init(parentContext); - - sharedState = inheritedSharedState; - topLevelCreator = false; } void QQmlObjectCreator::init(QQmlContextData *providedParentContext) -- cgit v1.2.3 From b4327851a4895b28b2c60ca51e77eca3ee0a1b4e Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 12 Aug 2016 08:02:37 +0200 Subject: Move the moth stack slot allocator into qmldevtools This way it's accessible to the QML compiler. Change-Id: I3918a796c698fc75e134b29a61eed2ec028bc851 Reviewed-by: Lars Knoll --- src/qml/compiler/qv4isel_moth.cpp | 163 +------------------------------------- src/qml/compiler/qv4ssa_p.h | 163 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 162 deletions(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index afb36c5f14..f87cbe3f1b 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -143,167 +143,6 @@ inline bool isBoolType(IR::Expr *e) return (e->type == IR::BoolType); } -/* - * stack slot allocation: - * - * foreach bb do - * foreach stmt do - * if the current statement is not a phi-node: - * purge ranges that end before the current statement - * check for life ranges to activate, and if they don't have a stackslot associated then allocate one - * renumber temps to stack - * for phi nodes: check if all temps (src+dst) are assigned stack slots and marked as allocated - * if it's a jump: - * foreach phi node in the successor: - * allocate slots for each temp (both sources and targets) if they don't have one allocated already - * insert moves before the jump - */ -class AllocateStackSlots: protected ConvertTemps -{ - IR::LifeTimeIntervals::Ptr _intervals; - QVector _unhandled; - QVector _live; - QBitArray _slotIsInUse; - IR::Function *_function; - - int defPosition(IR::Stmt *s) const - { - return usePosition(s) + 1; - } - - int usePosition(IR::Stmt *s) const - { - return _intervals->positionForStatement(s); - } - -public: - AllocateStackSlots(const IR::LifeTimeIntervals::Ptr &intervals) - : _intervals(intervals) - , _slotIsInUse(intervals->size(), false) - , _function(0) - { - _live.reserve(8); - _unhandled = _intervals->intervals(); - } - - void forFunction(IR::Function *function) - { - IR::Optimizer::showMeTheCode(function, "Before stack slot allocation"); - _function = function; - toStackSlots(function); - } - -protected: - virtual int allocateFreeSlot() - { - for (int i = 0, ei = _slotIsInUse.size(); i != ei; ++i) { - if (!_slotIsInUse[i]) { - if (_nextUnusedStackSlot <= i) { - Q_ASSERT(_nextUnusedStackSlot == i); - _nextUnusedStackSlot = i + 1; - } - _slotIsInUse[i] = true; - return i; - } - } - - Q_UNREACHABLE(); - return -1; - } - - virtual void process(IR::Stmt *s) - { -// qDebug("L%d statement %d:", _currentBasicBlock->index, s->id); - - if (IR::Phi *phi = s->asPhi()) { - visitPhi(phi); - } else { - // purge ranges no longer alive: - for (int i = 0; i < _live.size(); ) { - const IR::LifeTimeInterval *lti = _live.at(i); - if (lti->end() < usePosition(s)) { -// qDebug() << "\t - moving temp" << lti->temp().index << "to handled, freeing slot" << _stackSlotForTemp[lti->temp().index]; - _live.remove(i); - Q_ASSERT(_slotIsInUse[_stackSlotForTemp[lti->temp().index]]); - _slotIsInUse[_stackSlotForTemp[lti->temp().index]] = false; - continue; - } else { - ++i; - } - } - - // active new ranges: - while (!_unhandled.isEmpty()) { - IR::LifeTimeInterval *lti = _unhandled.last(); - if (lti->start() > defPosition(s)) - break; // we're done - Q_ASSERT(!_stackSlotForTemp.contains(lti->temp().index)); - _stackSlotForTemp[lti->temp().index] = allocateFreeSlot(); -// qDebug() << "\t - activating temp" << lti->temp().index << "on slot" << _stackSlotForTemp[lti->temp().index]; - _live.append(lti); - _unhandled.removeLast(); - } - - s->accept(this); - } - - if (IR::Jump *jump = s->asJump()) { - IR::MoveMapping moves; - foreach (IR::Stmt *succStmt, jump->target->statements()) { - if (IR::Phi *phi = succStmt->asPhi()) { - forceActivation(*phi->targetTemp); - for (int i = 0, ei = phi->d->incoming.size(); i != ei; ++i) { - IR::Expr *e = phi->d->incoming[i]; - if (IR::Temp *t = e->asTemp()) { - forceActivation(*t); - } - if (jump->target->in[i] == _currentBasicBlock) - moves.add(phi->d->incoming[i], phi->targetTemp); - } - } else { - break; - } - } - moves.order(); - QList newMoves = moves.insertMoves(_currentBasicBlock, _function, true); - foreach (IR::Move *move, newMoves) - move->accept(this); - } - } - - void forceActivation(const IR::Temp &t) - { - if (_stackSlotForTemp.contains(t.index)) - return; - - int i = _unhandled.size() - 1; - for (; i >= 0; --i) { - IR::LifeTimeInterval *lti = _unhandled[i]; - if (lti->temp() == t) { - _live.append(lti); - _unhandled.remove(i); - break; - } - } - Q_ASSERT(i >= 0); // check that we always found the entry - - _stackSlotForTemp[t.index] = allocateFreeSlot(); -// qDebug() << "\t - force activating temp" << t.index << "on slot" << _stackSlotForTemp[t.index]; - } - - virtual void visitPhi(IR::Phi *phi) - { - Q_UNUSED(phi); -#if !defined(QT_NO_DEBUG) - Q_ASSERT(_stackSlotForTemp.contains(phi->targetTemp->index)); - Q_ASSERT(_slotIsInUse[_stackSlotForTemp[phi->targetTemp->index]]); - foreach (IR::Expr *e, phi->d->incoming) { - if (IR::Temp *t = e->asTemp()) - Q_ASSERT(_stackSlotForTemp.contains(t->index)); - } -#endif // defined(QT_NO_DEBUG) - } -}; } // anonymous namespace InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) @@ -353,7 +192,7 @@ void InstructionSelection::run(int functionIndex) qEnvironmentVariableIsEmpty("QV4_NO_INTERPRETER_STACK_SLOT_ALLOCATION"); if (doStackSlotAllocation) { - AllocateStackSlots(opt.lifeTimeIntervals()).forFunction(_function); + IR::AllocateStackSlots(opt.lifeTimeIntervals()).forFunction(_function); } else { opt.convertOutOfSSA(); ConvertTemps().toStackSlots(_function); diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h index d06774e803..c5690a8581 100644 --- a/src/qml/compiler/qv4ssa_p.h +++ b/src/qml/compiler/qv4ssa_p.h @@ -46,6 +46,7 @@ // #include "qv4jsir_p.h" +#include "qv4isel_util_p.h" #include QT_BEGIN_NAMESPACE @@ -271,6 +272,168 @@ private: QList &swaps) const; }; +/* + * stack slot allocation: + * + * foreach bb do + * foreach stmt do + * if the current statement is not a phi-node: + * purge ranges that end before the current statement + * check for life ranges to activate, and if they don't have a stackslot associated then allocate one + * renumber temps to stack + * for phi nodes: check if all temps (src+dst) are assigned stack slots and marked as allocated + * if it's a jump: + * foreach phi node in the successor: + * allocate slots for each temp (both sources and targets) if they don't have one allocated already + * insert moves before the jump + */ +class AllocateStackSlots: protected ConvertTemps +{ + IR::LifeTimeIntervals::Ptr _intervals; + QVector _unhandled; + QVector _live; + QBitArray _slotIsInUse; + IR::Function *_function; + + int defPosition(IR::Stmt *s) const + { + return usePosition(s) + 1; + } + + int usePosition(IR::Stmt *s) const + { + return _intervals->positionForStatement(s); + } + +public: + AllocateStackSlots(const IR::LifeTimeIntervals::Ptr &intervals) + : _intervals(intervals) + , _slotIsInUse(intervals->size(), false) + , _function(0) + { + _live.reserve(8); + _unhandled = _intervals->intervals(); + } + + void forFunction(IR::Function *function) + { + IR::Optimizer::showMeTheCode(function, "Before stack slot allocation"); + _function = function; + toStackSlots(function); + } + +protected: + virtual int allocateFreeSlot() + { + for (int i = 0, ei = _slotIsInUse.size(); i != ei; ++i) { + if (!_slotIsInUse[i]) { + if (_nextUnusedStackSlot <= i) { + Q_ASSERT(_nextUnusedStackSlot == i); + _nextUnusedStackSlot = i + 1; + } + _slotIsInUse[i] = true; + return i; + } + } + + Q_UNREACHABLE(); + return -1; + } + + virtual void process(IR::Stmt *s) + { +// qDebug("L%d statement %d:", _currentBasicBlock->index, s->id); + + if (IR::Phi *phi = s->asPhi()) { + visitPhi(phi); + } else { + // purge ranges no longer alive: + for (int i = 0; i < _live.size(); ) { + const IR::LifeTimeInterval *lti = _live.at(i); + if (lti->end() < usePosition(s)) { +// qDebug() << "\t - moving temp" << lti->temp().index << "to handled, freeing slot" << _stackSlotForTemp[lti->temp().index]; + _live.remove(i); + Q_ASSERT(_slotIsInUse[_stackSlotForTemp[lti->temp().index]]); + _slotIsInUse[_stackSlotForTemp[lti->temp().index]] = false; + continue; + } else { + ++i; + } + } + + // active new ranges: + while (!_unhandled.isEmpty()) { + IR::LifeTimeInterval *lti = _unhandled.last(); + if (lti->start() > defPosition(s)) + break; // we're done + Q_ASSERT(!_stackSlotForTemp.contains(lti->temp().index)); + _stackSlotForTemp[lti->temp().index] = allocateFreeSlot(); +// qDebug() << "\t - activating temp" << lti->temp().index << "on slot" << _stackSlotForTemp[lti->temp().index]; + _live.append(lti); + _unhandled.removeLast(); + } + + s->accept(this); + } + + if (IR::Jump *jump = s->asJump()) { + IR::MoveMapping moves; + foreach (IR::Stmt *succStmt, jump->target->statements()) { + if (IR::Phi *phi = succStmt->asPhi()) { + forceActivation(*phi->targetTemp); + for (int i = 0, ei = phi->d->incoming.size(); i != ei; ++i) { + IR::Expr *e = phi->d->incoming[i]; + if (IR::Temp *t = e->asTemp()) { + forceActivation(*t); + } + if (jump->target->in[i] == _currentBasicBlock) + moves.add(phi->d->incoming[i], phi->targetTemp); + } + } else { + break; + } + } + moves.order(); + QList newMoves = moves.insertMoves(_currentBasicBlock, _function, true); + foreach (IR::Move *move, newMoves) + move->accept(this); + } + } + + void forceActivation(const IR::Temp &t) + { + if (_stackSlotForTemp.contains(t.index)) + return; + + int i = _unhandled.size() - 1; + for (; i >= 0; --i) { + IR::LifeTimeInterval *lti = _unhandled[i]; + if (lti->temp() == t) { + _live.append(lti); + _unhandled.remove(i); + break; + } + } + Q_ASSERT(i >= 0); // check that we always found the entry + + _stackSlotForTemp[t.index] = allocateFreeSlot(); +// qDebug() << "\t - force activating temp" << t.index << "on slot" << _stackSlotForTemp[t.index]; + } + + virtual void visitPhi(IR::Phi *phi) + { + Q_UNUSED(phi); +#if !defined(QT_NO_DEBUG) + Q_ASSERT(_stackSlotForTemp.contains(phi->targetTemp->index)); + Q_ASSERT(_slotIsInUse[_stackSlotForTemp[phi->targetTemp->index]]); + foreach (IR::Expr *e, phi->d->incoming) { + if (IR::Temp *t = e->asTemp()) + Q_ASSERT(_stackSlotForTemp.contains(t->index)); + } +#endif // defined(QT_NO_DEBUG) + } +}; + } // IR namespace } // QV4 namespace -- cgit v1.2.3