Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qv4bytecodegenerator.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <private/qv4bytecodegenerator_p.h>
5#include <private/qv4compilercontext_p.h>
6#include <private/qqmljsastfwd_p.h>
7
9using namespace QV4;
10using namespace Moth;
11
13{
14 currentLine = static_cast<int>(loc.startLine);
15 currentSourceLocation = loc;
16}
17
19{
20 ++currentStatement;
21}
22
24{
25 int t = currentReg++;
26 if (regCount < currentReg)
27 regCount = currentReg;
28 return t;
29}
30
32{
33 int t = currentReg;
34 currentReg += n;
35 if (regCount < currentReg)
36 regCount = currentReg;
37 return t;
38}
39
40void BytecodeGenerator::packInstruction(I &i)
41{
45 int instructionsAsInts[sizeof(Instr)/sizeof(int)] = {};
46 int nMembers = Moth::InstrInfo::argumentCount[static_cast<int>(i.type)];
47 uchar *code = i.packed + Instr::encodedLength(type);
48 for (int j = 0; j < nMembers; ++j) {
49 instructionsAsInts[j] = qFromLittleEndian<qint32>(code + j * sizeof(int));
50 }
51 enum {
52 Normal,
53 Wide
54 } width = Normal;
55 for (int n = 0; n < nMembers; ++n) {
56 if (width == Normal && (static_cast<qint8>(instructionsAsInts[n]) != instructionsAsInts[n])) {
57 width = Wide;
58 break;
59 }
60 }
61 code = i.packed;
62 switch (width) {
63 case Normal:
64 code = Instr::pack(code, type);
65 for (int n = 0; n < nMembers; ++n) {
66 qint8 v = static_cast<qint8>(instructionsAsInts[n]);
67 memcpy(code, &v, 1);
68 code += 1;
69 }
70 i.size = code - i.packed;
71 if (i.offsetForJump != -1)
72 i.offsetForJump = i.size - 1;
73 break;
74 case Wide:
75 // nothing to do
76 break;
77 }
78}
79
80void BytecodeGenerator::adjustJumpOffsets()
81{
82 for (int index = 0; index < instructions.size(); ++index) {
83 auto &i = instructions[index];
84 if (i.offsetForJump == -1) // no jump
85 continue;
86 Q_ASSERT(i.linkedLabel != -1 && labels.at(i.linkedLabel) != -1);
87 const auto &linkedInstruction = instructions.at(labels.at(i.linkedLabel));
88 qint8 *c = reinterpret_cast<qint8*>(i.packed + i.offsetForJump);
89 int jumpOffset = linkedInstruction.position - (i.position + i.size);
90// qDebug() << "adjusting jump offset for instruction" << index << i.position << i.size << "offsetForJump" << i.offsetForJump << "target"
91// << labels.at(i.linkedLabel) << linkedInstruction.position << "jumpOffset" << jumpOffset;
93 if (Instr::isWide(type)) {
94 Q_ASSERT(i.offsetForJump == i.size - 4);
95 qToLittleEndian<qint32>(jumpOffset, c);
96 } else {
97 Q_ASSERT(i.offsetForJump == i.size - 1);
98 qint8 o = jumpOffset;
99 Q_ASSERT(o == jumpOffset);
100 *c = o;
101 }
102 }
103}
104
105void BytecodeGenerator::compressInstructions()
106{
107 // first round: compress all non jump instructions
108 int position = 0;
109 for (auto &i : instructions) {
110 i.position = position;
111 if (i.offsetForJump == -1)
112 packInstruction(i);
113 position += i.size;
114 }
115
116 adjustJumpOffsets();
117
118 // compress all jumps
119 position = 0;
120 for (auto &i : instructions) {
121 i.position = position;
122 if (i.offsetForJump != -1)
123 packInstruction(i);
124 position += i.size;
125 }
126
127 // adjust once again, as the packing above could have changed offsets
128 adjustJumpOffsets();
129}
130
132{
133 compressInstructions();
134
135 // collect content and line numbers
136 QByteArray code;
137 QVector<CompiledData::CodeOffsetToLineAndStatement> lineAndStatementNumbers;
138
139 currentLine = -1;
140 currentStatement = -1;
141
142 Q_UNUSED(startLine);
143 for (qsizetype i = 0; i < instructions.size(); i++) {
144 if (instructions[i].line != currentLine || instructions[i].statement != currentStatement) {
145 currentLine = instructions[i].line;
146 currentStatement = instructions[i].statement;
148 entry.codeOffset = code.size();
149 entry.line = currentLine;
150 entry.statement = currentStatement;
151 lineAndStatementNumbers.append(entry);
152 }
153
154 if (m_sourceLocationTable)
155 m_sourceLocationTable->entries[i].offset = static_cast<quint32>(code.size());
156
157 code.append(reinterpret_cast<const char *>(instructions[i].packed), instructions[i].size);
158 }
159
160 context->code = code;
161 context->lineAndStatementNumberMapping = lineAndStatementNumbers;
162 context->sourceLocationTable = std::move(m_sourceLocationTable);
163
164 context->labelInfo.reserve(context->labelInfo.size() + _labelInfos.size());
165 for (const auto &li : _labelInfos)
166 context->labelInfo.push_back(instructions.at(labels.at(li.labelIndex)).position);
167}
168
169int BytecodeGenerator::addInstructionHelper(Instr::Type type, const Instr &i, int offsetOfOffset) {
170 if (lastInstrType == int(Instr::Type::StoreReg)) {
171 if (type == Instr::Type::LoadReg) {
172 if (i.LoadReg.reg == lastInstr.StoreReg.reg) {
173 // value is already in the accumulator
174 return -1;
175 }
176 }
177 if (type == Instr::Type::MoveReg) {
178 if (i.MoveReg.srcReg == lastInstr.StoreReg.reg) {
179 Instruction::StoreReg store;
180 store.reg = i.MoveReg.destReg;
181 addInstruction(store);
182 return -1;
183 }
184 }
185 }
186 lastInstrType = int(type);
187 lastInstr = i;
188
189 if (debugMode && type != Instr::Type::Debug) {
191QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // broken gcc warns about Instruction::Debug()
192 if (instructions.isEmpty() || currentLine != instructions.constLast().line) {
193 addInstruction(Instruction::Debug());
194 } else if (type == Instr::Type::Ret) {
195 currentLine = -currentLine;
196 addInstruction(Instruction::Debug());
197 currentLine = -currentLine;
198 currentSourceLocation = QQmlJS::SourceLocation();
199 }
201 }
202
203 const int pos = instructions.size();
204
205 const int argCount = Moth::InstrInfo::argumentCount[static_cast<int>(type)];
206 int s = argCount*sizeof(int);
207 if (offsetOfOffset != -1)
208 offsetOfOffset += Instr::encodedLength(type);
209 I instr {
210 type,
211 static_cast<short>(s + Instr::encodedLength(type)),
212 0,
213 currentLine,
214 currentStatement,
215 offsetOfOffset,
216 -1,
217 "\0\0"
218 };
219 uchar *code = instr.packed;
221
222 for (int j = 0; j < argCount; ++j) {
223 qToLittleEndian<qint32>(i.argumentsAsInts[j], code);
224 code += sizeof(int);
225 }
226
227 instructions.append(instr);
228 if (m_sourceLocationTable)
229 m_sourceLocationTable->entries.append({ 0, currentSourceLocation });
230
231 return pos;
232}
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
QString & append(QChar c)
Definition qstring.cpp:3252
void setLocation(const QQmlJS::SourceLocation &loc)
void addInstruction(const InstrData< InstrT > &data)
void finalize(Compiler::Context *context)
static void * context
#define QT_WARNING_POP
#define QT_WARNING_DISABLE_GCC(text)
#define QT_WARNING_PUSH
GLsizei const GLfloat * v
[13]
GLuint index
[2]
GLint GLsizei width
GLenum type
GLfloat n
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLuint entry
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint GLenum GLsizei GLsizei GLint GLint GLboolean packed
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
unsigned char uchar
Definition qtypes.h:32
ptrdiff_t qsizetype
Definition qtypes.h:165
QT_BEGIN_NAMESPACE typedef signed char qint8
Definition qtypes.h:45
#define MOTH_NUM_INSTRUCTIONS()
if(qFloatDistance(a, b)<(1<< 7))
[0]
static const int argumentCount[]
static int encodedLength(Type t)
static Type wideInstructionType(Type t)
static Type unpack(const uchar *c)
static uchar * pack(uchar *c, Type t)
static bool isWide(Type t)
static Type narrowInstructionType(Type t)