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

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