namespace CompiledData {
-int Function::calculateSize(QQmlJS::V4IR::Function *f)
-{
- return calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size());
-}
-
CompilationUnit::~CompilationUnit()
{
engine->compilationUnits.erase(engine->compilationUnits.find(this));
quint32 formalsOffset;
quint32 nLocals;
quint32 localsOffset;
+ quint32 nLineNumberMappingEntries;
+ quint32 lineNumberMappingOffset; // Array of uint pairs (offset and line number)
quint32 nInnerFunctions;
quint32 innerFunctionsOffset;
// quint32 formalsIndex[nFormals]
const quint32 *formalsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + formalsOffset); }
const quint32 *localsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + localsOffset); }
+ const quint32 *lineNumberMapping() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + lineNumberMappingOffset); }
- static int calculateSize(int nFormals, int nLocals, int nInnerfunctions) {
- return (sizeof(Function) + (nFormals + nLocals + nInnerfunctions) * sizeof(quint32) + 7) & ~0x7;
+ static int calculateSize(int nFormals, int nLocals, int nInnerfunctions, int lineNumberMappings) {
+ return (sizeof(Function) + (nFormals + nLocals + nInnerfunctions + 2 * lineNumberMappings) * sizeof(quint32) + 7) & ~0x7;
}
- static int calculateSize(QQmlJS::V4IR::Function *f);
};
struct String
return regexps.size() - 1;
}
+void QV4::Compiler::JSUnitGenerator::registerLineNumberMapping(QQmlJS::V4IR::Function *function, const QVector<uint> &mappings)
+{
+ lineNumberMappingsPerFunction.insert(function, mappings);
+}
+
QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit()
{
registerString(irModule->fileName);
for (int i = 0; i < irModule->functions.size(); ++i) {
QQmlJS::V4IR::Function *f = irModule->functions.at(i);
functionOffsets.insert(f, functionDataSize + unitSize + stringDataSize);
- functionDataSize += QV4::CompiledData::Function::calculateSize(f);
+
+ int lineNumberMappingCount = 0;
+ QHash<QQmlJS::V4IR::Function *, QVector<uint> >::ConstIterator lineNumberMapping = lineNumberMappingsPerFunction.find(f);
+ if (lineNumberMapping != lineNumberMappingsPerFunction.constEnd())
+ lineNumberMappingCount = lineNumberMapping->count() / 2;
+
+ functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), lineNumberMappingCount);
}
const uint lookupDataSize = CompiledData::Lookup::calculateSize() * lookups.count();
if (function == irModule->rootFunction)
unit->indexOfRootFunction = i;
- writeFunction(f, i, function);
- f += QV4::CompiledData::Function::calculateSize(function);
+ const int bytes = writeFunction(f, i, function);
+ f += bytes;
}
CompiledData::Lookup *lookupsToWrite = (CompiledData::Lookup*)(data + unit->offsetToLookupTable);
return unit;
}
-void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4IR::Function *irFunction)
+int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4IR::Function *irFunction)
{
QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f;
+
+ QHash<QQmlJS::V4IR::Function *, QVector<uint> >::ConstIterator lineNumberMapping = lineNumberMappingsPerFunction.find(irFunction);
+
function->index = index;
function->nameIndex = getStringId(*irFunction->name);
function->flags = 0;
function->formalsOffset = sizeof(QV4::CompiledData::Function);
function->nLocals = irFunction->locals.size();
function->localsOffset = function->formalsOffset + function->nFormals * sizeof(quint32);
+
+ function->nLineNumberMappingEntries = 0;
+ if (lineNumberMapping != lineNumberMappingsPerFunction.constEnd()) {
+ function->nLineNumberMappingEntries = lineNumberMapping->count() / 2;
+ }
+ function->lineNumberMappingOffset = function->localsOffset + function->nLocals * sizeof(quint32);
+
function->nInnerFunctions = irFunction->nestedFunctions.size();
- function->innerFunctionsOffset = function->localsOffset + function->nLocals * sizeof(quint32);
+ function->innerFunctionsOffset = function->lineNumberMappingOffset + function->nLineNumberMappingEntries * 2 * sizeof(quint32);
// write formals
quint32 *formals = (quint32 *)(f + function->formalsOffset);
for (int i = 0; i < irFunction->locals.size(); ++i)
locals[i] = getStringId(*irFunction->locals.at(i));
+ // write line number mappings
+ quint32 *mappingsToWrite = (quint32*)(f + function->lineNumberMappingOffset);
+ memcpy(mappingsToWrite, lineNumberMapping->constData(), 2 * function->nLineNumberMappingEntries * sizeof(quint32));
+
// 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));
+
+ return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions, function->nLineNumberMappingEntries);
}
int registerRegExp(QQmlJS::V4IR::RegExp *regexp);
+ void registerLineNumberMapping(QQmlJS::V4IR::Function *function, const QVector<uint> &mappings);
+
QV4::CompiledData::Unit *generateUnit();
- void writeFunction(char *f, int index, QQmlJS::V4IR::Function *irFunction);
+ // Returns bytes written
+ int writeFunction(char *f, int index, QQmlJS::V4IR::Function *irFunction);
QHash<QString, int> stringToId;
QStringList strings;
QHash<QQmlJS::V4IR::Function *, uint> functionOffsets;
QList<CompiledData::Lookup> lookups;
QVector<CompiledData::RegExp> regexps;
+ QHash<QQmlJS::V4IR::Function *, QVector<uint> > lineNumberMappingsPerFunction;
};
}
JSC::LinkBuffer linkBuffer(dummy, this, 0);
vmFunc->codeSize = linkBuffer.offsetOf(endOfCode);
- vmFunc->lineNumberMappings.resize(codeLineNumberMappings.count());
+ QVector<uint> lineNumberMapping(codeLineNumberMappings.count() * 2);
+
for (int i = 0; i < codeLineNumberMappings.count(); ++i) {
- QV4::LineNumberMapping mapping;
- mapping.codeOffset = linkBuffer.offsetOf(codeLineNumberMappings.at(i).location);
- mapping.lineNumber = codeLineNumberMappings.at(i).lineNumber;
- vmFunc->lineNumberMappings[i] = mapping;
+ lineNumberMapping[i * 2] = linkBuffer.offsetOf(codeLineNumberMappings.at(i).location);
+ lineNumberMapping[i * 2 + 1] = codeLineNumberMappings.at(i).lineNumber;
}
+ _isel->registerLineNumberMapping(_function, lineNumberMapping);
QHash<void*, const char*> functions;
foreach (CallToLink ctl, _callsToLink) {
uint registerGetterLookup(const QString &str) { return jsUnitGenerator.registerGetterLookup(str); }
uint registerSetterLookup(const QString &str) { return jsUnitGenerator.registerSetterLookup(str); }
uint registerGlobalGetterLookup(const QString &str) { return jsUnitGenerator.registerGlobalGetterLookup(str); }
+ void registerLineNumberMapping(V4IR::Function *function, const QVector<uint> &mappings) { jsUnitGenerator.registerLineNumberMapping(function, mappings); }
protected:
QV4::Function *createFunctionMapping(QV4::Function *outer, V4IR::Function *irFunction);
QList<int>::Iterator breakPoint = breakPointsForFile->begin();
while (breakPoint != breakPointsForFile->end()) {
bool breakPointFound = false;
- for (QVector<LineNumberMapping>::ConstIterator mapping = function->lineNumberMappings.constBegin(),
- end = function->lineNumberMappings.constEnd(); mapping != end; ++mapping) {
- if (mapping->lineNumber == *breakPoint) {
- uchar *codePtr = const_cast<uchar *>(function->codeData) + mapping->codeOffset;
+ const quint32 *lineNumberMappings = function->compiledFunction->lineNumberMapping();
+ for (int i = 0; i < function->compiledFunction->nLineNumberMappingEntries; ++i) {
+ const int codeOffset = lineNumberMappings[i * 2];
+ const int lineNumber = lineNumberMappings[i * 2 + 1];
+ if (lineNumber == *breakPoint) {
+ uchar *codePtr = const_cast<uchar *>(function->codeData) + codeOffset;
QQmlJS::Moth::Instr *instruction = reinterpret_cast<QQmlJS::Moth::Instr*>(codePtr);
instruction->common.breakPoint = !removeBreakPoints;
// Continue setting the next break point.
}
namespace QV4 {
-bool operator<(const LineNumberMapping &mapping, qptrdiff pc)
+struct LineNumberMappingHelper
{
- return mapping.codeOffset < pc;
-}
+ const quint32 *table;
+ int lowerBound(int begin, int end, qptrdiff offset) {
+ int middle;
+ int n = int(end - begin);
+ int half;
+
+ while (n > 0) {
+ half = n >> 1;
+ middle = begin + half;
+ if (table[middle * 2] < offset) {
+ begin = middle + 1;
+ n -= half + 1;
+ } else {
+ n = half;
+ }
+ }
+ return begin;
+ }
+};
+
}
int Function::lineNumberForProgramCounter(qptrdiff offset) const
{
- QVector<LineNumberMapping>::ConstIterator it = qLowerBound(lineNumberMappings.begin(), lineNumberMappings.end(), offset);
- if (it != lineNumberMappings.constBegin() && lineNumberMappings.count() > 0)
- --it;
- if (it == lineNumberMappings.constEnd())
+ LineNumberMappingHelper helper;
+ helper.table = compiledFunction->lineNumberMapping();
+ const uint count = compiledFunction->nLineNumberMappingEntries;
+
+ int pos = helper.lowerBound(0, count, offset);
+ if (pos != 0 && count > 0)
+ --pos;
+ if (pos == count)
return -1;
- return it->lineNumber;
+ return helper.table[pos * 2 + 1];
}
QT_END_NAMESPACE