Store line number mappings in the compiled function
authorSimon Hausmann <simon.hausmann@digia.com>
Fri, 16 Aug 2013 06:57:58 +0000 (08:57 +0200)
committerLars Knoll <lars.knoll@digia.com>
Fri, 16 Aug 2013 08:14:22 +0000 (10:14 +0200)
Change-Id: I4e37aac3618b20ccd52ce4833098781374a3daf6
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
src/qml/compiler/qv4compileddata.cpp
src/qml/compiler/qv4compileddata_p.h
src/qml/compiler/qv4compiler.cpp
src/qml/compiler/qv4compiler_p.h
src/qml/compiler/qv4isel_masm.cpp
src/qml/compiler/qv4isel_p.h
src/qml/jsruntime/qv4debugging.cpp
src/qml/jsruntime/qv4function.cpp

index 08c4d80..6ac7a48 100644 (file)
@@ -50,11 +50,6 @@ namespace QV4 {
 
 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));
index e267f0f..0c5bf15 100644 (file)
@@ -141,6 +141,8 @@ struct Function
     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]
@@ -150,11 +152,11 @@ struct Function
 
     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
index d67b7de..7f2f611 100644 (file)
@@ -111,6 +111,11 @@ int QV4::Compiler::JSUnitGenerator::registerRegExp(QQmlJS::V4IR::RegExp *regexp)
     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);
@@ -128,7 +133,13 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit()
     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();
@@ -180,8 +191,8 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit()
         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);
@@ -194,9 +205,12 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit()
     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;
@@ -212,8 +226,15 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V
     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);
@@ -225,10 +246,16 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V
     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);
 }
 
 
index 753e462..1032369 100644 (file)
@@ -70,8 +70,11 @@ struct JSUnitGenerator {
 
     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;
@@ -79,6 +82,7 @@ struct JSUnitGenerator {
     QHash<QQmlJS::V4IR::Function *, uint> functionOffsets;
     QList<CompiledData::Lookup> lookups;
     QVector<CompiledData::RegExp> regexps;
+    QHash<QQmlJS::V4IR::Function *, QVector<uint> > lineNumberMappingsPerFunction;
 };
 
 }
index d93a67a..df5fa94 100644 (file)
@@ -586,13 +586,13 @@ JSC::MacroAssemblerCodeRef Assembler::link(QV4::Function *vmFunc)
     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) {
index 24ad581..3553d9d 100644 (file)
@@ -73,6 +73,7 @@ public:
     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);
index 5965af8..3bb0311 100644 (file)
@@ -350,10 +350,12 @@ void Debugger::BreakPoints::applyToFunction(Function *function, bool removeBreak
     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.
index 24ea1fb..b814637 100644 (file)
@@ -99,20 +99,42 @@ void Function::mark()
 }
 
 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