aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-09-29 13:30:42 +0200
committerUlf Hermann <ulf.hermann@qt.io>2022-10-13 22:13:12 +0200
commitae49af00b59628623bc15e19974ee5af5f0121ba (patch)
tree91488d095e7a5b52bb1b8df05e56fb668039ea7b
parent9cfc19faf5d1ce2b9626914ab4528998b072385d (diff)
QML: Track the statement indices together with line numbers
We will need the statement indices when tracking value type references. New value type references shall only be written back in the same statement they were created in. Task-number: QTBUG-99766 Change-Id: I83f908df034e7da8ba46ccacaa29bd9d78020d20 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r--src/qml/common/qv4compileddata_p.h46
-rw-r--r--src/qml/compiler/qv4bytecodegenerator.cpp30
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h3
-rw-r--r--src/qml/compiler/qv4codegen.cpp4
-rw-r--r--src/qml/compiler/qv4compiler.cpp20
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h2
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp11
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h11
-rw-r--r--src/qml/jsruntime/qv4stackframe.cpp36
-rw-r--r--src/qml/jsruntime/qv4stackframe_p.h1
-rw-r--r--src/qmlcompiler/qqmljscodegenerator.cpp8
11 files changed, 123 insertions, 49 deletions
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index ff08f03683..f87578daa1 100644
--- a/src/qml/common/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -43,7 +43,7 @@ QT_BEGIN_NAMESPACE
// Also change the comment behind the number to describe the latest change. This has the added
// benefit that if another patch changes the version too, it will result in a merge conflict, and
// not get removed silently.
-#define QV4_DATA_STRUCTURE_VERSION 0x38 // Added context to translation data
+#define QV4_DATA_STRUCTURE_VERSION 0x39 // Changed CodeOffsetToLine(AndStatement) struct
class QIODevice;
class QQmlTypeNameCache;
@@ -237,11 +237,12 @@ struct String
static_assert (sizeof (String) == 4, "String structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-struct CodeOffsetToLine {
+struct CodeOffsetToLineAndStatement {
quint32_le codeOffset;
- quint32_le line;
+ qint32_le line; // signed because debug instructions get negative line numbers
+ quint32_le statement;
};
-static_assert(sizeof(CodeOffsetToLine) == 8, "CodeOffsetToLine 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(CodeOffsetToLineAndStatement) == 12, "CodeOffsetToLineAndStatement structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Block
{
@@ -325,8 +326,8 @@ struct Function
ParameterType returnType;
quint32_le localsOffset;
quint16_le nLocals;
- quint16_le nLineNumbers;
- size_t lineNumberOffset() const { return localsOffset + nLocals * sizeof(quint32); }
+ quint16_le nLineAndStatementNumbers;
+ size_t lineAndStatementNumberOffset() const { return localsOffset + nLocals * sizeof(quint32); }
quint32_le nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers
quint32_le nRegisters;
@@ -337,7 +338,10 @@ struct Function
quint16_le firstTemporalDeadZoneRegister;
quint16_le sizeOfRegisterTemporalDeadZone;
- size_t labelInfosOffset() const { return lineNumberOffset() + nLineNumbers * sizeof(CodeOffsetToLine); }
+ size_t labelInfosOffset() const
+ {
+ return lineAndStatementNumberOffset() + nLineAndStatementNumbers * sizeof(CodeOffsetToLineAndStatement);
+ }
// Keep all unaligned data at the end
quint8 flags;
@@ -346,9 +350,21 @@ struct Function
// quint32 formalsIndex[nFormals]
// quint32 localsIndex[nLocals]
- const Parameter *formalsTable() const { return reinterpret_cast<const Parameter *>(reinterpret_cast<const char *>(this) + formalsOffset); }
- const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
- const CodeOffsetToLine *lineNumberTable() const { return reinterpret_cast<const CodeOffsetToLine *>(reinterpret_cast<const char *>(this) + lineNumberOffset()); }
+ const Parameter *formalsTable() const
+ {
+ return reinterpret_cast<const Parameter *>(
+ reinterpret_cast<const char *>(this) + formalsOffset);
+ }
+ const quint32_le *localsTable() const
+ {
+ return reinterpret_cast<const quint32_le *>(
+ reinterpret_cast<const char *>(this) + localsOffset);
+ }
+ const CodeOffsetToLineAndStatement *lineAndStatementNumberTable() const
+ {
+ return reinterpret_cast<const CodeOffsetToLineAndStatement *>(
+ reinterpret_cast<const char *>(this) + lineAndStatementNumberOffset());
+ }
// --- QQmlPropertyCacheCreator interface
const Parameter *formalsBegin() const { return formalsTable(); }
@@ -359,9 +375,13 @@ struct Function
const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; }
- static int calculateSize(int nFormals, int nLocals, int nLines, int nInnerfunctions, int labelInfoSize, int codeSize) {
- int trailingData = nFormals * sizeof(Parameter) + (nLocals + nInnerfunctions + labelInfoSize)*sizeof (quint32)
- + nLines*sizeof(CodeOffsetToLine);
+ static int calculateSize(
+ int nFormals, int nLocals, int nLinesAndStatements, int nInnerfunctions,
+ int labelInfoSize, int codeSize)
+ {
+ int trailingData = nFormals * sizeof(Parameter)
+ + (nLocals + nInnerfunctions + labelInfoSize) * sizeof (quint32)
+ + nLinesAndStatements * sizeof(CodeOffsetToLineAndStatement);
size_t size = align(align(sizeof(Function)) + size_t(trailingData)) + align(codeSize);
Q_ASSERT(size < INT_MAX);
return int(size);
diff --git a/src/qml/compiler/qv4bytecodegenerator.cpp b/src/qml/compiler/qv4bytecodegenerator.cpp
index 8f0518093a..b88c83512f 100644
--- a/src/qml/compiler/qv4bytecodegenerator.cpp
+++ b/src/qml/compiler/qv4bytecodegenerator.cpp
@@ -15,6 +15,11 @@ void BytecodeGenerator::setLocation(const QQmlJS::SourceLocation &loc)
currentSourceLocation = loc;
}
+void BytecodeGenerator::incrementStatement()
+{
+ ++currentStatement;
+}
+
int BytecodeGenerator::newRegister()
{
int t = currentReg++;
@@ -129,17 +134,21 @@ void BytecodeGenerator::finalize(Compiler::Context *context)
// collect content and line numbers
QByteArray code;
- QVector<CompiledData::CodeOffsetToLine> lineNumbers;
+ QVector<CompiledData::CodeOffsetToLineAndStatement> lineAndStatementNumbers;
currentLine = -1;
+ currentStatement = -1;
+
Q_UNUSED(startLine);
for (qsizetype i = 0; i < instructions.size(); i++) {
- if (instructions[i].line != currentLine) {
+ if (instructions[i].line != currentLine || instructions[i].statement != currentStatement) {
currentLine = instructions[i].line;
- CompiledData::CodeOffsetToLine entry;
+ currentStatement = instructions[i].statement;
+ CompiledData::CodeOffsetToLineAndStatement entry;
entry.codeOffset = code.size();
entry.line = currentLine;
- lineNumbers.append(entry);
+ entry.statement = currentStatement;
+ lineAndStatementNumbers.append(entry);
}
if (m_sourceLocationTable)
@@ -149,7 +158,7 @@ void BytecodeGenerator::finalize(Compiler::Context *context)
}
context->code = code;
- context->lineNumberMapping = lineNumbers;
+ context->lineAndStatementNumberMapping = lineAndStatementNumbers;
context->sourceLocationTable = std::move(m_sourceLocationTable);
context->labelInfo.reserve(context->labelInfo.size() + _labelInfos.size());
@@ -197,7 +206,16 @@ QT_WARNING_POP
int s = argCount*sizeof(int);
if (offsetOfOffset != -1)
offsetOfOffset += Instr::encodedLength(type);
- I instr{type, static_cast<short>(s + Instr::encodedLength(type)), 0, currentLine, offsetOfOffset, -1, "\0\0" };
+ I instr {
+ type,
+ static_cast<short>(s + Instr::encodedLength(type)),
+ 0,
+ currentLine,
+ currentStatement,
+ offsetOfOffset,
+ -1,
+ "\0\0"
+ };
uchar *code = instr.packed;
code = Instr::pack(code, Instr::wideInstructionType(type));
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index 85d260ed7b..35e539fb5e 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -229,6 +229,7 @@ QT_WARNING_POP
void setLocation(const QQmlJS::SourceLocation &loc);
+ void incrementStatement();
ExceptionHandler *exceptionHandler() const {
return currentExceptionHandler;
@@ -279,6 +280,7 @@ private:
short size;
uint position;
int line;
+ int statement;
int offsetForJump;
int linkedLabel;
unsigned char packed[sizeof(Instr) + 2]; // 2 for instruction type
@@ -297,6 +299,7 @@ public:
private:
int startLine = 0;
int currentLine = 0;
+ int currentStatement = 0;
QQmlJS::SourceLocation currentSourceLocation;
std::unique_ptr<QV4::Compiler::Context::SourceLocationTable> m_sourceLocationTable;
bool debugMode = false;
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 9b0efcba41..2f5a9bd55f 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -373,6 +373,7 @@ void Codegen::statement(Statement *ast)
{
RegisterScope scope(this);
+ bytecodeGenerator->incrementStatement();
bytecodeGenerator->setLocation(ast->firstSourceLocation());
VolatileMemoryLocations vLocs = scanVolatileMemoryLocations(ast);
@@ -388,6 +389,7 @@ void Codegen::statement(ExpressionNode *ast)
} else {
RegisterScope scope(this);
+ bytecodeGenerator->incrementStatement();
pushExpr(Result(nx));
VolatileMemoryLocations vLocs = scanVolatileMemoryLocations(ast);
qSwap(_volatileMemoryLocations, vLocs);
@@ -3382,7 +3384,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, AST::FormalPara
qDebug() << "=== Bytecode for" << _context->name << "strict mode" << _context->isStrict
<< "register count" << _context->registerCountInFunction << "implicit return" << requiresReturnValue;
QV4::Moth::dumpBytecode(_context->code, _context->locals.size(), _context->arguments.size(),
- _context->line, _context->lineNumberMapping);
+ _context->line, _context->lineAndStatementNumberMapping);
qDebug();
}
}
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index bb5c7d109f..e1e26715cd 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -424,9 +424,11 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->localsOffset = currentOffset;
currentOffset += function->nLocals * sizeof(quint32);
- function->nLineNumbers = irFunction->lineNumberMapping.size();
- Q_ASSERT(function->lineNumberOffset() == currentOffset);
- currentOffset += function->nLineNumbers * sizeof(CompiledData::CodeOffsetToLine);
+ function->nLineAndStatementNumbers
+ = irFunction->lineAndStatementNumberMapping.size();
+ Q_ASSERT(function->lineAndStatementNumberOffset() == currentOffset);
+ currentOffset += function->nLineAndStatementNumbers
+ * sizeof(CompiledData::CodeOffsetToLineAndStatement);
function->nRegisters = irFunction->registerCountInFunction;
@@ -453,8 +455,11 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
for (int i = 0; i < irFunction->locals.size(); ++i)
locals[i] = getStringId(irFunction->locals.at(i));
- // write line numbers
- memcpy(f + function->lineNumberOffset(), irFunction->lineNumberMapping.constData(), irFunction->lineNumberMapping.size()*sizeof(CompiledData::CodeOffsetToLine));
+ // write line and statement numbers
+ memcpy(f + function->lineAndStatementNumberOffset(),
+ irFunction->lineAndStatementNumberMapping.constData(),
+ irFunction->lineAndStatementNumberMapping.size()
+ * sizeof(CompiledData::CodeOffsetToLineAndStatement));
quint32_le *labels = (quint32_le *)(f + function->labelInfosOffset());
for (unsigned u : irFunction->labelInfo) {
@@ -658,8 +663,9 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
Context *f = module->functions.at(i);
blockAndFunctionOffsets[i] = nextOffset;
- quint32 size = QV4::CompiledData::Function::calculateSize(f->arguments.size(), f->locals.size(), f->lineNumberMapping.size(), f->nestedContexts.size(),
- int(f->labelInfo.size()), f->code.size());
+ quint32 size = QV4::CompiledData::Function::calculateSize(
+ f->arguments.size(), f->locals.size(), f->lineAndStatementNumberMapping.size(),
+ f->nestedContexts.size(), int(f->labelInfo.size()), f->code.size());
functionSize += size - f->code.size();
nextOffset += size;
}
diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h
index 3e80079b9a..e0f3547d0b 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -184,7 +184,7 @@ struct Context {
ControlFlow *controlFlow = nullptr;
QByteArray code;
- QVector<CompiledData::CodeOffsetToLine> lineNumberMapping;
+ QVector<CompiledData::CodeOffsetToLineAndStatement> lineAndStatementNumberMapping;
std::unique_ptr<SourceLocationTable> sourceLocationTable;
std::vector<unsigned> labelInfo;
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index bdd6ee683a..03ca29f1e1 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -106,11 +106,13 @@ QString dumpArguments(int argc, int argv, int nFormals)
return QStringLiteral("(") + dumpRegister(argv, nFormals) + QStringLiteral(", ") + QString::number(argc) + QStringLiteral(")");
}
-void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*startLine*/, const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping)
+void dumpBytecode(
+ const char *code, int len, int nLocals, int nFormals, int /*startLine*/,
+ const QVector<CompiledData::CodeOffsetToLineAndStatement> &lineAndStatementNumberMapping)
{
MOTH_JUMP_TABLE;
- auto findLine = [](const CompiledData::CodeOffsetToLine &entry, uint offset) {
+ auto findLine = [](const CompiledData::CodeOffsetToLineAndStatement &entry, uint offset) {
return entry.codeOffset < offset;
};
@@ -118,7 +120,10 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
const char *start = code;
const char *end = code + len;
while (code < end) {
- const auto codeToLine = std::lower_bound(lineNumberMapping.constBegin(), lineNumberMapping.constEnd(), static_cast<uint>(code - start) + 1, findLine) - 1;
+ const auto codeToLine = std::lower_bound(
+ lineAndStatementNumberMapping.constBegin(),
+ lineAndStatementNumberMapping.constEnd(),
+ static_cast<uint>(code - start) + 1, findLine) - 1;
int line = int(codeToLine->line);
if (line != lastLine)
lastLine = line;
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 75408fd348..5b6d676782 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -474,7 +474,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace CompiledData {
-struct CodeOffsetToLine;
+struct CodeOffsetToLineAndStatement;
}
namespace Moth {
@@ -500,10 +500,13 @@ inline bool operator!=(const StackSlot &l, const StackSlot &r) { return l.stackS
// When making changes to the instructions, make sure to bump QV4_DATA_STRUCTURE_VERSION in qv4compileddata_p.h
void dumpBytecode(const char *bytecode, int len, int nLocals, int nFormals, int startLine = 1,
- const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping = QVector<CompiledData::CodeOffsetToLine>());
+ const QVector<CompiledData::CodeOffsetToLineAndStatement> &lineAndStatementNumberMapping
+ = QVector<CompiledData::CodeOffsetToLineAndStatement>());
inline void dumpBytecode(const QByteArray &bytecode, int nLocals, int nFormals, int startLine = 1,
- const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping = QVector<CompiledData::CodeOffsetToLine>()) {
- dumpBytecode(bytecode.constData(), bytecode.size(), nLocals, nFormals, startLine, lineNumberMapping);
+ const QVector<CompiledData::CodeOffsetToLineAndStatement> &lineAndStatementNumberMapping
+ = QVector<CompiledData::CodeOffsetToLineAndStatement>()) {
+ dumpBytecode(bytecode.constData(), bytecode.size(), nLocals, nFormals, startLine,
+ lineAndStatementNumberMapping);
}
union Instr
diff --git a/src/qml/jsruntime/qv4stackframe.cpp b/src/qml/jsruntime/qv4stackframe.cpp
index a02ce0edc5..e8ff9a89bc 100644
--- a/src/qml/jsruntime/qv4stackframe.cpp
+++ b/src/qml/jsruntime/qv4stackframe.cpp
@@ -17,21 +17,37 @@ QString CppStackFrame::function() const
return v4Function ? v4Function->name()->toQString() : QString();
}
-int CppStackFrame::lineNumber() const
+static const CompiledData::CodeOffsetToLineAndStatement *lineAndStatement(const CppStackFrame *frame)
{
- if (!v4Function || instructionPointer <= 0)
- return -1;
+ if (!frame->v4Function || frame->instructionPointer <= 0)
+ return nullptr;
- auto findLine = [](const CompiledData::CodeOffsetToLine &entry, uint offset) {
+ auto findLine = [](const CompiledData::CodeOffsetToLineAndStatement &entry, uint offset) {
return entry.codeOffset < offset;
};
- const QV4::CompiledData::Function *cf = v4Function->compiledFunction;
- const uint offset = instructionPointer;
- const CompiledData::CodeOffsetToLine *lineNumbers = cf->lineNumberTable();
- const uint nLineNumbers = cf->nLineNumbers;
- const CompiledData::CodeOffsetToLine *line = std::lower_bound(lineNumbers, lineNumbers + nLineNumbers, offset, findLine) - 1;
- return line->line;
+ const QV4::CompiledData::Function *cf = frame->v4Function->compiledFunction;
+ const uint offset = frame->instructionPointer;
+ const CompiledData::CodeOffsetToLineAndStatement *lineAndStatementNumbers
+ = cf->lineAndStatementNumberTable();
+ const uint nLineAndStatementNumbers = cf->nLineAndStatementNumbers;
+ return std::lower_bound(
+ lineAndStatementNumbers, lineAndStatementNumbers + nLineAndStatementNumbers,
+ offset, findLine) - 1;
+}
+
+int CppStackFrame::lineNumber() const
+{
+ if (auto *line = lineAndStatement(this))
+ return line->line;
+ return -1;
+}
+
+int CppStackFrame::statementNumber() const
+{
+ if (auto *statement = lineAndStatement(this))
+ return statement->statement;
+ return -1;
}
ReturnedValue QV4::CppStackFrame::thisObject() const
diff --git a/src/qml/jsruntime/qv4stackframe_p.h b/src/qml/jsruntime/qv4stackframe_p.h
index b9d57d5f54..2777d79c31 100644
--- a/src/qml/jsruntime/qv4stackframe_p.h
+++ b/src/qml/jsruntime/qv4stackframe_p.h
@@ -81,6 +81,7 @@ struct Q_QML_PRIVATE_EXPORT CppStackFrame : protected CppStackFrameBase
QString source() const;
QString function() const;
int lineNumber() const;
+ int statementNumber() const;
CppStackFrame *parentFrame() const { return parent; }
void setParentFrame(CppStackFrame *parentFrame) { parent = parentFrame; }
diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp
index 3fc818531c..e84456907e 100644
--- a/src/qmlcompiler/qqmljscodegenerator.cpp
+++ b/src/qmlcompiler/qqmljscodegenerator.cpp
@@ -2897,15 +2897,15 @@ QString QQmlJSCodeGenerator::conversion(const QQmlJSScope::ConstPtr &from,
int QQmlJSCodeGenerator::nextJSLine(uint line) const
{
- auto findLine = [](uint line, const QV4::CompiledData::CodeOffsetToLine &entry) {
+ auto findLine = [](int line, const QV4::CompiledData::CodeOffsetToLineAndStatement &entry) {
return entry.line > line;
};
const auto codeToLine
- = std::upper_bound(m_context->lineNumberMapping.constBegin(),
- m_context->lineNumberMapping.constEnd(),
+ = std::upper_bound(m_context->lineAndStatementNumberMapping.constBegin(),
+ m_context->lineAndStatementNumberMapping.constEnd(),
line,
findLine);
- bool bNoNextLine = m_context->lineNumberMapping.constEnd() == codeToLine;
+ bool bNoNextLine = m_context->lineAndStatementNumberMapping.constEnd() == codeToLine;
return static_cast<int>(bNoNextLine ? -1 : codeToLine->line);
}