aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qv4compiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/compiler/qv4compiler.cpp')
-rw-r--r--src/qml/compiler/qv4compiler.cpp234
1 files changed, 133 insertions, 101 deletions
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index aacf0e9928..729c56540d 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -42,6 +42,8 @@
#include <qv4isel_p.h>
#include <private/qv4string_p.h>
#include <private/qv4value_p.h>
+#include <private/qv4alloca_p.h>
+#include <wtf/MathExtras.h>
QV4::Compiler::StringTableGenerator::StringTableGenerator()
{
@@ -75,15 +77,21 @@ void QV4::Compiler::StringTableGenerator::clear()
void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
{
char *dataStart = reinterpret_cast<char *>(unit);
- uint *stringTable = reinterpret_cast<uint *>(dataStart + unit->offsetToStringTable);
+ CompiledData::LEUInt32 *stringTable = reinterpret_cast<CompiledData::LEUInt32 *>(dataStart + unit->offsetToStringTable);
char *stringData = dataStart + unit->offsetToStringTable + unit->stringTableSize * sizeof(uint);
for (int i = 0; i < strings.size(); ++i) {
stringTable[i] = stringData - dataStart;
const QString &qstr = strings.at(i);
- QV4::CompiledData::String *s = (QV4::CompiledData::String*)(stringData);
+ QV4::CompiledData::String *s = reinterpret_cast<QV4::CompiledData::String *>(stringData);
s->size = qstr.length();
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
memcpy(s + 1, qstr.constData(), qstr.length()*sizeof(ushort));
+#else
+ ushort *uc = reinterpret_cast<ushort *>(s + 1);
+ for (int i = 0; i < qstr.length(); ++i)
+ uc[i] = qToLittleEndian<ushort>(qstr.at(i).unicode());
+#endif
stringData += QV4::CompiledData::String::calculateSize(qstr);
}
@@ -91,7 +99,6 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::IR::Module *module)
: irModule(module)
- , jsClassDataSize(0)
{
// Make sure the empty string always gets index 0
registerString(QString());
@@ -173,36 +180,38 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, IR::ExprList *arg
{
// ### re-use existing class definitions.
- QList<CompiledData::JSClassMember> members;
- members.reserve(count);
+ const int size = CompiledData::JSClass::calculateSize(count);
+ jsClassOffsets.append(jsClassData.size());
+ const int oldSize = jsClassData.size();
+ jsClassData.resize(jsClassData.size() + size);
+ memset(jsClassData.data() + oldSize, 0, size);
- IR::ExprList *it = args;
- for (int i = 0; i < count; ++i, it = it->next) {
- CompiledData::JSClassMember member;
+ CompiledData::JSClass *jsClass = reinterpret_cast<CompiledData::JSClass*>(jsClassData.data() + oldSize);
+ jsClass->nMembers = count;
+ CompiledData::JSClassMember *member = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + 1);
+ IR::ExprList *it = args;
+ for (int i = 0; i < count; ++i, it = it->next, ++member) {
QV4::IR::Name *name = it->expr->asName();
it = it->next;
const bool isData = it->expr->asConst()->value;
it = it->next;
- member.nameOffset = registerString(*name->id);
- member.isAccessor = !isData;
- members << member;
+ member->nameOffset = registerString(*name->id);
+ member->isAccessor = !isData;
if (!isData)
it = it->next;
}
- jsClasses << members;
- jsClassDataSize += CompiledData::JSClass::calculateSize(members.count());
- return jsClasses.size() - 1;
+ return jsClassOffsets.size() - 1;
}
QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorOption option)
{
registerString(irModule->fileName);
- foreach (QV4::IR::Function *f, irModule->functions) {
+ for (QV4::IR::Function *f : qAsConst(irModule->functions)) {
registerString(*f->name);
for (int i = 0; i < f->formals.size(); ++i)
registerString(*f->formals.at(i));
@@ -210,94 +219,51 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
registerString(*f->locals.at(i));
}
- int unitSize = QV4::CompiledData::Unit::calculateSize(irModule->functions.size(), regexps.size(),
- constants.size(), lookups.size(), jsClasses.count());
-
- uint functionDataSize = 0;
- for (int i = 0; i < irModule->functions.size(); ++i) {
- QV4::IR::Function *f = irModule->functions.at(i);
- functionOffsets.insert(f, functionDataSize + unitSize);
+ CompiledData::LEUInt32 *functionOffsets = reinterpret_cast<CompiledData::LEUInt32*>(alloca(irModule->functions.size() * sizeof(CompiledData::LEUInt32)));
+ uint jsClassDataOffset = 0;
- const int qmlIdDepsCount = f->idObjectDependencies.count();
- const int qmlPropertyDepsCount = f->scopeObjectPropertyDependencies.count() + f->contextObjectPropertyDependencies.count();
- functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), qmlIdDepsCount, qmlPropertyDepsCount);
+ char *dataPtr;
+ CompiledData::Unit *unit;
+ {
+ QV4::CompiledData::Unit tempHeader = generateHeader(option, functionOffsets, &jsClassDataOffset);
+ dataPtr = reinterpret_cast<char *>(malloc(tempHeader.unitSize));
+ memcpy(&unit, &dataPtr, sizeof(CompiledData::Unit*));
+ memcpy(unit, &tempHeader, sizeof(tempHeader));
}
- const int totalSize = unitSize + functionDataSize + jsClassDataSize + (option == GenerateWithStringTable ? stringTable.sizeOfTableAndData() : 0);
- char *data = (char *)malloc(totalSize);
- memset(data, 0, totalSize);
- QV4::CompiledData::Unit *unit = (QV4::CompiledData::Unit*)data;
-
- memcpy(unit->magic, QV4::CompiledData::magic_str, sizeof(unit->magic));
- unit->architecture = 0; // ###
- unit->flags = QV4::CompiledData::Unit::IsJavascript;
- unit->version = 1;
- unit->unitSize = totalSize;
- unit->functionTableSize = irModule->functions.size();
- unit->offsetToFunctionTable = sizeof(*unit);
- unit->lookupTableSize = lookups.count();
- unit->offsetToLookupTable = unit->offsetToFunctionTable + unit->functionTableSize * sizeof(uint);
- unit->regexpTableSize = regexps.size();
- unit->offsetToRegexpTable = unit->offsetToLookupTable + unit->lookupTableSize * CompiledData::Lookup::calculateSize();
- unit->constantTableSize = constants.size();
- unit->offsetToConstantTable = unit->offsetToRegexpTable + unit->regexpTableSize * CompiledData::RegExp::calculateSize();
- unit->jsClassTableSize = jsClasses.count();
- unit->offsetToJSClassTable = unit->offsetToConstantTable + unit->constantTableSize * sizeof(ReturnedValue);
- if (option == GenerateWithStringTable) {
- unit->stringTableSize = stringTable.stringCount();
- unit->offsetToStringTable = unitSize + functionDataSize + jsClassDataSize;
- } else {
- unit->stringTableSize = 0;
- unit->offsetToStringTable = 0;
- }
- unit->indexOfRootFunction = -1;
- unit->sourceFileIndex = getStringId(irModule->fileName);
- unit->nImports = 0;
- unit->offsetToImports = 0;
- unit->nObjects = 0;
- unit->offsetToObjects = 0;
- unit->indexOfRootObject = 0;
-
- uint *functionTable = (uint *)(data + unit->offsetToFunctionTable);
- for (int i = 0; i < irModule->functions.size(); ++i)
- functionTable[i] = functionOffsets.value(irModule->functions.at(i));
-
- char *f = data + unitSize;
+ memcpy(dataPtr + unit->offsetToFunctionTable, functionOffsets, unit->functionTableSize * sizeof(CompiledData::LEUInt32));
+
for (int i = 0; i < irModule->functions.size(); ++i) {
QV4::IR::Function *function = irModule->functions.at(i);
if (function == irModule->rootFunction)
unit->indexOfRootFunction = i;
- const int bytes = writeFunction(f, i, function);
- f += bytes;
+ writeFunction(dataPtr + functionOffsets[i], function);
}
- CompiledData::Lookup *lookupsToWrite = (CompiledData::Lookup*)(data + unit->offsetToLookupTable);
- foreach (const CompiledData::Lookup &l, lookups)
+ CompiledData::Lookup *lookupsToWrite = reinterpret_cast<CompiledData::Lookup*>(dataPtr + unit->offsetToLookupTable);
+ for (const CompiledData::Lookup &l : qAsConst(lookups))
*lookupsToWrite++ = l;
- CompiledData::RegExp *regexpTable = (CompiledData::RegExp *)(data + unit->offsetToRegexpTable);
+ CompiledData::RegExp *regexpTable = reinterpret_cast<CompiledData::RegExp *>(dataPtr + unit->offsetToRegexpTable);
memcpy(regexpTable, regexps.constData(), regexps.size() * sizeof(*regexpTable));
- ReturnedValue *constantTable = (ReturnedValue *)(data + unit->offsetToConstantTable);
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ ReturnedValue *constantTable = reinterpret_cast<ReturnedValue *>(dataPtr + unit->offsetToConstantTable);
memcpy(constantTable, constants.constData(), constants.size() * sizeof(ReturnedValue));
-
- // write js classes and js class lookup table
- uint *jsClassTable = (uint*)(data + unit->offsetToJSClassTable);
- char *jsClass = data + unitSize + functionDataSize;
- for (int i = 0; i < jsClasses.count(); ++i) {
- jsClassTable[i] = jsClass - data;
-
- const QList<CompiledData::JSClassMember> members = jsClasses.at(i);
-
- CompiledData::JSClass *c = reinterpret_cast<CompiledData::JSClass*>(jsClass);
- c->nMembers = members.count();
-
- CompiledData::JSClassMember *memberToWrite = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + sizeof(CompiledData::JSClass));
- foreach (const CompiledData::JSClassMember &member, members)
- *memberToWrite++ = member;
-
- jsClass += CompiledData::JSClass::calculateSize(members.count());
+#else
+ CompiledData::LEUInt64 *constantTable = reinterpret_cast<CompiledData::LEUInt64 *>(dataPtr + unit->offsetToConstantTable);
+ for (int i = 0; i < constants.count(); ++i)
+ constantTable[i] = constants.at(i);
+#endif
+
+ {
+ memcpy(dataPtr + jsClassDataOffset, jsClassData.constData(), jsClassData.size());
+
+ // write js classes and js class lookup table
+ CompiledData::LEUInt32 *jsClassOffsetTable = reinterpret_cast<CompiledData::LEUInt32 *>(dataPtr + unit->offsetToJSClassTable);
+ for (int i = 0; i < jsClassOffsets.count(); ++i)
+ jsClassOffsetTable[i] = jsClassDataOffset + jsClassOffsets.at(i);
}
// write strings and string table
@@ -307,13 +273,13 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
return unit;
}
-int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::Function *irFunction)
+void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *irFunction) const
{
QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f;
quint32 currentOffset = sizeof(QV4::CompiledData::Function);
+ currentOffset = (currentOffset + 7) & ~quint32(0x7);
- function->index = index;
function->nameIndex = getStringId(*irFunction->name);
function->flags = 0;
if (irFunction->hasDirectEval)
@@ -335,8 +301,6 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::F
currentOffset += function->nLocals * sizeof(quint32);
function->nInnerFunctions = irFunction->nestedFunctions.size();
- function->innerFunctionsOffset = currentOffset;
- currentOffset += function->nInnerFunctions * sizeof(quint32);
function->nDependingIdObjects = 0;
function->nDependingContextProperties = 0;
@@ -363,6 +327,9 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::F
function->location.line = irFunction->line;
function->location.column = irFunction->column;
+ function->codeOffset = 0;
+ function->codeSize = 0;
+
// write formals
quint32 *formals = (quint32 *)(f + function->formalsOffset);
for (int i = 0; i < irFunction->formals.size(); ++i)
@@ -373,15 +340,12 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::F
for (int i = 0; i < irFunction->locals.size(); ++i)
locals[i] = getStringId(*irFunction->locals.at(i));
- // write inner functions
- quint32 *innerFunctions = (quint32 *)(f + function->innerFunctionsOffset);
- for (int i = 0; i < irFunction->nestedFunctions.size(); ++i)
- innerFunctions[i] = functionOffsets.value(irFunction->nestedFunctions.at(i));
-
// write QML dependencies
quint32 *writtenDeps = (quint32 *)(f + function->dependingIdObjectsOffset);
- foreach (int id, irFunction->idObjectDependencies)
- *writtenDeps++ = id;
+ for (int id : irFunction->idObjectDependencies) {
+ Q_ASSERT(id >= 0);
+ *writtenDeps++ = static_cast<quint32>(id);
+ }
writtenDeps = (quint32 *)(f + function->dependingContextPropertiesOffset);
for (auto property : irFunction->contextObjectPropertyDependencies) {
@@ -394,7 +358,75 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::F
*writtenDeps++ = property.key(); // property index
*writtenDeps++ = property.value(); // notify index
}
+}
+
+QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Compiler::JSUnitGenerator::GeneratorOption option, QJsonPrivate::q_littleendian<quint32> *functionOffsets, uint *jsClassDataOffset)
+{
+ CompiledData::Unit unit;
+ memcpy(unit.magic, CompiledData::magic_str, sizeof(unit.magic));
+ unit.flags = QV4::CompiledData::Unit::IsJavascript;
+ unit.flags |= irModule->unitFlags;
+ unit.version = QV4_DATA_STRUCTURE_VERSION;
+ unit.qtVersion = QT_VERSION;
+ unit.architectureIndex = registerString(QSysInfo::buildAbi());
+ unit.codeGeneratorIndex = registerString(codeGeneratorName);
+ memset(unit.dependencyMD5Checksum, 0, sizeof(unit.dependencyMD5Checksum));
- return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions,
- function->nDependingIdObjects, function->nDependingContextProperties + function->nDependingScopeProperties);
+ quint32 nextOffset = sizeof(CompiledData::Unit);
+
+ unit.functionTableSize = irModule->functions.size();
+ unit.offsetToFunctionTable = nextOffset;
+ nextOffset += unit.functionTableSize * sizeof(uint);
+
+ unit.lookupTableSize = lookups.count();
+ unit.offsetToLookupTable = nextOffset;
+ nextOffset += unit.lookupTableSize * sizeof(CompiledData::Lookup);
+
+ unit.regexpTableSize = regexps.size();
+ unit.offsetToRegexpTable = nextOffset;
+ nextOffset += unit.regexpTableSize * sizeof(CompiledData::RegExp);
+
+ unit.constantTableSize = constants.size();
+
+ // Ensure we load constants from well-aligned addresses into for example SSE registers.
+ nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(16, nextOffset));
+ unit.offsetToConstantTable = nextOffset;
+ nextOffset += unit.constantTableSize * sizeof(ReturnedValue);
+
+ unit.jsClassTableSize = jsClassOffsets.count();
+ unit.offsetToJSClassTable = nextOffset;
+ nextOffset += unit.jsClassTableSize * sizeof(uint);
+
+ *jsClassDataOffset = nextOffset;
+ nextOffset += jsClassData.size();
+
+ for (int i = 0; i < irModule->functions.size(); ++i) {
+ QV4::IR::Function *f = irModule->functions.at(i);
+ functionOffsets[i] = nextOffset;
+
+ const int qmlIdDepsCount = f->idObjectDependencies.count();
+ const int qmlPropertyDepsCount = f->scopeObjectPropertyDependencies.count() + f->contextObjectPropertyDependencies.count();
+ nextOffset += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), qmlIdDepsCount, qmlPropertyDepsCount);
+ }
+
+ if (option == GenerateWithStringTable) {
+ unit.stringTableSize = stringTable.stringCount();
+ unit.offsetToStringTable = nextOffset;
+ nextOffset += stringTable.sizeOfTableAndData();
+ } else {
+ unit.stringTableSize = 0;
+ unit.offsetToStringTable = 0;
+ }
+ unit.indexOfRootFunction = -1;
+ unit.sourceFileIndex = getStringId(irModule->fileName);
+ unit.sourceTimeStamp = irModule->sourceTimeStamp;
+ unit.nImports = 0;
+ unit.offsetToImports = 0;
+ unit.nObjects = 0;
+ unit.offsetToObjects = 0;
+ unit.indexOfRootObject = 0;
+
+ unit.unitSize = nextOffset;
+
+ return unit;
}