Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qv4compilercontrolflow_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 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// Qt-Security score:significant
4
5#ifndef QV4COMPILERCONTROLFLOW_P_H
6#define QV4COMPILERCONTROLFLOW_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <private/qv4codegen_p.h>
20#include <private/qqmljsast_p.h>
21#include <private/qv4bytecodegenerator_p.h>
22
23QT_BEGIN_NAMESPACE
24
25namespace QV4 {
26
27namespace Compiler {
28
33
41
47
52
56
57 ControlFlow(Codegen *cg, Type type)
58 : cg(cg), parent(cg->controlFlow), type(type)
59 {
60 cg->controlFlow = this;
61 }
62
63 virtual ~ControlFlow() {
64 cg->controlFlow = parent;
65 }
66
67 UnwindTarget unwindTarget(UnwindType type, const QString &label = QString())
68 {
69 Q_ASSERT(type == Break || type == Continue || type == Return);
70 ControlFlow *flow = this;
71 int level = 0;
72 while (flow) {
73 BytecodeGenerator::Label l = flow->getUnwindTarget(type, label);
74 if (l.isValid())
75 return UnwindTarget{l, level};
76 if (flow->requiresUnwind())
77 ++level;
78 flow = flow->parent;
79 }
80 if (type == Return)
81 return UnwindTarget{ cg->returnLabel(), level };
82 return UnwindTarget();
83 }
84
85 virtual QString label() const { return QString(); }
86
87 bool hasLoop() const {
88 const ControlFlow *flow = this;
89 while (flow) {
90 if (flow->type == Loop)
91 return true;
92 flow = flow->parent;
93 }
94 return false;
95 }
96
97protected:
98 virtual BytecodeGenerator::Label getUnwindTarget(UnwindType, const QString & = QString()) {
99 return BytecodeGenerator::Label();
100 }
101 virtual bool requiresUnwind() {
102 return false;
103 }
104
105public:
107 return parent ? parent->unwindHandler() : nullptr;
108 }
109
111 return parentUnwindHandler();
112 }
113
114
115protected:
117 QString label;
118 if (cg->_labelledStatement) {
119 label = cg->_labelledStatement->label.toString();
120 cg->_labelledStatement = nullptr;
121 }
122 return label;
123 }
125 return cg->bytecodeGenerator;
126 }
127};
128
130{
132
133 ControlFlowUnwind(Codegen *cg, Type type)
134 : ControlFlow(cg, type)
135 {
136 }
137
139 {
140 unwindLabel = generator()->newExceptionHandler();
141 }
142
144 {
145 Q_ASSERT(requiresUnwind());
146
147 Instruction::UnwindDispatch dispatch;
148 generator()->addInstruction(dispatch);
149 }
150
152 return unwindLabel.isValid() ? &unwindLabel : parentUnwindHandler();
153 }
154};
155
157{
158 std::function<void()> cleanup = nullptr;
159
160 ControlFlowUnwindCleanup(Codegen *cg, std::function<void()> cleanup, Type type = Block)
161 : ControlFlowUnwind(cg, type), cleanup(cleanup)
162 {
163 if (cleanup) {
165 generator()->setUnwindHandler(&unwindLabel);
166 }
167 }
168
170 if (cleanup) {
171 unwindLabel.link();
172 cleanup();
173 generator()->setUnwindHandler(parentUnwindHandler());
175 }
176 }
177
178 bool requiresUnwind() override {
179 return cleanup != nullptr;
180 }
181};
182
184{
188
189 ControlFlowLoop(Codegen *cg, BytecodeGenerator::Label *breakLabel, BytecodeGenerator::Label *continueLabel = nullptr, std::function<void()> cleanup = nullptr)
191 {
192 }
193
194 BytecodeGenerator::Label getUnwindTarget(UnwindType type, const QString &label) override {
195 switch (type) {
196 case Break:
197 if (breakLabel && (label.isEmpty() || label == loopLabel))
198 return *breakLabel;
199 break;
200 case Continue:
201 if (continueLabel && (label.isEmpty() || label == loopLabel))
202 return *continueLabel;
203 break;
204 default:
205 break;
206 }
207 return BytecodeGenerator::Label();
208 }
209
210 QString label() const override { return loopLabel; }
211};
212
213
215{
216 ControlFlowWith(Codegen *cg)
218 {
220
221 // assumes the with object is in the accumulator
222 Instruction::PushWithContext pushScope;
223 generator()->addInstruction(pushScope);
224 generator()->setUnwindHandler(&unwindLabel);
225 }
226
228 // emit code for unwinding
229 unwindLabel.link();
230
231 generator()->setUnwindHandler(parentUnwindHandler());
232 Instruction::PopContext pop;
233 generator()->addInstruction(pop);
234
236 }
237
238 bool requiresUnwind() override {
239 return true;
240 }
241
242
243};
244
246{
247 ControlFlowBlock(Codegen *cg, QQmlJS::AST::Node *ast)
249 {
250 block = cg->enterBlock(ast);
251 block->emitBlockHeader(cg);
252
253 if (block->requiresExecutionContext) {
255 generator()->setUnwindHandler(&unwindLabel);
256 }
257 }
258
259 virtual ~ControlFlowBlock() {
260 // emit code for unwinding
261 if (block->requiresExecutionContext) {
262 unwindLabel.link();
263 generator()->setUnwindHandler(parentUnwindHandler());
264 }
265
266 block->emitBlockFooter(cg);
267
268 if (block->requiresExecutionContext )
270 cg->leaveBlock();
271 }
272
273 virtual bool requiresUnwind() override {
274 return block->requiresExecutionContext;
275 }
276
278};
279
281{
283 bool insideCatch = false;
285
286 ControlFlowCatch(Codegen *cg, QQmlJS::AST::Catch *catchExpression)
289 {
290 generator()->setUnwindHandler(&exceptionLabel);
291 }
292
293 virtual bool requiresUnwind() override {
294 return true;
295 }
296
298 return insideCatch ? &unwindLabel : &exceptionLabel;
299 }
300
302 // emit code for unwinding
303 insideCatch = true;
305
306 Codegen::RegisterScope scope(cg);
307
308 // exceptions inside the try block go here
309 exceptionLabel.link();
310 BytecodeGenerator::Jump noException = generator()->jumpNoException();
311
312 Context *block = cg->enterBlock(catchExpression);
313
314 block->emitBlockHeader(cg);
315
316 generator()->setUnwindHandler(&unwindLabel);
317
318 if (catchExpression->patternElement->bindingIdentifier.isEmpty())
319 // destructuring pattern
320 cg->initializeAndDestructureBindingElement(catchExpression->patternElement, Reference::fromName(cg, QStringLiteral("@caught")));
321 // skip the additional block
322 cg->statementList(catchExpression->statement->statements);
323
324 // exceptions inside catch and break/return statements go here
325 unwindLabel.link();
326 block->emitBlockFooter(cg);
327
328 cg->leaveBlock();
329
330 noException.link();
331 generator()->setUnwindHandler(parentUnwindHandler());
332
334 insideCatch = false;
335 }
336};
337
339{
341 bool insideFinally = false;
342
343 ControlFlowFinally(Codegen *cg, QQmlJS::AST::Finally *finally, bool hasCatchBlock)
345 {
346 Q_ASSERT(finally != nullptr);
348
349 // No need to set the handler for the finally now if there is a catch block.
350 // In that case, a handler for the latter will be set immediately after this.
351 if (!hasCatchBlock) {
352 generator()->setUnwindHandler(&unwindLabel);
353 }
354 }
355
356 virtual bool requiresUnwind() override {
357 return !insideFinally;
358 }
359
361 return insideFinally ? parentUnwindHandler() : ControlFlowUnwind::unwindHandler();
362 }
363
365 // emit code for unwinding
366 unwindLabel.link();
367
368 Codegen::RegisterScope scope(cg);
369
370 insideFinally = true;
371 int returnValueTemp = -1;
372 if (cg->requiresReturnValue) {
373 returnValueTemp = generator()->newRegister();
374 Instruction::MoveReg move;
375 move.srcReg = cg->_returnAddress;
376 move.destReg = returnValueTemp;
377 generator()->addInstruction(move);
378 }
379 int exceptionTemp = generator()->newRegister();
380 Instruction::GetException instr;
381 generator()->addInstruction(instr);
382 Reference::fromStackSlot(cg, exceptionTemp).storeConsumeAccumulator();
383
384 generator()->setUnwindHandler(parentUnwindHandler());
385 cg->statement(finally->statement);
386 insideFinally = false;
387
388 if (cg->requiresReturnValue) {
389 Instruction::MoveReg move;
390 move.srcReg = returnValueTemp;
391 move.destReg = cg->_returnAddress;
392 generator()->addInstruction(move);
393 }
394 Reference::fromStackSlot(cg, exceptionTemp).loadInAccumulator();
395 Instruction::SetException setException;
396 generator()->addInstruction(setException);
397
399 }
400};
401
402} } // QV4::Compiler namespace
403
404QT_END_NAMESPACE
405
406#endif
Definition qjsvalue.h:24
ControlFlowBlock(Codegen *cg, QQmlJS::AST::Node *ast)
BytecodeGenerator::ExceptionHandler exceptionLabel
ControlFlowCatch(Codegen *cg, QQmlJS::AST::Catch *catchExpression)
BytecodeGenerator::ExceptionHandler * unwindHandler() override
BytecodeGenerator::ExceptionHandler * unwindHandler() override
ControlFlowFinally(Codegen *cg, QQmlJS::AST::Finally *finally, bool hasCatchBlock)
ControlFlowLoop(Codegen *cg, BytecodeGenerator::Label *breakLabel, BytecodeGenerator::Label *continueLabel=nullptr, std::function< void()> cleanup=nullptr)
BytecodeGenerator::Label * continueLabel
BytecodeGenerator::Label getUnwindTarget(UnwindType type, const QString &label) override
BytecodeGenerator::Label * breakLabel
ControlFlowUnwindCleanup(Codegen *cg, std::function< void()> cleanup, Type type=Block)
BytecodeGenerator::ExceptionHandler unwindLabel
virtual BytecodeGenerator::ExceptionHandler * unwindHandler() override
ControlFlow(Codegen *cg, Type type)
UnwindTarget unwindTarget(UnwindType type, const QString &label=QString())
virtual BytecodeGenerator::ExceptionHandler * unwindHandler()
BytecodeGenerator * generator() const
BytecodeGenerator::ExceptionHandler * parentUnwindHandler()
virtual BytecodeGenerator::Label getUnwindTarget(UnwindType, const QString &=QString())