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(
321 catchExpression->patternElement,
322 Reference::fromName(cg, QStringLiteral("@caught")), true);
323 }
324 // skip the additional block
325 cg->statementList(catchExpression->statement->statements);
326
327 // exceptions inside catch and break/return statements go here
328 unwindLabel.link();
329 block->emitBlockFooter(cg);
330
331 cg->leaveBlock();
332
333 noException.link();
334 generator()->setUnwindHandler(parentUnwindHandler());
335
337 insideCatch = false;
338 }
339};
340
342{
344 bool insideFinally = false;
345
346 ControlFlowFinally(Codegen *cg, QQmlJS::AST::Finally *finally, bool hasCatchBlock)
348 {
349 Q_ASSERT(finally != nullptr);
351
352 // No need to set the handler for the finally now if there is a catch block.
353 // In that case, a handler for the latter will be set immediately after this.
354 if (!hasCatchBlock) {
355 generator()->setUnwindHandler(&unwindLabel);
356 }
357 }
358
359 virtual bool requiresUnwind() override {
360 return !insideFinally;
361 }
362
364 return insideFinally ? parentUnwindHandler() : ControlFlowUnwind::unwindHandler();
365 }
366
368 // emit code for unwinding
369 unwindLabel.link();
370
371 Codegen::RegisterScope scope(cg);
372
373 insideFinally = true;
374 int returnValueTemp = -1;
375 if (cg->requiresReturnValue) {
376 returnValueTemp = generator()->newRegister();
377 Instruction::MoveReg move;
378 move.srcReg = cg->_returnAddress;
379 move.destReg = returnValueTemp;
380 generator()->addInstruction(move);
381 }
382 int exceptionTemp = generator()->newRegister();
383 Instruction::GetException instr;
384 generator()->addInstruction(instr);
385 Reference::fromStackSlot(cg, exceptionTemp).storeConsumeAccumulator();
386
387 generator()->setUnwindHandler(parentUnwindHandler());
388 cg->statement(finally->statement);
389 insideFinally = false;
390
391 if (cg->requiresReturnValue) {
392 Instruction::MoveReg move;
393 move.srcReg = returnValueTemp;
394 move.destReg = cg->_returnAddress;
395 generator()->addInstruction(move);
396 }
397 Reference::fromStackSlot(cg, exceptionTemp).loadInAccumulator();
398 Instruction::SetException setException;
399 generator()->addInstruction(setException);
400
402 }
403};
404
405} } // QV4::Compiler namespace
406
407QT_END_NAMESPACE
408
409#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())