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#ifndef QV4BYTECODEGENERATOR_P_H
5#define QV4BYTECODEGENERATOR_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17#include <private/qv4instr_moth_p.h>
18#include <private/qv4compileddata_p.h>
19#include <private/qv4compilercontext_p.h>
20#include <private/qqmljssourcelocation_p.h>
21
22#include <memory>
23
24QT_BEGIN_NAMESPACE
25
26namespace QQmlJS {
27class SourceLocation;
28}
29
30namespace QV4 {
31
32namespace Compiler {
33struct Context;
34}
35
36namespace Moth {
37
38class BytecodeGenerator {
39public:
40 BytecodeGenerator(int line, bool debug, bool storeSourceLocation = false)
41 : startLine(line), debugMode(debug)
42 {
43 if (storeSourceLocation)
44 m_sourceLocationTable.reset(p: new QV4::Compiler::Context::SourceLocationTable {});
45 }
46
47 struct Label {
48 enum LinkMode {
49 LinkNow,
50 LinkLater
51 };
52 Label() = default;
53 Label(BytecodeGenerator *generator, LinkMode mode = LinkNow)
54 : generator(generator),
55 index(generator->labels.size()) {
56 generator->labels.append(t: -1);
57 if (mode == LinkNow)
58 link();
59 }
60
61 void link() const {
62 Q_ASSERT(index >= 0);
63 Q_ASSERT(generator->labels[index] == -1);
64 generator->labels[index] = generator->instructions.size();
65 generator->clearLastInstruction();
66 }
67 bool isValid() const { return generator != nullptr; }
68
69 BytecodeGenerator *generator = nullptr;
70 int index = -1;
71 };
72
73 struct Jump {
74 Jump(BytecodeGenerator *generator, int instruction)
75 : generator(generator),
76 index(instruction)
77 { Q_ASSERT(generator && index != -1); }
78
79 ~Jump() {
80 Q_ASSERT(index == -1 || generator->instructions[index].linkedLabel != -1); // make sure link() got called
81 }
82
83 Jump(Jump &&j) {
84 std::swap(a&: generator, b&: j.generator);
85 std::swap(a&: index, b&: j.index);
86 }
87
88 BytecodeGenerator *generator = nullptr;
89 int index = -1;
90
91 void link() {
92 link(l: generator->label());
93 }
94 void link(Label l) {
95 Q_ASSERT(l.index >= 0);
96 Q_ASSERT(generator->instructions[index].linkedLabel == -1);
97 generator->instructions[index].linkedLabel = l.index;
98 }
99
100 private:
101 // make this type move-only:
102 Q_DISABLE_COPY(Jump)
103 // we never move-assign this type anywhere, so disable it:
104 Jump &operator=(Jump &&) = delete;
105 };
106
107 struct ExceptionHandler : public Label {
108 ExceptionHandler() = default;
109 ExceptionHandler(BytecodeGenerator *generator)
110 : Label(generator, LinkLater)
111 {
112 }
113 ~ExceptionHandler()
114 {
115 Q_ASSERT(!generator || generator->currentExceptionHandler != this);
116 }
117 ExceptionHandler(const ExceptionHandler &) = default;
118 ExceptionHandler(ExceptionHandler &&) = default;
119 ExceptionHandler &operator=(const ExceptionHandler &) = default;
120 ExceptionHandler &operator=(ExceptionHandler &&) = default;
121 bool isValid() const { return generator != nullptr; }
122 };
123
124 Label label() {
125 return Label(this, Label::LinkNow);
126 }
127
128 Label newLabel() {
129 return Label(this, Label::LinkLater);
130 }
131
132 ExceptionHandler newExceptionHandler() {
133 return ExceptionHandler(this);
134 }
135
136 template<int InstrT>
137 void addInstruction(const InstrData<InstrT> &data)
138 {
139 Instr genericInstr;
140 InstrMeta<InstrT>::setData(genericInstr, data);
141 addInstructionHelper(type: Moth::Instr::Type(InstrT), i: genericInstr);
142 }
143
144 Q_REQUIRED_RESULT Jump jump()
145 {
146QT_WARNING_PUSH
147QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // broken gcc warns about Instruction::Debug()
148 Instruction::Jump data;
149 return addJumpInstruction(data);
150QT_WARNING_POP
151 }
152
153 Q_REQUIRED_RESULT Jump jumpTrue()
154 {
155 return addJumpInstruction(data: Instruction::JumpTrue());
156 }
157
158 Q_REQUIRED_RESULT Jump jumpFalse()
159 {
160 return addJumpInstruction(data: Instruction::JumpFalse());
161 }
162
163 Q_REQUIRED_RESULT Jump jumpNotUndefined()
164 {
165 Instruction::JumpNotUndefined data{};
166 return addJumpInstruction(data);
167 }
168
169 Q_REQUIRED_RESULT Jump jumpNoException()
170 {
171 Instruction::JumpNoException data{};
172 return addJumpInstruction(data);
173 }
174
175 Q_REQUIRED_RESULT Jump jumpOptionalLookup(int index)
176 {
177 Instruction::GetOptionalLookup data{};
178 data.index = index;
179 return addJumpInstruction(data);
180 }
181
182 Q_REQUIRED_RESULT Jump jumpOptionalProperty(int name)
183 {
184 Instruction::LoadOptionalProperty data{};
185 data.name = name;
186 return addJumpInstruction(data);
187 }
188
189 void jumpStrictEqual(const StackSlot &lhs, const Label &target)
190 {
191 Instruction::CmpStrictEqual cmp;
192 cmp.lhs = lhs;
193 addInstruction(data: std::move(cmp));
194 addJumpInstruction(data: Instruction::JumpTrue()).link(l: target);
195 }
196
197 void jumpStrictNotEqual(const StackSlot &lhs, const Label &target)
198 {
199 Instruction::CmpStrictNotEqual cmp;
200 cmp.lhs = lhs;
201 addInstruction(data: std::move(cmp));
202 addJumpInstruction(data: Instruction::JumpTrue()).link(l: target);
203 }
204
205 void checkException()
206 {
207 Instruction::CheckException chk;
208 addInstruction(data: chk);
209 }
210
211 void setUnwindHandler(ExceptionHandler *handler)
212 {
213 currentExceptionHandler = handler;
214 Instruction::SetUnwindHandler data;
215 data.offset = 0;
216 if (!handler)
217 addInstruction(data);
218 else
219 addJumpInstruction(data).link(l: *handler);
220 }
221
222 void unwindToLabel(int level, const Label &target)
223 {
224 if (level) {
225 Instruction::UnwindToLabel unwind;
226 unwind.level = level;
227 addJumpInstruction(data: unwind).link(l: target);
228 } else {
229 jump().link(l: target);
230 }
231 }
232
233
234
235 void setLocation(const QQmlJS::SourceLocation &loc);
236 void incrementStatement();
237
238 ExceptionHandler *exceptionHandler() const {
239 return currentExceptionHandler;
240 }
241
242 int newRegister();
243 int newRegisterArray(int n);
244 int registerCount() const { return regCount; }
245 int currentRegister() const { return currentReg; }
246
247 void finalize(Compiler::Context *context);
248
249 template<int InstrT>
250 Jump addJumpInstruction(const InstrData<InstrT> &data)
251 {
252 Instr genericInstr;
253 InstrMeta<InstrT>::setData(genericInstr, data);
254 return Jump(this, addInstructionHelper(type: Moth::Instr::Type(InstrT), i: genericInstr, offsetof(InstrData<InstrT>, offset)));
255 }
256
257 void addCJumpInstruction(bool jumpOnFalse, const Label *trueLabel, const Label *falseLabel)
258 {
259 if (jumpOnFalse)
260 addJumpInstruction(data: Instruction::JumpFalse()).link(l: *falseLabel);
261 else
262 addJumpInstruction(data: Instruction::JumpTrue()).link(l: *trueLabel);
263 }
264
265 void clearLastInstruction()
266 {
267 lastInstrType = -1;
268 }
269
270 void addLoopStart(const Label &start)
271 {
272 _labelInfos.push_back(x: { .labelIndex: start.index });
273 }
274
275private:
276 friend struct Jump;
277 friend struct Label;
278 friend struct ExceptionHandler;
279
280 int addInstructionHelper(Moth::Instr::Type type, const Instr &i, int offsetOfOffset = -1);
281
282 struct I {
283 Moth::Instr::Type type;
284 short size;
285 uint position;
286 int line;
287 int statement;
288 int offsetForJump;
289 int linkedLabel;
290 unsigned char packed[sizeof(Instr) + 2]; // 2 for instruction type
291 };
292
293 void compressInstructions();
294 void packInstruction(I &i);
295 void adjustJumpOffsets();
296
297 QVector<I> instructions;
298 QVector<int> labels;
299 ExceptionHandler *currentExceptionHandler = nullptr;
300 int regCount = 0;
301public:
302 int currentReg = 0;
303private:
304 int startLine = 0;
305 int currentLine = 0;
306 int currentStatement = 0;
307 QQmlJS::SourceLocation currentSourceLocation;
308 std::unique_ptr<QV4::Compiler::Context::SourceLocationTable> m_sourceLocationTable;
309 bool debugMode = false;
310
311 int lastInstrType = -1;
312 Moth::Instr lastInstr;
313
314 struct LabelInfo {
315 int labelIndex;
316 };
317 std::vector<LabelInfo> _labelInfos;
318};
319
320}
321}
322
323QT_END_NAMESPACE
324
325#endif
326

source code of qtdeclarative/src/qml/compiler/qv4bytecodegenerator_p.h