aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/compiler')
-rw-r--r--src/qml/compiler/compiler.pri1
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp103
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h17
-rw-r--r--src/qml/compiler/qv4codegen.cpp319
-rw-r--r--src/qml/compiler/qv4codegen_p.h43
-rw-r--r--src/qml/compiler/qv4compileddata.cpp283
-rw-r--r--src/qml/compiler/qv4compileddata_p.h266
-rw-r--r--src/qml/compiler/qv4compiler.cpp24
-rw-r--r--src/qml/compiler/qv4compiler_p.h2
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp28
10 files changed, 468 insertions, 618 deletions
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index c3dd5890d6..c6ae8c6b69 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -20,7 +20,6 @@ HEADERS += \
SOURCES += \
$$PWD/qv4bytecodegenerator.cpp \
- $$PWD/qv4compileddata.cpp \
$$PWD/qv4compiler.cpp \
$$PWD/qv4compilercontext.cpp \
$$PWD/qv4compilerscanfunctions.cpp \
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 3e5798ba8b..1891f31f13 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -374,13 +374,12 @@ bool IRBuilder::generateFromQml(const QString &code, const QString &url, Documen
if (!parseResult || !diagnosticMessages.isEmpty()) {
// Extract errors from the parser
for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
-
if (m.isWarning()) {
- qWarning("%s:%d : %s", qPrintable(url), m.loc.startLine, qPrintable(m.message));
+ qWarning("%s:%d : %s", qPrintable(url), m.line, qPrintable(m.message));
continue;
}
- recordError(m.loc, m.message);
+ errors << m;
}
return false;
}
@@ -650,11 +649,9 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node)
return false;
}
- if (node->versionToken.isValid()) {
- int major, minor;
- extractVersion(textRefAt(node->versionToken), &major, &minor);
- import->majorVersion = major;
- import->minorVersion = minor;
+ if (node->version) {
+ import->majorVersion = node->version->majorVersion;
+ import->minorVersion = node->version->minorVersion;
} else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Library import requires a version"));
return false;
@@ -770,33 +767,33 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
static const struct TypeNameToType {
const char *name;
size_t nameLength;
- QV4::CompiledData::Property::Type type;
+ QV4::CompiledData::BuiltinType type;
} propTypeNameToTypes[] = {
- { "int", strlen("int"), QV4::CompiledData::Property::Int },
- { "bool", strlen("bool"), QV4::CompiledData::Property::Bool },
- { "double", strlen("double"), QV4::CompiledData::Property::Real },
- { "real", strlen("real"), QV4::CompiledData::Property::Real },
- { "string", strlen("string"), QV4::CompiledData::Property::String },
- { "url", strlen("url"), QV4::CompiledData::Property::Url },
- { "color", strlen("color"), QV4::CompiledData::Property::Color },
+ { "int", strlen("int"), QV4::CompiledData::BuiltinType::Int },
+ { "bool", strlen("bool"), QV4::CompiledData::BuiltinType::Bool },
+ { "double", strlen("double"), QV4::CompiledData::BuiltinType::Real },
+ { "real", strlen("real"), QV4::CompiledData::BuiltinType::Real },
+ { "string", strlen("string"), QV4::CompiledData::BuiltinType::String },
+ { "url", strlen("url"), QV4::CompiledData::BuiltinType::Url },
+ { "color", strlen("color"), QV4::CompiledData::BuiltinType::Color },
// Internally QTime, QDate and QDateTime are all supported.
// To be more consistent with JavaScript we expose only
// QDateTime as it matches closely with the Date JS type.
// We also call it "date" to match.
// { "time", strlen("time"), Property::Time },
// { "date", strlen("date"), Property::Date },
- { "date", strlen("date"), QV4::CompiledData::Property::DateTime },
- { "rect", strlen("rect"), QV4::CompiledData::Property::Rect },
- { "point", strlen("point"), QV4::CompiledData::Property::Point },
- { "size", strlen("size"), QV4::CompiledData::Property::Size },
- { "font", strlen("font"), QV4::CompiledData::Property::Font },
- { "vector2d", strlen("vector2d"), QV4::CompiledData::Property::Vector2D },
- { "vector3d", strlen("vector3d"), QV4::CompiledData::Property::Vector3D },
- { "vector4d", strlen("vector4d"), QV4::CompiledData::Property::Vector4D },
- { "quaternion", strlen("quaternion"), QV4::CompiledData::Property::Quaternion },
- { "matrix4x4", strlen("matrix4x4"), QV4::CompiledData::Property::Matrix4x4 },
- { "variant", strlen("variant"), QV4::CompiledData::Property::Variant },
- { "var", strlen("var"), QV4::CompiledData::Property::Var }
+ { "date", strlen("date"), QV4::CompiledData::BuiltinType::DateTime },
+ { "rect", strlen("rect"), QV4::CompiledData::BuiltinType::Rect },
+ { "point", strlen("point"), QV4::CompiledData::BuiltinType::Point },
+ { "size", strlen("size"), QV4::CompiledData::BuiltinType::Size },
+ { "font", strlen("font"), QV4::CompiledData::BuiltinType::Font },
+ { "vector2d", strlen("vector2d"), QV4::CompiledData::BuiltinType::Vector2D },
+ { "vector3d", strlen("vector3d"), QV4::CompiledData::BuiltinType::Vector3D },
+ { "vector4d", strlen("vector4d"), QV4::CompiledData::BuiltinType::Vector4D },
+ { "quaternion", strlen("quaternion"), QV4::CompiledData::BuiltinType::Quaternion },
+ { "matrix4x4", strlen("matrix4x4"), QV4::CompiledData::BuiltinType::Matrix4x4 },
+ { "variant", strlen("variant"), QV4::CompiledData::BuiltinType::Variant },
+ { "var", strlen("var"), QV4::CompiledData::BuiltinType::Var }
};
static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
sizeof(propTypeNameToTypes[0]);
@@ -836,8 +833,9 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
if (memberType.at(0).isUpper()) {
// Must be a QML object type.
// Lazily determine type during compilation.
- param->type = QV4::CompiledData::Property::Custom;
- param->customTypeNameIndex = registerString(memberType);
+ param->indexIsBuiltinType = false;
+ param->typeNameIndexOrBuiltinType = registerString(memberType);
+ Q_ASSERT(quint32(jsGenerator->getStringId(memberType)) < (1u << 31));
} else {
QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: ");
errStr.append(memberType);
@@ -846,13 +844,12 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
}
} else {
// the parameter is a known basic type
- param->type = type->type;
- param->customTypeNameIndex = emptyStringIndex;
+ param->indexIsBuiltinType = true;
+ param->typeNameIndexOrBuiltinType = static_cast<quint32>(type->type);
+ Q_ASSERT(quint32(type->type) < (1u << 31));
}
param->nameIndex = registerString(p->name.toString());
- param->location.line = p->identifierToken.startLine;
- param->location.column = p->identifierToken.startColumn;
signal->parameters->append(param);
p = p->next;
}
@@ -875,13 +872,15 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
} else {
const QStringRef &name = node->name;
+ Property *property = New<Property>();
+ property->isReadOnly = node->isReadonlyMember;
+
bool typeFound = false;
- QV4::CompiledData::Property::Type type = QV4::CompiledData::Property::Var;
for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
const TypeNameToType *t = propTypeNameToTypes + ii;
if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
- type = t->type;
+ property->setBuiltinType(t->type);
typeFound = true;
}
}
@@ -889,11 +888,10 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
if (!typeFound && memberType.at(0).isUpper()) {
const QStringRef &typeModifier = node->typeModifier;
- if (typeModifier.isEmpty()) {
- type = QV4::CompiledData::Property::Custom;
- } else if (typeModifier == QLatin1String("list")) {
- type = QV4::CompiledData::Property::CustomList;
- } else {
+ property->setCustomType(registerString(memberType));
+ if (typeModifier == QLatin1String("list")) {
+ property->isList = true;
+ } else if (!typeModifier.isEmpty()) {
recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
return false;
}
@@ -908,16 +906,6 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
return false;
}
- Property *property = New<Property>();
- property->flags = 0;
- if (node->isReadonlyMember)
- property->flags |= QV4::CompiledData::Property::IsReadOnly;
- property->type = type;
- if (type >= QV4::CompiledData::Property::Custom)
- property->customTypeNameIndex = registerString(memberType);
- else
- property->customTypeNameIndex = emptyStringIndex;
-
const QString propName = name.toString();
property->nameIndex = registerString(propName);
@@ -1040,7 +1028,7 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
binding->valueLocation.line = loc.startLine;
binding->valueLocation.column = loc.startColumn;
binding->type = QV4::CompiledData::Binding::Type_Invalid;
- if (_propertyDeclaration && (_propertyDeclaration->flags & QV4::CompiledData::Property::IsReadOnly))
+ if (_propertyDeclaration && _propertyDeclaration->isReadOnly)
binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
@@ -1271,7 +1259,7 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo
binding->flags = 0;
- if (_propertyDeclaration && (_propertyDeclaration->flags & QV4::CompiledData::Property::IsReadOnly))
+ if (_propertyDeclaration && _propertyDeclaration->isReadOnly)
binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
// No type name on the initializer means it must be a group property
@@ -1502,7 +1490,8 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O
void IRBuilder::recordError(const QQmlJS::AST::SourceLocation &location, const QString &description)
{
QQmlJS::DiagnosticMessage error;
- error.loc = location;
+ error.line = location.startLine;
+ error.column = location.startColumn;
error.message = description;
errors << error;
}
@@ -1534,7 +1523,7 @@ bool IRBuilder::isStatementNodeScript(QQmlJS::AST::Statement *statement)
bool IRBuilder::isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement)
{
- if (property->type != QV4::CompiledData::Property::Custom)
+ if (property->isBuiltinType || property->isList)
return false;
QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
if (!exprStmt)
@@ -1749,7 +1738,7 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
jsUnit->unitSize += totalSize;
memcpy(jsUnit->qmlUnit(), qmlUnit, totalSize);
free(qmlUnit);
- jsUnit->generateChecksum();
+ QV4::Compiler::JSUnitGenerator::generateUnitChecksum(jsUnit);
qmlUnit = jsUnit->qmlUnit();
}
@@ -1838,7 +1827,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
}
scan.leaveEnvironment();
- if (hasError)
+ if (hasError())
return QVector<int>();
_context = nullptr;
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index b49eaee420..64298466e0 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -526,16 +526,15 @@ private:
} // namespace QmlIR
-struct QQmlCompileError
+inline QQmlJS::DiagnosticMessage qQmlCompileError(const QV4::CompiledData::Location &location,
+ const QString &description)
{
- QQmlCompileError() {}
- QQmlCompileError(const QV4::CompiledData::Location &location, const QString &description)
- : location(location), description(description) {}
- QV4::CompiledData::Location location;
- QString description;
-
- bool isSet() const { return !description.isEmpty(); }
-};
+ QQmlJS::DiagnosticMessage error;
+ error.line = location.line;
+ error.column = location.column;
+ error.message = description;
+ return error;
+}
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index b7e3e20fd0..453963c1dd 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -43,6 +43,7 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QStringList>
#include <QtCore/QStack>
+#include <QtCore/qurl.h>
#include <QScopeGuard>
#include <private/qqmljsast_p.h>
#include <private/qqmljslexer_p.h>
@@ -53,7 +54,8 @@
#include <private/qv4compilercontrolflow_p.h>
#include <private/qv4bytecodegenerator_p.h>
#include <private/qv4compilerscanfunctions_p.h>
-#include <qqmlerror.h>
+#include <private/qv4stringtoarrayindex_p.h>
+#include <private/qqmljsdiagnosticmessage_p.h>
#include <cmath>
#include <iostream>
@@ -96,7 +98,6 @@ Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict)
, jsUnitGenerator(jsUnitGenerator)
, _strictMode(strict)
, _fileNameIsUrl(false)
- , hasError(false)
{
jsUnitGenerator->codeGeneratorName = QStringLiteral("moth");
pushExpr();
@@ -189,7 +190,7 @@ void Codegen::generateFromProgram(const QString &fileName,
ScanFunctions scan(this, sourceCode, contextType);
scan(node);
- if (hasError)
+ if (hasError())
return;
defineFunction(QStringLiteral("%entry"), node, nullptr, node->statements);
@@ -213,7 +214,7 @@ void Codegen::generateFromModule(const QString &fileName,
ScanFunctions scan(this, sourceCode, ContextType::ESModule);
scan(node);
- if (hasError)
+ if (hasError())
return;
{
@@ -263,7 +264,7 @@ Context *Codegen::enterBlock(Node *node)
Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
{
- if (hasError)
+ if (hasError())
return exprResult();
if (expr.isConstant()) {
@@ -414,7 +415,7 @@ void Codegen::statement(ExpressionNode *ast)
qSwap(_volatileMemoryLocations, vLocs);
Reference result = popResult();
- if (hasError)
+ if (hasError())
return;
if (result.loadTriggersSideEffect())
result.loadInAccumulator(); // triggers side effects
@@ -424,7 +425,7 @@ void Codegen::statement(ExpressionNode *ast)
void Codegen::condition(ExpressionNode *ast, const BytecodeGenerator::Label *iftrue,
const BytecodeGenerator::Label *iffalse, bool trueBlockFollowsCondition)
{
- if (hasError)
+ if (hasError())
return;
if (!ast)
@@ -434,7 +435,7 @@ void Codegen::condition(ExpressionNode *ast, const BytecodeGenerator::Label *ift
accept(ast);
Result r = popExpr();
- if (hasError)
+ if (hasError())
return;
if (r.format() == ex) {
@@ -588,7 +589,7 @@ Codegen::Reference Codegen::targetForPatternElement(AST::PatternElement *p)
if (!p->bindingTarget || p->destructuringPattern())
return Codegen::Reference::fromStackSlot(this);
Reference lhs = expression(p->bindingTarget);
- if (hasError)
+ if (hasError())
return lhs;
if (!lhs.isLValue()) {
throwReferenceError(p->bindingTarget->firstSourceLocation(), QStringLiteral("Binding target is not a reference."));
@@ -606,14 +607,14 @@ void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, con
Reference varToStore = targetForPatternElement(e);
if (isDefinition)
varToStore.isReferenceToConst = false;
- if (hasError)
+ if (hasError())
return;
if (e->initializer) {
if (!baseRef.isValid()) {
// assignment
Reference expr = expression(e->initializer);
- if (hasError)
+ if (hasError())
return;
expr.loadInAccumulator();
varToStore.storeConsumeAccumulator();
@@ -621,7 +622,7 @@ void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, con
baseRef.loadInAccumulator();
BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
Reference expr = expression(e->initializer);
- if (hasError) {
+ if (hasError()) {
jump.link();
return;
}
@@ -632,7 +633,7 @@ void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, con
baseRef.loadInAccumulator();
BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
Reference expr = expression(e->initializer);
- if (hasError) {
+ if (hasError()) {
jump.link();
return;
}
@@ -669,7 +670,7 @@ Codegen::Reference Codegen::referenceForPropertyName(const Codegen::Reference &o
Reference property;
if (cname) {
Reference computedName = expression(cname->expression);
- if (hasError)
+ if (hasError())
return Reference();
computedName = computedName.storeOnStack();
property = Reference::fromSubscript(object, computedName).asLValue();
@@ -692,10 +693,10 @@ void Codegen::destructurePropertyList(const Codegen::Reference &object, PatternP
PatternProperty *p = it->property;
RegisterScope scope(this);
Reference property = referenceForPropertyName(object, p->name);
- if (hasError)
+ if (hasError())
return;
initializeAndDestructureBindingElement(p, property, isDefinition);
- if (hasError)
+ if (hasError())
return;
}
}
@@ -751,7 +752,7 @@ void Codegen::destructureElementList(const Codegen::Reference &array, PatternEle
next.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(next);
initializeAndDestructureBindingElement(e, iteratorValue, isDefinition);
- if (hasError)
+ if (hasError())
return;
}
}
@@ -1015,7 +1016,7 @@ bool Codegen::visit(ClassExpression *ast)
if (ast->heritage) {
bytecodeGenerator->setLocation(ast->heritage->firstSourceLocation());
Reference r = expression(ast->heritage);
- if (hasError)
+ if (hasError())
return false;
r.storeOnStack(heritage.stackSlot());
} else {
@@ -1034,7 +1035,7 @@ bool Codegen::visit(ClassExpression *ast)
RegisterScope scope(this);
bytecodeGenerator->setLocation(cname->firstSourceLocation());
Reference computedName = expression(cname->expression);
- if (hasError)
+ if (hasError())
return false;
computedName.storeOnStack(member->isStatic ? currentStaticName++ : currentNonStaticName++);
}
@@ -1067,19 +1068,20 @@ bool Codegen::visit(ClassDeclaration *ast)
bool Codegen::visit(Expression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
statement(ast->left);
blockTailCalls.unblock();
+ clearExprResultName(); // The name only holds for the left part
accept(ast->right);
return false;
}
bool Codegen::visit(ArrayPattern *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -1101,7 +1103,7 @@ bool Codegen::visit(ArrayPattern *ast)
} else {
RegisterScope scope(this);
Reference r = expression(arg);
- if (hasError)
+ if (hasError())
return;
(void) r.storeOnStack(temp);
}
@@ -1119,7 +1121,7 @@ bool Codegen::visit(ArrayPattern *ast)
continue;
push(e->initializer);
- if (hasError)
+ if (hasError())
return false;
}
@@ -1180,7 +1182,7 @@ bool Codegen::visit(ArrayPattern *ast)
{
RegisterScope innerScope(this);
Reference expr = expression(it->element->initializer);
- if (hasError)
+ if (hasError())
return false;
expr.loadInAccumulator();
@@ -1221,7 +1223,7 @@ bool Codegen::visit(ArrayPattern *ast)
} else {
RegisterScope innerScope(this);
Reference expr = expression(it->element->initializer);
- if (hasError)
+ if (hasError())
return false;
expr.loadInAccumulator();
@@ -1239,12 +1241,12 @@ bool Codegen::visit(ArrayPattern *ast)
bool Codegen::visit(ArrayMemberExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
Reference base = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
if (base.isSuper()) {
Reference index = expression(ast->expression).storeOnStack();
@@ -1252,7 +1254,7 @@ bool Codegen::visit(ArrayMemberExpression *ast)
return false;
}
base = base.storeOnStack();
- if (hasError)
+ if (hasError())
return false;
if (AST::StringLiteral *str = AST::cast<AST::StringLiteral *>(ast->expression)) {
QString s = str->value.toString();
@@ -1266,7 +1268,7 @@ bool Codegen::visit(ArrayMemberExpression *ast)
return false;
}
Reference index = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
setExprResult(Reference::fromSubscript(base, index));
return false;
@@ -1293,7 +1295,7 @@ static QSOperator::Op baseOp(int op)
bool Codegen::visit(BinaryExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -1311,7 +1313,7 @@ bool Codegen::visit(BinaryExpression *ast)
auto endif = bytecodeGenerator->newLabel();
Reference left = expression(ast->left);
- if (hasError)
+ if (hasError())
return false;
left.loadInAccumulator();
@@ -1321,7 +1323,7 @@ bool Codegen::visit(BinaryExpression *ast)
blockTailCalls.unblock();
Reference right = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
right.loadInAccumulator();
@@ -1342,7 +1344,7 @@ bool Codegen::visit(BinaryExpression *ast)
auto endif = bytecodeGenerator->newLabel();
Reference left = expression(ast->left);
- if (hasError)
+ if (hasError())
return false;
left.loadInAccumulator();
@@ -1352,7 +1354,7 @@ bool Codegen::visit(BinaryExpression *ast)
blockTailCalls.unblock();
Reference right = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
right.loadInAccumulator();
@@ -1365,7 +1367,7 @@ bool Codegen::visit(BinaryExpression *ast)
if (AST::Pattern *p = ast->left->patternCast()) {
RegisterScope scope(this);
Reference right = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
right = right.storeOnStack();
destructurePattern(p, right);
@@ -1376,7 +1378,7 @@ bool Codegen::visit(BinaryExpression *ast)
return false;
}
Reference left = expression(ast->left);
- if (hasError)
+ if (hasError())
return false;
if (!left.isLValue()) {
@@ -1388,7 +1390,7 @@ bool Codegen::visit(BinaryExpression *ast)
return false;
blockTailCalls.unblock();
Reference r = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
r.loadInAccumulator();
if (exprAccept(nx))
@@ -1399,7 +1401,7 @@ bool Codegen::visit(BinaryExpression *ast)
}
Reference left = expression(ast->left);
- if (hasError)
+ if (hasError())
return false;
switch (ast->op) {
@@ -1433,7 +1435,7 @@ bool Codegen::visit(BinaryExpression *ast)
Reference tempLeft = left.storeOnStack();
Reference right = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
binopHelper(baseOp(ast->op), tempLeft, right).loadInAccumulator();
@@ -1447,7 +1449,7 @@ bool Codegen::visit(BinaryExpression *ast)
case QSOperator::BitXor:
if (left.isConstant()) {
Reference right = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
setExprResult(binopHelper(static_cast<QSOperator::Op>(ast->op), right, left));
break;
@@ -1480,7 +1482,7 @@ bool Codegen::visit(BinaryExpression *ast)
left = left.storeOnStack(); // force any loads of the lhs, so the rhs won't clobber it
right = expression(ast->right);
}
- if (hasError)
+ if (hasError())
return false;
setExprResult(binopHelper(static_cast<QSOperator::Op>(ast->op), left, right));
@@ -1864,7 +1866,7 @@ Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Refe
bool Codegen::visit(CallExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -1872,7 +1874,7 @@ bool Codegen::visit(CallExpression *ast)
Reference base = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
switch (base.type) {
case Reference::Member:
@@ -1895,7 +1897,7 @@ bool Codegen::visit(CallExpression *ast)
int functionObject = bytecodeGenerator->newRegister();
auto calldata = pushArgs(ast->arguments);
- if (hasError)
+ if (hasError())
return false;
blockTailCalls.unblock();
@@ -2043,7 +2045,7 @@ Codegen::Arguments Codegen::pushArgs(ArgumentList *args)
}
RegisterScope scope(this);
Reference e = expression(it->expression);
- if (hasError)
+ if (hasError())
break;
if (!argc && !it->next && !hasSpread) {
// avoid copy for functions taking a single argument
@@ -2072,7 +2074,7 @@ Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args)
for (TemplateLiteral *it = args; it && it->expression; it = it->next) {
RegisterScope scope(this);
Reference e = expression(it->expression);
- if (hasError)
+ if (hasError())
break;
(void) e.storeOnStack(calldata + argc);
++argc;
@@ -2083,7 +2085,7 @@ Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args)
bool Codegen::visit(ConditionalExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -2097,14 +2099,14 @@ bool Codegen::visit(ConditionalExpression *ast)
iftrue.link();
Reference ok = expression(ast->ok);
- if (hasError)
+ if (hasError())
return false;
ok.loadInAccumulator();
BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
iffalse.link();
Reference ko = expression(ast->ko);
- if (hasError) {
+ if (hasError()) {
jump_endif.link(); // dummy link, to prevent assert in Jump destructor from triggering
return false;
}
@@ -2118,13 +2120,13 @@ bool Codegen::visit(ConditionalExpression *ast)
bool Codegen::visit(DeleteExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
switch (expr.type) {
@@ -2189,7 +2191,7 @@ bool Codegen::visit(DeleteExpression *ast)
bool Codegen::visit(FalseLiteral *)
{
- if (hasError)
+ if (hasError())
return false;
setExprResult(Reference::fromConst(this, QV4::Encode(false)));
@@ -2198,7 +2200,7 @@ bool Codegen::visit(FalseLiteral *)
bool Codegen::visit(SuperLiteral *)
{
- if (hasError)
+ if (hasError())
return false;
setExprResult(Reference::fromSuper(this));
@@ -2207,7 +2209,7 @@ bool Codegen::visit(SuperLiteral *)
bool Codegen::visit(FieldMemberExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2230,7 +2232,7 @@ bool Codegen::visit(FieldMemberExpression *ast)
}
Reference base = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
if (base.isSuper()) {
Instruction::LoadRuntimeString load;
@@ -2246,7 +2248,7 @@ bool Codegen::visit(FieldMemberExpression *ast)
bool Codegen::visit(TaggedTemplate *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -2255,7 +2257,7 @@ bool Codegen::visit(TaggedTemplate *ast)
bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast)
{
- if (hasError)
+ if (hasError())
return false;
int functionObject = -1, thisObject = -1;
@@ -2279,7 +2281,7 @@ bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast)
int templateObjectTemp = Reference::fromAccumulator(this).storeOnStack().stackSlot();
Q_UNUSED(templateObjectTemp);
auto calldata = pushTemplateArgs(ast->templateLiteral);
- if (hasError)
+ if (hasError())
return false;
++calldata.argc;
Q_ASSERT(calldata.argv == templateObjectTemp + 1);
@@ -2308,7 +2310,7 @@ void Codegen::createTemplateObject(TemplateLiteral *t)
bool Codegen::visit(FunctionExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2316,7 +2318,7 @@ bool Codegen::visit(FunctionExpression *ast)
RegisterScope scope(this);
int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body);
- if (hasError)
+ if (hasError())
return false;
loadClosure(function);
setExprResult(Reference::fromAccumulator(this));
@@ -2372,7 +2374,7 @@ void Codegen::loadClosure(int closureId)
bool Codegen::visit(IdentifierExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
setExprResult(referenceForName(ast->name.toString(), false, ast->firstSourceLocation()));
@@ -2381,7 +2383,7 @@ bool Codegen::visit(IdentifierExpression *ast)
bool Codegen::visit(NestedExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
accept(ast->expression);
@@ -2400,7 +2402,7 @@ void Codegen::handleConstruct(const Reference &base, ArgumentList *arguments)
}
auto calldata = pushArgs(arguments);
- if (hasError)
+ if (hasError())
return;
if (base.isSuper())
@@ -2430,14 +2432,14 @@ void Codegen::handleConstruct(const Reference &base, ArgumentList *arguments)
bool Codegen::visit(NewExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference base = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
if (base.isSuper()) {
throwSyntaxError(ast->expression->firstSourceLocation(), QStringLiteral("Cannot use new with super."));
@@ -2450,14 +2452,14 @@ bool Codegen::visit(NewExpression *ast)
bool Codegen::visit(NewMemberExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference base = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
if (base.isSuper()) {
throwSyntaxError(ast->base->firstSourceLocation(), QStringLiteral("Cannot use new with super."));
@@ -2470,7 +2472,7 @@ bool Codegen::visit(NewMemberExpression *ast)
bool Codegen::visit(NotExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2480,7 +2482,7 @@ bool Codegen::visit(NotExpression *ast)
bool Codegen::visit(NullExpression *)
{
- if (hasError)
+ if (hasError())
return false;
if (exprAccept(cx))
@@ -2493,7 +2495,7 @@ bool Codegen::visit(NullExpression *)
bool Codegen::visit(NumericLiteral *ast)
{
- if (hasError)
+ if (hasError())
return false;
setExprResult(Reference::fromConst(this, QV4::Encode::smallestNumber(ast->value)));
@@ -2502,7 +2504,7 @@ bool Codegen::visit(NumericLiteral *ast)
bool Codegen::visit(ObjectPattern *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2537,8 +2539,8 @@ bool Codegen::visit(ObjectPattern *ast)
{
RegisterScope innerScope(this);
- Reference value = expression(p->initializer);
- if (hasError)
+ Reference value = expression(p->initializer, name);
+ if (hasError())
return false;
value.loadInAccumulator();
}
@@ -2565,7 +2567,7 @@ bool Codegen::visit(ObjectPattern *ast)
if (cname) {
RegisterScope innerScope(this);
Reference name = expression(cname->expression);
- if (hasError)
+ if (hasError())
return false;
name.loadInAccumulator();
} else {
@@ -2590,12 +2592,12 @@ bool Codegen::visit(ObjectPattern *ast)
FunctionExpression *f = p->initializer->asFunctionDefinition();
Q_ASSERT(f);
int function = defineFunction(f->name.toString(), f, f->formals, f->body);
- if (hasError)
+ if (hasError())
return false;
Reference::fromConst(this, Encode(function)).loadInAccumulator();
} else {
Reference value = expression(p->initializer);
- if (hasError)
+ if (hasError())
return false;
value.loadInAccumulator();
}
@@ -2614,11 +2616,11 @@ bool Codegen::visit(ObjectPattern *ast)
bool Codegen::visit(PostDecrementExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
Reference expr = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
if (!expr.isLValue()) {
throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation"));
@@ -2634,11 +2636,11 @@ bool Codegen::visit(PostDecrementExpression *ast)
bool Codegen::visit(PostIncrementExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
Reference expr = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
if (!expr.isLValue()) {
throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation"));
@@ -2652,11 +2654,11 @@ bool Codegen::visit(PostIncrementExpression *ast)
}
bool Codegen::visit(PreDecrementExpression *ast)
-{ if (hasError)
+{ if (hasError())
return false;
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
if (!expr.isLValue()) {
throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference."));
@@ -2671,11 +2673,11 @@ bool Codegen::visit(PreDecrementExpression *ast)
bool Codegen::visit(PreIncrementExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
if (!expr.isLValue()) {
throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference."));
@@ -2690,7 +2692,7 @@ bool Codegen::visit(PreIncrementExpression *ast)
bool Codegen::visit(RegExpLiteral *ast)
{
- if (hasError)
+ if (hasError())
return false;
auto r = Reference::fromStackSlot(this);
@@ -2706,7 +2708,7 @@ bool Codegen::visit(RegExpLiteral *ast)
bool Codegen::visit(StringLiteral *ast)
{
- if (hasError)
+ if (hasError())
return false;
auto r = Reference::fromAccumulator(this);
@@ -2721,7 +2723,7 @@ bool Codegen::visit(StringLiteral *ast)
bool Codegen::visit(TemplateLiteral *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2738,7 +2740,7 @@ bool Codegen::visit(TemplateLiteral *ast)
bytecodeGenerator->addInstruction(store);
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
if (ast->next) {
@@ -2768,7 +2770,7 @@ bool Codegen::visit(TemplateLiteral *ast)
bool Codegen::visit(ThisExpression *)
{
- if (hasError)
+ if (hasError())
return false;
if (_context->isArrowFunction) {
@@ -2783,7 +2785,7 @@ bool Codegen::visit(ThisExpression *)
bool Codegen::visit(TildeExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2793,7 +2795,7 @@ bool Codegen::visit(TildeExpression *ast)
bool Codegen::visit(TrueLiteral *)
{
- if (hasError)
+ if (hasError())
return false;
setExprResult(Reference::fromConst(this, QV4::Encode(true)));
@@ -2802,14 +2804,14 @@ bool Codegen::visit(TrueLiteral *)
bool Codegen::visit(TypeOfExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
if (expr.type == Reference::Name) {
@@ -2829,7 +2831,7 @@ bool Codegen::visit(TypeOfExpression *ast)
bool Codegen::visit(UnaryMinusExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2839,7 +2841,7 @@ bool Codegen::visit(UnaryMinusExpression *ast)
bool Codegen::visit(UnaryPlusExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2849,7 +2851,7 @@ bool Codegen::visit(UnaryPlusExpression *ast)
bool Codegen::visit(VoidExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -2862,7 +2864,7 @@ bool Codegen::visit(VoidExpression *ast)
bool Codegen::visit(FunctionDeclaration * ast)
{
- if (hasError)
+ if (hasError())
return false;
// no need to block tail calls: the function body isn't visited here.
@@ -2884,7 +2886,7 @@ bool Codegen::visit(YieldExpression *ast)
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = ast->expression ? expression(ast->expression) : Reference::fromConst(this, Encode::undefined());
- if (hasError)
+ if (hasError())
return false;
Reference acc = Reference::fromAccumulator(this);
@@ -2979,7 +2981,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
// already defined
return leaveContext();
- _context->name = name;
+ _context->name = name.isEmpty() ? currentExpr().result().name : name;
_module->functions.append(_context);
_context->functionIndex = _module->functions.count() - 1;
@@ -3062,7 +3064,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
} else {
if (e->bindingTarget || e->initializer) {
initializeAndDestructureBindingElement(e, arg);
- if (hasError)
+ if (hasError())
break;
}
}
@@ -3078,7 +3080,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
statementList(body);
- if (!hasError) {
+ if (!hasError()) {
bytecodeGenerator->setLocation(ast->lastSourceLocation());
_context->emitBlockFooter(this);
@@ -3125,7 +3127,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
bool Codegen::visit(Block *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3137,7 +3139,7 @@ bool Codegen::visit(Block *ast)
bool Codegen::visit(BreakStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
// no need to block tail calls here: children aren't visited
@@ -3162,7 +3164,7 @@ bool Codegen::visit(BreakStatement *ast)
bool Codegen::visit(ContinueStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
// no need to block tail calls here: children aren't visited
@@ -3195,7 +3197,7 @@ bool Codegen::visit(DebuggerStatement *)
bool Codegen::visit(DoWhileStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3240,7 +3242,7 @@ bool Codegen::visit(EmptyStatement *)
bool Codegen::visit(ExpressionStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3248,7 +3250,7 @@ bool Codegen::visit(ExpressionStatement *ast)
if (requiresReturnValue) {
Reference e = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
(void) e.storeOnStack(_returnAddress);
} else {
@@ -3259,7 +3261,7 @@ bool Codegen::visit(ExpressionStatement *ast)
bool Codegen::visit(ForEachStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3275,7 +3277,7 @@ bool Codegen::visit(ForEachStatement *ast)
RegisterScope innerScope(this);
ControlFlowBlock controlFlow(this, ast);
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
expr.loadInAccumulator();
@@ -3318,7 +3320,7 @@ bool Codegen::visit(ForEachStatement *ast)
destructurePattern(p, lhsValue);
} else {
Reference lhs = expression(e);
- if (hasError)
+ if (hasError())
goto error;
if (!lhs.isLValue()) {
throwReferenceError(e->firstSourceLocation(), QStringLiteral("Invalid left-hand side expression for 'in' expression"));
@@ -3330,7 +3332,7 @@ bool Codegen::visit(ForEachStatement *ast)
}
} else if (PatternElement *p = AST::cast<PatternElement *>(ast->lhs)) {
initializeAndDestructureBindingElement(p, lhsValue, /*isDefinition =*/ true);
- if (hasError)
+ if (hasError())
goto error;
} else {
Q_UNREACHABLE();
@@ -3356,7 +3358,7 @@ bool Codegen::visit(ForEachStatement *ast)
bool Codegen::visit(ForStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3400,7 +3402,7 @@ bool Codegen::visit(ForStatement *ast)
bool Codegen::visit(IfStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3432,7 +3434,7 @@ bool Codegen::visit(IfStatement *ast)
bool Codegen::visit(LabelledStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3480,7 +3482,7 @@ void Codegen::emitReturn(const Reference &expr)
bool Codegen::visit(ReturnStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
if (_functionContext->contextType != ContextType::Function && _functionContext->contextType != ContextType::Binding) {
@@ -3490,7 +3492,7 @@ bool Codegen::visit(ReturnStatement *ast)
Reference expr;
if (ast->expression) {
expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
} else {
expr = Reference::fromConst(this, Encode::undefined());
@@ -3503,7 +3505,7 @@ bool Codegen::visit(ReturnStatement *ast)
bool Codegen::visit(SwitchStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
if (requiresReturnValue)
@@ -3516,7 +3518,7 @@ bool Codegen::visit(SwitchStatement *ast)
BytecodeGenerator::Label switchEnd = bytecodeGenerator->newLabel();
Reference lhs = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
lhs = lhs.storeOnStack();
@@ -3535,7 +3537,7 @@ bool Codegen::visit(SwitchStatement *ast)
for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
CaseClause *clause = it->clause;
Reference rhs = expression(clause->expression);
- if (hasError)
+ if (hasError())
return false;
rhs.loadInAccumulator();
bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
@@ -3544,7 +3546,7 @@ bool Codegen::visit(SwitchStatement *ast)
for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
CaseClause *clause = it->clause;
Reference rhs = expression(clause->expression);
- if (hasError)
+ if (hasError())
return false;
rhs.loadInAccumulator();
bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
@@ -3590,14 +3592,14 @@ bool Codegen::visit(SwitchStatement *ast)
bool Codegen::visit(ThrowStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
expr.loadInAccumulator();
@@ -3634,7 +3636,7 @@ void Codegen::handleTryFinally(TryStatement *ast)
bool Codegen::visit(TryStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3650,7 +3652,7 @@ bool Codegen::visit(TryStatement *ast)
bool Codegen::visit(VariableStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
variableDeclarationList(ast->declarations);
@@ -3659,7 +3661,7 @@ bool Codegen::visit(VariableStatement *ast)
bool Codegen::visit(WhileStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
if (AST::cast<FalseLiteral *>(ast->expression))
@@ -3691,14 +3693,14 @@ bool Codegen::visit(WhileStatement *ast)
bool Codegen::visit(WithStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference src = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
src = src.storeOnStack(); // trigger load before we setup the exception handler, so exceptions here go to the right place
src.loadInAccumulator();
@@ -3768,33 +3770,30 @@ bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(const Reference &r,
return isArgOrEval;
}
-void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
+void Codegen::throwError(ErrorType errorType, const SourceLocation &loc, const QString &detail)
{
- if (hasError)
+ if (hasError())
return;
- hasError = true;
- QQmlJS::DiagnosticMessage error;
- error.message = detail;
- error.loc = loc;
- _errors << error;
+ _errorType = errorType;
+ _error.message = detail;
+ _error.line = loc.startLine;
+ _error.column = loc.startColumn;
}
-void Codegen::throwReferenceError(const SourceLocation &loc, const QString &detail)
+void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
{
- if (hasError)
- return;
+ throwError(SyntaxError, loc, detail);
+}
- hasError = true;
- QQmlJS::DiagnosticMessage error;
- error.message = detail;
- error.loc = loc;
- _errors << error;
+void Codegen::throwReferenceError(const SourceLocation &loc, const QString &detail)
+{
+ throwError(ReferenceError, loc, detail);
}
-QList<QQmlJS::DiagnosticMessage> Codegen::errors() const
+QQmlJS::DiagnosticMessage Codegen::error() const
{
- return _errors;
+ return _error;
}
QV4::CompiledData::CompilationUnit Codegen::generateCompilationUnit(
@@ -3837,12 +3836,11 @@ CompiledData::CompilationUnit Codegen::compileModule(
JSUnitGenerator jsGenerator(&compilerModule);
Codegen cg(&jsGenerator, /*strictMode*/true);
cg.generateFromModule(url, url, sourceCode, moduleNode, &compilerModule);
- auto errors = cg.errors();
- if (diagnostics)
- *diagnostics << errors;
-
- if (!errors.isEmpty())
+ if (cg.hasError()) {
+ if (diagnostics)
+ *diagnostics << cg.error();
return CompiledData::CompilationUnit();
+ }
return cg.generateCompilationUnit();
}
@@ -3960,28 +3958,9 @@ Codegen::VolatileMemoryLocations Codegen::scanVolatileMemoryLocations(AST::Node
return scanner.scan(ast);
}
-
-QList<QQmlError> Codegen::qmlErrors() const
+QUrl Codegen::url() const
{
- QList<QQmlError> qmlErrors;
-
- // Short circuit to avoid costly (de)heap allocation of QUrl if there are no errors.
- if (_errors.size() == 0)
- return qmlErrors;
-
- qmlErrors.reserve(_errors.size());
-
- QUrl url(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
- for (const QQmlJS::DiagnosticMessage &msg: qAsConst(_errors)) {
- QQmlError e;
- e.setUrl(url);
- e.setLine(msg.loc.startLine);
- e.setColumn(msg.loc.startColumn);
- e.setDescription(msg.message);
- qmlErrors << e;
- }
-
- return qmlErrors;
+ return QUrl(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
}
bool Codegen::RValue::operator==(const RValue &other) const
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 6d5f8c0951..51b821aafe 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -54,14 +54,13 @@
#include <private/qqmljsastvisitor_p.h>
#include <private/qqmljsengine_p.h>
#include <private/qqmljsast_p.h>
+#include <private/qqmljsdiagnosticmessage_p.h>
#include <private/qv4compiler_p.h>
#include <private/qv4compilercontext_p.h>
#include <private/qv4util_p.h>
#include <private/qv4bytecodegenerator_p.h>
#include <private/qv4calldata_p.h>
-#include <QtQml/qqmlerror.h>
-
QT_BEGIN_NAMESPACE
using namespace QQmlJS;
@@ -199,8 +198,9 @@ public:
codegen = cg;
}
- Reference() :
+ Reference(const QString &name = QString()) :
constant(0),
+ name(name),
isArgOrEval(false),
isReadonly(false),
isReferenceToConst(false),
@@ -418,6 +418,11 @@ protected:
bool _trueBlockFollowsCondition = false;
public:
+ explicit Result(const QString &name)
+ : _result(name)
+ , _requested(ex)
+ {}
+
explicit Result(const Reference &lrvalue)
: _result(lrvalue)
, _requested(ex)
@@ -476,6 +481,10 @@ protected:
void setResult(Reference &&result) {
_result = std::move(result);
}
+
+ void clearResultName() {
+ _result.name.clear();
+ }
};
void enterContext(AST::Node *node);
@@ -523,19 +532,19 @@ protected:
const BytecodeGenerator::Label *iffalse,
bool trueBlockFollowsCondition);
- inline Reference expression(AST::ExpressionNode *ast)
+ inline Reference expression(AST::ExpressionNode *ast, const QString &name = QString())
{
- if (!ast || hasError)
+ if (!ast || hasError())
return Reference();
- pushExpr();
+ pushExpr(name);
ast->accept(this);
return popResult();
}
inline void accept(AST::Node *node)
{
- if (!hasError && node)
+ if (!hasError() && node)
node->accept(this);
}
@@ -662,8 +671,16 @@ protected:
}
public:
- QList<DiagnosticMessage> errors() const;
- QList<QQmlError> qmlErrors() const;
+ enum ErrorType {
+ NoError,
+ SyntaxError,
+ ReferenceError
+ };
+
+ ErrorType errorType() const { return _errorType; }
+ bool hasError() const { return _errorType != NoError; }
+ DiagnosticMessage error() const;
+ QUrl url() const;
Reference binopHelper(QSOperator::Op oper, Reference &left, Reference &right);
Reference jumpBinop(QSOperator::Op oper, Reference &left, Reference &right);
@@ -716,6 +733,7 @@ protected:
inline void setExprResult(const Reference &result) { m_expressions.back().setResult(result); }
inline void setExprResult(Reference &&result) { m_expressions.back().setResult(std::move(result)); }
inline Reference exprResult() const { return m_expressions.back().result(); }
+ inline void clearExprResultName() { m_expressions.back().clearResultName(); }
inline bool exprAccept(Format f) { return m_expressions.back().accept(f); }
@@ -723,7 +741,7 @@ protected:
inline void pushExpr(Result &&expr) { m_expressions.push_back(std::move(expr)); }
inline void pushExpr(const Result &expr) { m_expressions.push_back(expr); }
- inline void pushExpr() { m_expressions.emplace_back(); }
+ inline void pushExpr(const QString &name = QString()) { m_expressions.emplace_back(name); }
inline Result popExpr()
{
@@ -760,8 +778,8 @@ protected:
ControlFlow *controlFlow = nullptr;
bool _fileNameIsUrl;
- bool hasError;
- QList<QQmlJS::DiagnosticMessage> _errors;
+ ErrorType _errorType = NoError;
+ QQmlJS::DiagnosticMessage _error;
class TailCallBlocker
{
@@ -790,6 +808,7 @@ protected:
private:
VolatileMemoryLocations scanVolatileMemoryLocations(AST::Node *ast);
void handleConstruct(const Reference &base, AST::ArgumentList *args);
+ void throwError(ErrorType errorType, const AST::SourceLocation &loc, const QString &detail);
};
}
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
deleted file mode 100644
index 813868b0ae..0000000000
--- a/src/qml/compiler/qv4compileddata.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4compileddata_p.h"
-#include <private/qv4staticvalue_p.h>
-#include <private/qqmlirbuilder_p.h>
-#include <QCoreApplication>
-#include <QCryptographicHash>
-#include <QSaveFile>
-#include <QScopeGuard>
-#include <QFileInfo>
-
-// generated by qmake:
-#include "qml_compile_hash_p.h"
-
-#include <algorithm>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-
-namespace CompiledData {
-
-#if defined(QML_COMPILE_HASH)
-# ifdef Q_OS_LINUX
-// Place on a separate section on Linux so it's easier to check from outside
-// what the hash version is.
-__attribute__((section(".qml_compile_hash")))
-# endif
-const char qml_compile_hash[48 + 1] = QML_COMPILE_HASH;
-static_assert(sizeof(Unit::libraryVersionHash) >= QML_COMPILE_HASH_LENGTH + 1, "Compile hash length exceeds reserved size in data structure. Please adjust and bump the format version");
-#else
-# error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files"
-#endif
-
-
-CompilationUnit::CompilationUnit(const Unit *unitData, const QString &fileName, const QString &finalUrlString)
-{
- setUnitData(unitData, nullptr, fileName, finalUrlString);
-}
-
-CompilationUnit::~CompilationUnit()
-{
- if (data) {
- if (data->qmlUnit() != qmlData)
- free(const_cast<QmlUnit *>(qmlData));
- qmlData = nullptr;
-
- if (!(data->flags & QV4::CompiledData::Unit::StaticData))
- free(const_cast<Unit *>(data));
- }
- data = nullptr;
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- delete [] constants;
- constants = nullptr;
-#endif
-
- delete [] imports;
- imports = nullptr;
-}
-
-bool CompilationUnit::saveToDisk(const QString &outputFileName, QString *errorString) const
-{
- errorString->clear();
-
-#if QT_CONFIG(temporaryfile)
- // Foo.qml -> Foo.qmlc
- QSaveFile cacheFile(outputFileName);
- if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
- *errorString = cacheFile.errorString();
- return false;
- }
-
- SaveableUnitPointer saveable(this);
- qint64 headerWritten = cacheFile.write(saveable.data<char>(), saveable.size());
- if (headerWritten != saveable.size()) {
- *errorString = cacheFile.errorString();
- return false;
- }
-
- if (!cacheFile.commit()) {
- *errorString = cacheFile.errorString();
- return false;
- }
-
- return true;
-#else
- Q_UNUSED(outputFileName)
- *errorString = QStringLiteral("features.temporaryfile is disabled.");
- return false;
-#endif // QT_CONFIG(temporaryfile)
-}
-
-void CompilationUnit::setUnitData(const Unit *unitData, const QmlUnit *qmlUnit,
- const QString &fileName, const QString &finalUrlString)
-{
- data = unitData;
- qmlData = nullptr;
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- delete [] constants;
-#endif
- constants = nullptr;
- m_fileName.clear();
- m_finalUrlString.clear();
- if (!data)
- return;
-
- qmlData = qmlUnit ? qmlUnit : data->qmlUnit();
-
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- StaticValue *bigEndianConstants = new StaticValue[data->constantTableSize];
- const quint64_le *littleEndianConstants = data->constants();
- for (uint i = 0; i < data->constantTableSize; ++i)
- bigEndianConstants[i] = StaticValue::fromReturnedValue(littleEndianConstants[i]);
- constants = bigEndianConstants;
-#else
- constants = reinterpret_cast<const StaticValue*>(data->constants());
-#endif
-
- m_fileName = !fileName.isEmpty() ? fileName : stringAt(data->sourceFileIndex);
- m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(data->finalUrlIndex);
-}
-
-//reverse of Lexer::singleEscape()
-QString Binding::escapedString(const QString &string)
-{
- QString tmp = QLatin1String("\"");
- for (int i = 0; i < string.length(); ++i) {
- const QChar &c = string.at(i);
- switch (c.unicode()) {
- case 0x08:
- tmp += QLatin1String("\\b");
- break;
- case 0x09:
- tmp += QLatin1String("\\t");
- break;
- case 0x0A:
- tmp += QLatin1String("\\n");
- break;
- case 0x0B:
- tmp += QLatin1String("\\v");
- break;
- case 0x0C:
- tmp += QLatin1String("\\f");
- break;
- case 0x0D:
- tmp += QLatin1String("\\r");
- break;
- case 0x22:
- tmp += QLatin1String("\\\"");
- break;
- case 0x27:
- tmp += QLatin1String("\\\'");
- break;
- case 0x5C:
- tmp += QLatin1String("\\\\");
- break;
- default:
- tmp += c;
- break;
- }
- }
- tmp += QLatin1Char('\"');
- return tmp;
-}
-
-void CompilationUnit::unlink()
-{
- free(runtimeStrings);
- runtimeStrings = nullptr;
- delete [] runtimeRegularExpressions;
- runtimeRegularExpressions = nullptr;
- free(runtimeClasses);
- runtimeClasses = nullptr;
-}
-
-void Unit::generateChecksum()
-{
-#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
- QCryptographicHash hash(QCryptographicHash::Md5);
-
- const int checksummableDataOffset = offsetof(QV4::CompiledData::Unit, md5Checksum) + sizeof(md5Checksum);
-
- const char *dataPtr = reinterpret_cast<const char *>(this) + checksummableDataOffset;
- hash.addData(dataPtr, unitSize - checksummableDataOffset);
-
- QByteArray checksum = hash.result();
- Q_ASSERT(checksum.size() == sizeof(md5Checksum));
- memcpy(md5Checksum, checksum.constData(), sizeof(md5Checksum));
-#else
- memset(md5Checksum, 0, sizeof(md5Checksum));
-#endif
-}
-
-bool Unit::verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const
-{
- if (strncmp(magic, CompiledData::magic_str, sizeof(magic))) {
- *errorString = QStringLiteral("Magic bytes in the header do not match");
- return false;
- }
-
- if (version != quint32(QV4_DATA_STRUCTURE_VERSION)) {
- *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2").arg(version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16);
- return false;
- }
-
- if (qtVersion != quint32(QT_VERSION)) {
- *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2").arg(qtVersion, 0, 16).arg(QT_VERSION, 0, 16);
- return false;
- }
-
- if (sourceTimeStamp) {
- // Files from the resource system do not have any time stamps, so fall back to the application
- // executable.
- if (!expectedSourceTimeStamp.isValid())
- expectedSourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified();
-
- if (expectedSourceTimeStamp.isValid() && expectedSourceTimeStamp.toMSecsSinceEpoch() != sourceTimeStamp) {
- *errorString = QStringLiteral("QML source file has a different time stamp than cached file.");
- return false;
- }
- }
-
-#if defined(QML_COMPILE_HASH)
- if (qstrcmp(CompiledData::qml_compile_hash, libraryVersionHash) != 0) {
- *errorString = QStringLiteral("QML library version mismatch. Expected compile hash does not match");
- return false;
- }
-#else
-#error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files"
-#endif
-
- return true;
-}
-
-Location &Location::operator=(const QQmlJS::AST::SourceLocation &astLocation)
-{
- line = astLocation.startLine;
- column = astLocation.startColumn;
- return *this;
-}
-
-}
-
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 63738d6002..f3d5de3db1 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -51,19 +51,17 @@
//
#include <QtCore/qstring.h>
-#include <QtCore/qcryptographichash.h>
-#include <QVector>
-#include <QStringList>
-#include <QHash>
-#include <QUrl>
-
-#include <private/qv4executableallocator_p.h>
-#include <private/qqmlrefcount_p.h>
-#include <private/qqmlnullablevalue_p.h>
-#include <private/qv4identifier_p.h>
-#include <private/qflagpointer_p.h>
+#include <QtCore/qscopeguard.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qhash.h>
+
+#if QT_CONFIG(temporaryfile)
+#include <QtCore/qsavefile.h>
+#endif
+
#include <private/qendian_p.h>
-#include <private/qqmljsastfwd_p.h>
+#include <private/qv4staticvalue_p.h>
QT_BEGIN_NAMESPACE
@@ -88,10 +86,10 @@ struct Document;
}
namespace QV4 {
-struct StaticValue;
-
namespace Heap {
struct Module;
+struct String;
+struct InternalClass;
};
struct Function;
@@ -128,8 +126,6 @@ struct Location
Location() : _dummy(0) { }
- Location &operator=(const QQmlJS::AST::SourceLocation &astLocation);
-
inline bool operator<(const Location &other) const {
return line < other.line ||
(line == other.line && column < other.column);
@@ -411,7 +407,7 @@ static_assert(sizeof(ImportEntry) == 16, "ImportEntry structure needs to have th
// Qml data structures
-struct Q_QML_EXPORT TranslationData
+struct TranslationData
{
quint32_le stringIndex;
quint32_le commentIndex;
@@ -420,7 +416,7 @@ struct Q_QML_EXPORT TranslationData
};
static_assert(sizeof(TranslationData) == 16, "TranslationData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-struct Q_QML_PRIVATE_EXPORT Binding
+struct Binding
{
quint32_le propertyNameIndex;
@@ -517,7 +513,48 @@ struct Q_QML_PRIVATE_EXPORT Binding
bool isFunctionExpression() const { return (flags & IsFunctionExpression); }
- static QString escapedString(const QString &string);
+ //reverse of Lexer::singleEscape()
+ static QString escapedString(const QString &string)
+ {
+ QString tmp = QLatin1String("\"");
+ for (int i = 0; i < string.length(); ++i) {
+ const QChar &c = string.at(i);
+ switch (c.unicode()) {
+ case 0x08:
+ tmp += QLatin1String("\\b");
+ break;
+ case 0x09:
+ tmp += QLatin1String("\\t");
+ break;
+ case 0x0A:
+ tmp += QLatin1String("\\n");
+ break;
+ case 0x0B:
+ tmp += QLatin1String("\\v");
+ break;
+ case 0x0C:
+ tmp += QLatin1String("\\f");
+ break;
+ case 0x0D:
+ tmp += QLatin1String("\\r");
+ break;
+ case 0x22:
+ tmp += QLatin1String("\\\"");
+ break;
+ case 0x27:
+ tmp += QLatin1String("\\\'");
+ break;
+ case 0x5C:
+ tmp += QLatin1String("\\\\");
+ break;
+ default:
+ tmp += c;
+ break;
+ }
+ }
+ tmp += QLatin1Char('\"');
+ return tmp;
+ }
bool isTranslationBinding() const { return type == Type_Translation || type == Type_TranslationById; }
bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); }
@@ -565,14 +602,22 @@ struct Enum
};
static_assert(sizeof(Enum) == 12, "Enum structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+enum class BuiltinType : unsigned int {
+ Var = 0, Variant, Int, Bool, Real, String, Url, Color,
+ Font, Time, Date, DateTime, Rect, Point, Size,
+ Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, InvalidBuiltin
+};
+
struct Parameter
{
quint32_le nameIndex;
- quint32_le type;
- quint32_le customTypeNameIndex;
- Location location;
+ union {
+ quint32 _dummy;
+ quint32_le_bitfield<0, 1> indexIsBuiltinType;
+ quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType;
+ };
};
-static_assert(sizeof(Parameter) == 16, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+static_assert(sizeof(Parameter) == 8, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Signal
{
@@ -601,24 +646,33 @@ static_assert(sizeof(Signal) == 12, "Signal structure needs to have the expected
struct Property
{
- enum Type : unsigned int { Var = 0, Variant, Int, Bool, Real, String, Url, Color,
- Font, Time, Date, DateTime, Rect, Point, Size,
- Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion,
- Custom, CustomList };
-
- enum Flags : unsigned int {
- IsReadOnly = 0x1
- };
-
quint32_le nameIndex;
union {
- quint32_le_bitfield<0, 31> type;
- quint32_le_bitfield<31, 1> flags; // readonly
+ quint32_le_bitfield<0, 29> builtinTypeOrTypeNameIndex;
+ quint32_le_bitfield<29, 1> isBuiltinType;
+ quint32_le_bitfield<30, 1> isList;
+ quint32_le_bitfield<31, 1> isReadOnly;
};
- quint32_le customTypeNameIndex; // If type >= Custom
+
Location location;
+
+ void setBuiltinType(BuiltinType t)
+ {
+ builtinTypeOrTypeNameIndex = static_cast<quint32>(t);
+ isBuiltinType = true;
+ }
+ BuiltinType builtinType() const {
+ if (isBuiltinType)
+ return static_cast<BuiltinType>(quint32(builtinTypeOrTypeNameIndex));
+ return BuiltinType::InvalidBuiltin;
+ }
+ void setCustomType(int nameIndex)
+ {
+ builtinTypeOrTypeNameIndex = nameIndex;
+ isBuiltinType = false;
+ }
};
-static_assert(sizeof(Property) == 16, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+static_assert(sizeof(Property) == 12, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Alias {
enum Flags : unsigned int {
@@ -815,7 +869,6 @@ static_assert(sizeof(QmlUnit) == 16, "QmlUnit structure needs to have the expect
enum { QmlCompileHashSpace = 48 };
static const char magic_str[] = "qv4cdata";
-extern const char qml_compile_hash[QmlCompileHashSpace + 1];
struct Unit
{
@@ -830,8 +883,6 @@ struct Unit
char libraryVersionHash[QmlCompileHashSpace];
char md5Checksum[16]; // checksum of all bytes following this field.
- void generateChecksum();
-
char dependencyMD5Checksum[16];
enum : unsigned int {
@@ -879,8 +930,6 @@ struct Unit
quint32_le offsetToQmlUnit;
- bool verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const;
-
/* QML specific fields */
const QmlUnit *qmlUnit() const {
@@ -1014,8 +1063,8 @@ struct TypeReferenceMap : QHash<int, TypeReference>
auto prop = obj->propertiesBegin();
auto propEnd = obj->propertiesEnd();
for ( ; prop != propEnd; ++prop) {
- if (prop->type >= QV4::CompiledData::Property::Custom) {
- TypeReference &r = this->add(prop->customTypeNameIndex, prop->location);
+ if (!prop->isBuiltinType) {
+ TypeReference &r = this->add(prop->builtinTypeOrTypeNameIndex, prop->location);
r.errorWhenNotFound = true;
}
}
@@ -1043,7 +1092,7 @@ typedef QVector<QQmlPropertyData*> BindingPropertyData;
// This is how this hooks into the existing structures:
-struct Q_QML_PRIVATE_EXPORT CompilationUnitBase
+struct CompilationUnitBase
{
Q_DISABLE_COPY(CompilationUnitBase)
@@ -1080,11 +1129,11 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnitBase
Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value);
Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeStrings) == 0);
Q_STATIC_ASSERT(offsetof(CompilationUnitBase, constants) == sizeof(QV4::Heap::String **));
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offsetof(CompilationUnitBase, constants) + sizeof(const Value *));
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const Value *));
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const Value *));
+Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offsetof(CompilationUnitBase, constants) + sizeof(const StaticValue *));
+Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const StaticValue *));
+Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const StaticValue *));
-struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase
+struct CompilationUnit : public CompilationUnitBase
{
Q_DISABLE_COPY(CompilationUnit)
@@ -1094,8 +1143,31 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase
public:
using CompiledObject = CompiledData::Object;
- CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(), const QString &finalUrlString = QString());
- ~CompilationUnit();
+ CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(),
+ const QString &finalUrlString = QString())
+ {
+ setUnitData(unitData, nullptr, fileName, finalUrlString);
+ }
+
+ ~CompilationUnit()
+ {
+ if (data) {
+ if (data->qmlUnit() != qmlData)
+ free(const_cast<QmlUnit *>(qmlData));
+ qmlData = nullptr;
+
+ if (!(data->flags & QV4::CompiledData::Unit::StaticData))
+ free(const_cast<Unit *>(data));
+ }
+ data = nullptr;
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ delete [] constants;
+ constants = nullptr;
+#endif
+
+ delete [] imports;
+ imports = nullptr;
+ }
CompilationUnit(CompilationUnit &&other) noexcept
{
@@ -1123,8 +1195,36 @@ public:
}
const Unit *unitData() const { return data; }
+
void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr,
- const QString &fileName = QString(), const QString &finalUrlString = QString());
+ const QString &fileName = QString(), const QString &finalUrlString = QString())
+ {
+ data = unitData;
+ qmlData = nullptr;
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ delete [] constants;
+#endif
+ constants = nullptr;
+ m_fileName.clear();
+ m_finalUrlString.clear();
+ if (!data)
+ return;
+
+ qmlData = qmlUnit ? qmlUnit : data->qmlUnit();
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ StaticValue *bigEndianConstants = new StaticValue[data->constantTableSize];
+ const quint64_le *littleEndianConstants = data->constants();
+ for (uint i = 0; i < data->constantTableSize; ++i)
+ bigEndianConstants[i] = StaticValue::fromReturnedValue(littleEndianConstants[i]);
+ constants = bigEndianConstants;
+#else
+ constants = reinterpret_cast<const StaticValue*>(data->constants());
+#endif
+
+ m_fileName = !fileName.isEmpty() ? fileName : stringAt(data->sourceFileIndex);
+ m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(data->finalUrlIndex);
+ }
QString stringAt(int index) const
{
@@ -1139,58 +1239,76 @@ public:
Heap::Module *module() const { return m_module; }
void setModule(Heap::Module *module) { m_module = module; }
- void unlink();
-
private:
QString m_fileName; // initialized from data->sourceFileIndex
QString m_finalUrlString; // initialized from data->finalUrlIndex
Heap::Module *m_module = nullptr;
-
-public:
- bool saveToDisk(const QString &outputFileName, QString *errorString) const;
};
class SaveableUnitPointer
{
Q_DISABLE_COPY_MOVE(SaveableUnitPointer)
public:
- SaveableUnitPointer(const CompilationUnit *unit, quint32 temporaryFlags = Unit::StaticData) :
- unit(unit)
+ SaveableUnitPointer(const Unit *unit, quint32 temporaryFlags = Unit::StaticData) :
+ unit(unit),
+ temporaryFlags(temporaryFlags)
{
- quint32_le &unitFlags = mutableFlags();
- quint32 origFlags = unitFlags;
- unitFlags |= temporaryFlags;
- changedFlags = origFlags ^ unitFlags;
}
- ~SaveableUnitPointer()
+ ~SaveableUnitPointer() = default;
+
+ template<typename Char>
+ bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const
{
- mutableFlags() ^= changedFlags;
+ auto cleanup = qScopeGuard([this]() { mutableFlags() ^= temporaryFlags; });
+ mutableFlags() |= temporaryFlags;
+ return writer(data<Char>(), size());
}
- const CompilationUnit *operator->() const { return unit; }
- const CompilationUnit &operator*() const { return *unit; }
- operator const CompilationUnit *() { return unit; }
+ static bool writeDataToFile(const QString &outputFileName, const char *data, quint32 size,
+ QString *errorString)
+ {
+#if QT_CONFIG(temporaryfile)
+ QSaveFile cacheFile(outputFileName);
+ if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)
+ || cacheFile.write(data, size) != size
+ || !cacheFile.commit()) {
+ *errorString = cacheFile.errorString();
+ return false;
+ }
+
+ errorString->clear();
+ return true;
+#else
+ Q_UNUSED(outputFileName)
+ *errorString = QStringLiteral("features.temporaryfile is disabled.");
+ return false;
+#endif
+ }
+
+private:
+ const Unit *unit;
+ quint32 temporaryFlags;
+
+ quint32_le &mutableFlags() const
+ {
+ return const_cast<Unit *>(unit)->flags;
+ }
template<typename Char>
const Char *data() const
{
Q_STATIC_ASSERT(sizeof(Char) == 1);
const Char *dataPtr;
- memcpy(&dataPtr, &unit->data, sizeof(dataPtr));
+ memcpy(&dataPtr, &unit, sizeof(dataPtr));
return dataPtr;
}
quint32 size() const
{
- return unit->data->unitSize;
+ return unit->unitSize;
}
-
-private:
- quint32_le &mutableFlags() { return const_cast<Unit *>(unit->unitData())->flags; };
- const CompilationUnit *unit;
- quint32 changedFlags;
};
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index d8f293211e..b378c294b7 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -44,6 +44,7 @@
#include <private/qv4alloca_p.h>
#include <private/qqmljslexer_p.h>
#include <private/qqmljsast_p.h>
+#include <private/qml_compile_hash_p.h>
#include <QCryptographicHash>
// Efficient implementation that takes advantage of powers of two.
@@ -125,6 +126,25 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
}
}
+void QV4::Compiler::JSUnitGenerator::generateUnitChecksum(QV4::CompiledData::Unit *unit)
+{
+#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ QCryptographicHash hash(QCryptographicHash::Md5);
+
+ const int checksummableDataOffset
+ = offsetof(QV4::CompiledData::Unit, md5Checksum) + sizeof(unit->md5Checksum);
+
+ const char *dataPtr = reinterpret_cast<const char *>(unit) + checksummableDataOffset;
+ hash.addData(dataPtr, unit->unitSize - checksummableDataOffset);
+
+ QByteArray checksum = hash.result();
+ Q_ASSERT(checksum.size() == sizeof(unit->md5Checksum));
+ memcpy(unit->md5Checksum, checksum.constData(), sizeof(unit->md5Checksum));
+#else
+ memset(unit->md5Checksum, 0, sizeof(unit->md5Checksum));
+#endif
+}
+
QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::Compiler::Module *module)
: module(module)
{
@@ -391,7 +411,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
if (option == GenerateWithStringTable)
stringTable.serialize(unit);
- unit->generateChecksum();
+ generateUnitChecksum(unit);
return unit;
}
@@ -580,7 +600,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.flags |= module->unitFlags;
unit.version = QV4_DATA_STRUCTURE_VERSION;
unit.qtVersion = QT_VERSION;
- qstrcpy(unit.libraryVersionHash, CompiledData::qml_compile_hash);
+ qstrcpy(unit.libraryVersionHash, QML_COMPILE_HASH);
memset(unit.md5Checksum, 0, sizeof(unit.md5Checksum));
memset(unit.dependencyMD5Checksum, 0, sizeof(unit.dependencyMD5Checksum));
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 49e334bb81..f5884f6478 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -103,6 +103,8 @@ private:
};
struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
+ static void generateUnitChecksum(CompiledData::Unit *unit);
+
struct MemberInfo {
QString name;
bool isAccessor;
diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp
index ef67a11a70..416a0edee0 100644
--- a/src/qml/compiler/qv4compilerscanfunctions.cpp
+++ b/src/qml/compiler/qv4compilerscanfunctions.cpp
@@ -44,7 +44,6 @@
#include <QtCore/QSet>
#include <QtCore/QBuffer>
#include <QtCore/QBitArray>
-#include <QtCore/QLinkedList>
#include <QtCore/QStack>
#include <private/qqmljsast_p.h>
#include <private/qv4compilercontext_p.h>
@@ -55,6 +54,15 @@ using namespace QV4;
using namespace QV4::Compiler;
using namespace QQmlJS::AST;
+static CompiledData::Location location(const QQmlJS::AST::SourceLocation &astLocation)
+{
+ CompiledData::Location target;
+ target.line = astLocation.startLine;
+ target.column = astLocation.startColumn;
+ return target;
+}
+
+
ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, ContextType defaultProgramType)
: QQmlJS::AST::Visitor(cg->recursionDepth())
, _cg(cg)
@@ -176,7 +184,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
Compiler::ExportEntry entry;
entry.moduleRequest = declaration->fromClause->moduleSpecifier.toString();
entry.importName = QStringLiteral("*");
- entry.location = declaration->firstSourceLocation();
+ entry.location = location(declaration->firstSourceLocation());
_context->exportEntries << entry;
} else if (declaration->exportClause) {
for (ExportsList *it = declaration->exportClause->exportsList; it; it = it->next) {
@@ -189,7 +197,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
entry.moduleRequest = module;
entry.exportName = spec->exportedIdentifier.toString();
- entry.location = it->firstSourceLocation();
+ entry.location = location(it->firstSourceLocation());
_context->exportEntries << entry;
}
@@ -204,7 +212,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
Compiler::ExportEntry entry;
entry.localName = name;
entry.exportName = name;
- entry.location = vstmt->firstSourceLocation();
+ entry.location = location(vstmt->firstSourceLocation());
_context->exportEntries << entry;
}
} else if (auto *classDecl = AST::cast<AST::ClassDeclaration*>(declaration->variableStatementOrDeclaration)) {
@@ -213,7 +221,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
Compiler::ExportEntry entry;
entry.localName = name;
entry.exportName = name;
- entry.location = classDecl->firstSourceLocation();
+ entry.location = location(classDecl->firstSourceLocation());
_context->exportEntries << entry;
if (declaration->exportDefault)
localNameForDefaultExport = entry.localName;
@@ -232,7 +240,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
Compiler::ExportEntry entry;
entry.localName = functionName;
entry.exportName = functionName;
- entry.location = fdef->firstSourceLocation();
+ entry.location = location(fdef->firstSourceLocation());
_context->exportEntries << entry;
if (declaration->exportDefault)
localNameForDefaultExport = entry.localName;
@@ -244,7 +252,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
entry.localName = localNameForDefaultExport;
_context->localNameForDefaultExport = localNameForDefaultExport;
entry.exportName = QStringLiteral("default");
- entry.location = declaration->firstSourceLocation();
+ entry.location = location(declaration->firstSourceLocation());
_context->exportEntries << entry;
}
@@ -269,7 +277,7 @@ bool ScanFunctions::visit(ImportDeclaration *declaration)
entry.moduleRequest = module;
entry.importName = QStringLiteral("default");
entry.localName = import->importedDefaultBinding.toString();
- entry.location = declaration->firstSourceLocation();
+ entry.location = location(declaration->firstSourceLocation());
_context->importEntries << entry;
}
@@ -278,7 +286,7 @@ bool ScanFunctions::visit(ImportDeclaration *declaration)
entry.moduleRequest = module;
entry.importName = QStringLiteral("*");
entry.localName = import->nameSpaceImport->importedBinding.toString();
- entry.location = declaration->firstSourceLocation();
+ entry.location = location(declaration->firstSourceLocation());
_context->importEntries << entry;
}
@@ -291,7 +299,7 @@ bool ScanFunctions::visit(ImportDeclaration *declaration)
entry.importName = it->importSpecifier->identifier.toString();
else
entry.importName = entry.localName;
- entry.location = declaration->firstSourceLocation();
+ entry.location = location(declaration->firstSourceLocation());
_context->importEntries << entry;
}
}