This enables accelerated property access also for this code path.
Change-Id: Iafb177b1fe7878e6c54cfb258f2e8d8ea32aa59e
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
qmlSignals = pool->New<PoolList<Signal> >();
bindings = pool->New<PoolList<Binding> >();
functions = pool->New<PoolList<Function> >();
+ functionsAndExpressions = pool->New<PoolList<CompiledFunctionOrExpression> >();
+ runtimeFunctionIndices = 0;
declarationsOverride = 0;
}
out << "}" << endl;
}
-QString QmlObject::sanityCheckFunctionNames(const QList<CompiledFunctionOrExpression> &allFunctions, const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation)
+QString QmlObject::sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation)
{
QSet<int> functionNames;
for (Function *f = functions->first; f; f = f->next) {
- QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(allFunctions.at(f->index).node);
+ QQmlJS::AST::FunctionDeclaration *function = f->functionDeclaration;
Q_ASSERT(function);
*errorLocation = function->identifierToken;
- QString name = function->name.toString();
if (functionNames.contains(f->nameIndex))
return tr("Duplicate method name");
functionNames.insert(f->nameIndex);
return tr("Duplicate method name");
}
+ const QString name = function->name.toString();
if (name.at(0).isUpper())
return tr("Method names cannot begin with an upper case letter");
if (illegalNames.contains(name))
qSwap(_imports, output->imports);
qSwap(_pragmas, output->pragmas);
qSwap(_objects, output->objects);
- qSwap(_functions, output->functions);
qSwap(_typeReferences, output->typeReferences);
this->pool = output->jsParserEngine.pool();
this->jsGenerator = &output->jsGenerator;
qSwap(_imports, output->imports);
qSwap(_pragmas, output->pragmas);
qSwap(_objects, output->objects);
- qSwap(_functions, output->functions);
qSwap(_typeReferences, output->typeReferences);
return errors.isEmpty();
}
return false;
QQmlJS::AST::SourceLocation loc;
- QString error = obj->sanityCheckFunctionNames(_functions, illegalNames, &loc);
+ QString error = obj->sanityCheckFunctionNames(illegalNames, &loc);
if (!error.isEmpty()) {
recordError(loc, error);
return false;
bool QQmlCodeGenerator::visit(QQmlJS::AST::UiSourceElement *node)
{
if (QQmlJS::AST::FunctionDeclaration *funDecl = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration *>(node->sourceElement)) {
- _functions << funDecl;
+ CompiledFunctionOrExpression *foe = New<CompiledFunctionOrExpression>();
+ foe->node = funDecl;
+ foe->nameIndex = registerString(funDecl->name.toString());
+ foe->disableAcceleratedLookups = false;
+ const int index = _object->functionsAndExpressions->append(foe);
+
Function *f = New<Function>();
f->functionDeclaration = funDecl;
QQmlJS::AST::SourceLocation loc = funDecl->identifierToken;
f->location.line = loc.startLine;
f->location.column = loc.startColumn;
- f->index = _functions.size() - 1;
+ f->index = index;
f->nameIndex = registerString(funDecl->name.toString());
_object->appendFunction(f);
} else {
// Do binding instead
if (binding->type == QV4::CompiledData::Binding::Type_Invalid) {
binding->type = QV4::CompiledData::Binding::Type_Script;
- _functions << statement;
- binding->value.compiledScriptIndex = _functions.size() - 1;
+
+ CompiledFunctionOrExpression *expr = New<CompiledFunctionOrExpression>();
+ expr->node = statement;
+ expr->nameIndex = 0;
+ expr->disableAcceleratedLookups = false;
+ const int index = bindingsTarget()->functionsAndExpressions->append(expr);
+ binding->value.compiledScriptIndex = index;
binding->stringIndex = registerString(asStringRef(statement).toString());
}
}
return true;
}
-QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output, const QVector<int> &runtimeFunctionIndices)
+QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output)
{
jsUnitGenerator = &output.jsGenerator;
int unitSize = 0;
quint32 *functionsTable = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToFunctions);
for (const Function *f = o->firstFunction(); f; f = f->next)
- *functionsTable++ = runtimeFunctionIndices[f->index];
+ *functionsTable++ = o->runtimeFunctionIndices->at(f->index);
char *propertiesPtr = objectPtr + objectToWrite->offsetToProperties;
for (const QmlProperty *p = o->firstProperty(); p; p = p->next) {
}
char *bindingPtr = objectPtr + objectToWrite->offsetToBindings;
- bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isValueBindingNoAlias);
- bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isSignalHandler);
- bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isAttachedProperty);
- bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isGroupProperty);
- bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isValueBindingToAlias);
+ bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isValueBindingNoAlias);
+ bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isSignalHandler);
+ bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isAttachedProperty);
+ bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isGroupProperty);
+ bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isValueBindingToAlias);
Q_ASSERT((bindingPtr - objectToWrite->offsetToBindings - objectPtr) / sizeof(QV4::CompiledData::Binding) == unsigned(o->bindingCount()));
quint32 *signalOffsetTable = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToSignals);
return qmlUnit;
}
-char *QmlUnitGenerator::writeBindings(char *bindingPtr, QmlObject *o, const QVector<int> &runtimeFunctionIndices, BindingFilter filter) const
+char *QmlUnitGenerator::writeBindings(char *bindingPtr, QmlObject *o, BindingFilter filter) const
{
for (const Binding *b = o->firstBinding(); b; b = b->next) {
if (!(b->*(filter))())
QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr);
*bindingToWrite = *b;
if (b->type == QV4::CompiledData::Binding::Type_Script)
- bindingToWrite->value.compiledScriptIndex = runtimeFunctionIndices[b->value.compiledScriptIndex];
+ bindingToWrite->value.compiledScriptIndex = o->runtimeFunctionIndices->at(b->value.compiledScriptIndex);
bindingPtr += sizeof(QV4::CompiledData::Binding);
}
return bindingPtr;
}
JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, IR::Module *jsModule, QQmlJS::Engine *jsEngine,
- QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports)
+ QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, const QStringList &stringPool)
: QQmlJS::Codegen(/*strict mode*/false)
, sourceCode(sourceCode)
, jsEngine(jsEngine)
, qmlRoot(qmlRoot)
, imports(imports)
+ , stringPool(stringPool)
, _disableAcceleratedLookups(false)
, _contextObject(0)
, _scopeObject(0)
QString name;
if (function)
name = function->name.toString();
- else if (!qmlFunction.name.isEmpty())
- name = qmlFunction.name;
+ else if (qmlFunction.nameIndex != 0)
+ name = stringPool.value(qmlFunction.nameIndex);
else
name = QStringLiteral("%qml-expression-entry");
if (paramList)
paramList = paramList->finish();
- QQmlJS::AST::Statement *statement = static_cast<QQmlJS::AST::Statement*>(parsedQML->functions[binding->value.compiledScriptIndex].node);
+ CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex);
+ QQmlJS::AST::Statement *statement = static_cast<QQmlJS::AST::Statement*>(foe->node);
QQmlJS::AST::SourceElement *sourceElement = new (pool) QQmlJS::AST::StatementSourceElement(statement);
QQmlJS::AST::SourceElements *elements = new (pool) QQmlJS::AST::SourceElements(sourceElement);
elements = elements->finish();
QQmlJS::AST::FunctionDeclaration *functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(jsEngine.newStringRef(propertyName), paramList, body);
- parsedQML->functions[binding->value.compiledScriptIndex] = functionDeclaration;
+ foe->node = functionDeclaration;
binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerExpression;
}
return true;
++count;
}
}
+
+ T *slowAt(int index) const
+ {
+ T *result = first;
+ while (index > 0 && result) {
+ result = result->next;
+ --index;
+ }
+ return result;
+ }
+};
+
+template <typename T>
+class FixedPoolArray
+{
+ T *data;
+ int count;
+public:
+
+ void init(QQmlJS::MemoryPool *pool, const QVector<T> &vector)
+ {
+ count = vector.count();
+ data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
+
+ if (QTypeInfo<T>::isComplex) {
+ for (int i = 0; i < count; ++i)
+ new (data + i) T(vector.at(i));
+ } else {
+ memcpy(data, static_cast<const void*>(vector.constData()), count * sizeof(T));
+ }
+ }
+
+ const T &at(int index) const {
+ Q_ASSERT(index >= 0 && index < count);
+ return data[index];
+ }
+
+ int indexOf(const T &value) const {
+ for (int i = 0; i < count; ++i)
+ if (data[i] == value)
+ return i;
+ return -1;
+ }
};
struct QmlObject;
struct Binding : public QV4::CompiledData::Binding
{
- // Binding's compiledScriptIndex is index in parsedQML::functions
+ // Binding's compiledScriptIndex is index in object's functionsAndExpressions
Binding *next;
};
QQmlJS::AST::FunctionDeclaration *functionDeclaration;
QV4::CompiledData::Location location;
int nameIndex;
- int index; // index in parsedQML::functions
+ quint32 index; // index in parsedQML::functions
Function *next;
};
{
CompiledFunctionOrExpression()
: node(0)
+ , nameIndex(0)
, disableAcceleratedLookups(false)
+ , next(0)
{}
CompiledFunctionOrExpression(QQmlJS::AST::Node *n)
: node(n)
+ , nameIndex(0)
, disableAcceleratedLookups(false)
+ , next(0)
{}
QQmlJS::AST::Node *node; // FunctionDeclaration, Statement or Expression
- QString name;
+ quint32 nameIndex;
bool disableAcceleratedLookups;
+ CompiledFunctionOrExpression *next;
};
struct QmlObject
void dump(DebugStream &out);
- QString sanityCheckFunctionNames(const QList<CompiledFunctionOrExpression> &allFunctions, const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation);
+ QString sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation);
QString appendSignal(Signal *signal);
QString appendProperty(QmlProperty *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
QString appendBinding(Binding *b, bool isListBinding);
Binding *findBinding(quint32 nameIndex) const;
+ PoolList<CompiledFunctionOrExpression> *functionsAndExpressions;
+ FixedPoolArray<int> *runtimeFunctionIndices;
+
private:
PoolList<QmlProperty> *properties;
PoolList<Signal> *qmlSignals;
QQmlJS::AST::UiProgram *program;
int indexOfRootObject;
QList<QmlObject*> objects;
- QList<CompiledFunctionOrExpression> functions;
QV4::Compiler::JSUnitGenerator jsGenerator;
QV4::CompiledData::TypeReferenceMap typeReferences;
QList<QV4::CompiledData::Import*> _imports;
QList<Pragma*> _pragmas;
QList<QmlObject*> _objects;
- QList<CompiledFunctionOrExpression> _functions;
QV4::CompiledData::TypeReferenceMap _typeReferences;
{
}
- QV4::CompiledData::QmlUnit *generate(ParsedQML &output, const QVector<int> &runtimeFunctionIndices);
+ QV4::CompiledData::QmlUnit *generate(ParsedQML &output);
private:
typedef bool (Binding::*BindingFilter)() const;
- char *writeBindings(char *bindingPtr, QmlObject *o, const QVector<int> &runtimeFunctionIndices, BindingFilter filter) const;
+ char *writeBindings(char *bindingPtr, QmlObject *o, BindingFilter filter) const;
int getStringId(const QString &str) const;
struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen
{
JSCodeGen(const QString &fileName, const QString &sourceCode, IR::Module *jsModule,
- QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports);
+ QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports,
+ const QStringList &stringPool);
struct IdMapping
{
QQmlJS::Engine *jsEngine; // needed for memory pool
QQmlJS::AST::UiProgram *qmlRoot;
QQmlTypeNameCache *imports;
+ const QStringList &stringPool;
bool _disableAcceleratedLookups;
ObjectIdMapping _idObjects;
}
// Compile JS binding expressions and signal handlers
-
- JSCodeGen jsCodeGen(typeData->finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, compiledData->importCache);
- const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(parsedQML->functions);
- QList<QQmlError> jsErrors = jsCodeGen.errors();
- if (!jsErrors.isEmpty()) {
- errors << jsErrors;
- return false;
+ {
+ QtQml::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, compiledData->importCache, parsedQML->jsGenerator.strings);
+ QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
+ if (!jsCodeGen.generateCodeForComponents())
+ return false;
}
QV4::ExecutionEngine *v4 = engine->v4engine();
// Generate QML compiled type data structures
QmlUnitGenerator qmlGenerator;
- QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(*parsedQML, runtimeFunctionIndices);
+ QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(*parsedQML);
if (jsUnit) {
Q_ASSERT(!jsUnit->data);
}
// Sanity check property bindings
- QQmlPropertyValidator validator(this, runtimeFunctionIndices);
+ QQmlPropertyValidator validator(this);
if (!validator.validate())
return false;
return parsedQML->jsParserEngine.pool();
}
-const QList<CompiledFunctionOrExpression> &QQmlTypeCompiler::functions() const
-{
- return parsedQML->functions;
-}
-
void QQmlTypeCompiler::setCustomParserBindings(const QVector<int> &bindings)
{
compiledData->customParserBindings = bindings;
}
-QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler, const QVector<int> &runtimeFunctionIndices)
+QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler)
, enginePrivate(typeCompiler->enginePrivate())
, qmlUnit(typeCompiler->qmlUnit())
, propertyCaches(typeCompiler->propertyCaches())
, objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
, customParserData(typeCompiler->customParserData())
- , runtimeFunctionIndices(runtimeFunctionIndices)
{
}
return *compiler->imports();
}
-QQmlJS::AST::Node *QQmlPropertyValidator::astForBinding(int scriptIndex) const
+QQmlJS::AST::Node *QQmlPropertyValidator::astForBinding(int objectIndex, int scriptIndex) const
{
+ const QtQml::QmlObject *obj = compiler->qmlObjects()->at(objectIndex);
// ####
- int reverseIndex = runtimeFunctionIndices.indexOf(scriptIndex);
+ int reverseIndex = obj->runtimeFunctionIndices->indexOf(scriptIndex);
if (reverseIndex == -1)
return 0;
- return compiler->functions().value(reverseIndex).node;
+ QtQml::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(reverseIndex);
+ return foe ? foe->node : 0;
}
QQmlBinding::Identifier QQmlPropertyValidator::bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *)
{
- int id = customParserBindings.count();
+ const int id = customParserBindings.count();
customParserBindings.append(binding->value.compiledScriptIndex);
return id;
}
return true;
}
+QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QtQml::JSCodeGen *v4CodeGen)
+ : QQmlCompilePass(typeCompiler)
+ , objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
+ , resolvedTypes(*typeCompiler->resolvedTypes())
+ , qmlObjects(*typeCompiler->qmlObjects())
+ , propertyCaches(typeCompiler->propertyCaches())
+ , v4CodeGen(v4CodeGen)
+{
+}
+
+bool QQmlJSCodeGenerator::generateCodeForComponents()
+{
+ const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent = *compiler->objectIndexToIdPerComponent();
+ for (QHash<int, QHash<int, int> >::ConstIterator component = objectIndexToIdPerComponent.constBegin(), end = objectIndexToIdPerComponent.constEnd();
+ component != end; ++component) {
+ if (!compileComponent(component.key(), component.value()))
+ return false;
+ }
+
+ return compileComponent(compiler->rootObjectIndex(), *compiler->objectIndexToIdForRoot());
+}
+
+bool QQmlJSCodeGenerator::compileComponent(int contextObject, const QHash<int, int> &objectIndexToId)
+{
+ if (isComponent(contextObject)) {
+ const QtQml::QmlObject *component = qmlObjects.at(contextObject);
+ Q_ASSERT(component->bindingCount() == 1);
+ const QV4::CompiledData::Binding *componentBinding = component->firstBinding();
+ Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
+ contextObject = componentBinding->value.objectIndex;
+ }
+
+ JSCodeGen::ObjectIdMapping idMapping;
+ if (!objectIndexToId.isEmpty()) {
+ idMapping.reserve(objectIndexToId.count());
+
+ for (QHash<int, int>::ConstIterator idIt = objectIndexToId.constBegin(), end = objectIndexToId.constEnd();
+ idIt != end; ++idIt) {
+
+ const int objectIndex = idIt.key();
+ JSCodeGen::IdMapping m;
+ m.name = stringAt(qmlObjects.at(objectIndex)->idIndex);
+ m.idIndex = idIt.value();
+ m.type = propertyCaches.at(objectIndex);
+ idMapping << m;
+ }
+
+ v4CodeGen->beginContextScope(idMapping, propertyCaches.at(contextObject));
+ }
+
+ if (!compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject))
+ return false;
+
+ return true;
+}
+
+bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
+{
+ if (isComponent(objectIndex))
+ return true;
+
+ QtQml::QmlObject *object = qmlObjects.at(objectIndex);
+ if (object->functionsAndExpressions->count > 0) {
+ bool haveCustomParser = false;
+ QQmlCompiledData::TypeReference *objectType = resolvedTypes.value(object->inheritedTypeNameIndex);
+ if (objectType && objectType->type)
+ haveCustomParser = objectType->type->customParser() != 0;
+
+ QQmlPropertyCache *scopeObject = propertyCaches.at(scopeObjectIndex);
+ v4CodeGen->beginObjectScope(scopeObject);
+
+ QList<QtQml::CompiledFunctionOrExpression> functionsToCompile;
+ for (QtQml::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next) {
+ if (haveCustomParser)
+ foe->disableAcceleratedLookups = true;
+ functionsToCompile << *foe;
+ }
+ const QVector<int> runtimeFunctionIndices = v4CodeGen->generateJSCodeForFunctionsAndBindings(functionsToCompile);
+ QList<QQmlError> jsErrors = v4CodeGen->errors();
+ if (!jsErrors.isEmpty()) {
+ foreach (const QQmlError &e, jsErrors)
+ compiler->recordError(e);
+ return false;
+ }
+
+ QQmlJS::MemoryPool *pool = compiler->memoryPool();
+ object->runtimeFunctionIndices = pool->New<QtQml::FixedPoolArray<int> >();
+ object->runtimeFunctionIndices->init(pool, runtimeFunctionIndices);
+ }
+
+ for (const QtQml::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
+ if (binding->type < QV4::CompiledData::Binding::Type_Object)
+ continue;
+
+ int target = binding->value.objectIndex;
+ int scope = binding->type == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex;
+
+ if (!compileJavaScriptCodeInObjectsRecursively(binding->value.objectIndex, scope))
+ return false;
+ }
+
+ return true;
+}
+
QT_END_NAMESPACE
QHash<int, QHash<int, int> > *objectIndexToIdPerComponent();
QHash<int, QByteArray> *customParserData();
QQmlJS::MemoryPool *memoryPool();
- const QList<CompiledFunctionOrExpression> &functions() const;
void setCustomParserBindings(const QVector<int> &bindings);
private:
{
Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
public:
- QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler, const QVector<int> &runtimeFunctionIndices);
+ QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler);
bool validate();
// Re-implemented for QQmlCustomParser
virtual const QQmlImports &imports() const;
- virtual QQmlJS::AST::Node *astForBinding(int scriptIndex) const;
+ virtual QQmlJS::AST::Node *astForBinding(int objectIndex, int scriptIndex) const;
virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *parser);
private:
const QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
QHash<int, QByteArray> *customParserData;
QVector<int> customParserBindings;
- const QVector<int> &runtimeFunctionIndices;
+};
+
+// ### merge with QtQml::JSCodeGen and operate directly on object->functionsAndExpressions once old compiler is gone.
+class QQmlJSCodeGenerator : public QQmlCompilePass
+{
+public:
+ QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QtQml::JSCodeGen *v4CodeGen);
+
+ bool generateCodeForComponents();
+
+private:
+ bool compileComponent(int componentRoot, const QHash<int, int> &objectIndexToId);
+ bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
+
+ bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
+
+ const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent;
+ const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
+ const QList<QtQml::QmlObject*> &qmlObjects;
+ const QVector<QQmlPropertyCache *> &propertyCaches;
+ QtQml::JSCodeGen * const v4CodeGen;
};
QT_END_NAMESPACE
const QQmlScript::Parser &parser = unit->parser();
QQmlJS::Engine *jsEngine = parser.jsEngine();
QQmlJS::MemoryPool *pool = jsEngine->pool();
+ QStringList stringPool;
+ stringPool.append(QString());
for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
ComponentCompileState::PerObjectCompileData *cd = &compileState->jsCompileData[b->bindingContext.object];
QtQml::CompiledFunctionOrExpression f;
f.node = node;
- f.name = binding.property->name().toString().prepend(QStringLiteral("expression for "));
+ QString name = binding.property->name().toString().prepend(QStringLiteral("expression for "));
+ stringPool.append(name);
+ f.nameIndex = stringPool.count() - 1;
f.disableAcceleratedLookups = binding.disableLookupAcceleration;
cd->functionsToCompile.append(f);
binding.compiledIndex = cd->functionsToCompile.count() - 1;
const QString &sourceCode = jsEngine->code();
AST::UiProgram *qmlRoot = parser.qmlRoot();
- JSCodeGen jsCodeGen(unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, output->importCache);
+ JSCodeGen jsCodeGen(unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, output->importCache, stringPool);
JSCodeGen::ObjectIdMapping idMapping;
if (compileState->ids.count() > 0) {
return compiler->bindingIdentifier(binding, this);
}
-QQmlJS::AST::Node *QQmlCustomParser::astForBinding(int scriptIndex) const
+QQmlJS::AST::Node *QQmlCustomParser::astForBinding(int objectIndex, int scriptIndex) const
{
- return compiler->astForBinding(scriptIndex);
+ return compiler->astForBinding(objectIndex, scriptIndex);
}
struct StaticQtMetaObject : public QObject
virtual QQmlBinding::Identifier bindingIdentifier(const QQmlScript::Variant&, const QString&, QQmlCustomParser *) { return QQmlBinding::Invalid; }
virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *, QQmlCustomParser *) { return QQmlBinding::Invalid; }
- virtual QQmlJS::AST::Node *astForBinding(int) const { return 0; }
+ virtual QQmlJS::AST::Node *astForBinding(int, int) const { return 0; }
};
class Q_QML_PRIVATE_EXPORT QQmlCustomParser
QQmlBinding::Identifier bindingIdentifier(const QQmlScript::Variant&, const QString&);
QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding);
- QQmlJS::AST::Node *astForBinding(int scriptIndex) const;
+ QQmlJS::AST::Node *astForBinding(int objectIndex, int scriptIndex) const;
private:
QList<QQmlError> exceptions;
bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, QList<QQmlListModelParser::ListInstruction> &instr, QByteArray &data)
{
+ const quint32 targetObjectIndex = binding->value.objectIndex;
if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- const QV4::CompiledData::Object *target = qmlUnit->objectAt(binding->value.objectIndex);
+ const QV4::CompiledData::Object *target = qmlUnit->objectAt(targetObjectIndex);
QString objName = qmlUnit->header.stringAt(target->inheritedTypeNameIndex);
if (objName != listElementTypeName) {
const QMetaObject *mo = resolveType(objName);
int v = evaluateEnum(script, &ok);
if (!ok) {
using namespace QQmlJS;
- AST::Node *node = astForBinding(binding->value.compiledScriptIndex);
+ AST::Node *node = astForBinding(targetObjectIndex, binding->value.compiledScriptIndex);
if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement*>(node))
node = stmt->expression;
AST::StringLiteral *literal = 0;