ScummVM API documentation
coroutines.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef MTROPOLIS_COROUTINES_H
23 #define MTROPOLIS_COROUTINES_H
24 
25 #include "mtropolis/coroutine_protos.h"
26 #include "mtropolis/miniscript_protos.h"
27 #include "mtropolis/vthread.h"
28 
29 namespace MTropolis {
30 
31 struct CoroExecInstr;
32 struct CoroutineRuntimeState;
33 
34 typedef VThreadState (*CoroutineFragmentFunction_t)(CoroutineRuntimeState &coroState);
35 
38 
39  VThread *_vthread;
40  CoroutineStackFrame2 *_frame;
41  bool _condition;
42  MiniscriptInstructionOutcome _miniscriptOutcome;
43 
44 private:
45  CoroutineRuntimeState() = delete;
47  CoroutineRuntimeState &operator=(const CoroutineRuntimeState&) = delete;
48 };
49 
53 
54  CoroutineFrameConstructor_t _frameConstructor;
55  CoroutineGetFrameParametersFunction_t _getFrameParameters;
56  bool _isVoidReturn;
57 
58  CoroExecInstr *_instructions;
59  uint _numInstructions;
60 
61 private:
62  CompiledCoroutine(const CompiledCoroutine &) = delete;
63  CompiledCoroutine &operator =(const CompiledCoroutine &) = delete;
64 };
65 
67  explicit CoroutineStackFrame2(const CompiledCoroutine *compiledCoro);
68  virtual ~CoroutineStackFrame2();
69 
70  VThreadState execute(VThread *thread) override;
71 
72  const CompiledCoroutine *getCompiledCoroutine() const;
73 
74 private:
75  CoroutineStackFrame2() = delete;
77 
78  const CompiledCoroutine *_compiledCoro;
79  uint _nextInstr;
80 };
81 
82 enum class CoroOps {
83  Invalid = 0,
84 
85  BeginFunction,
86  EndFunction,
87 
88  IfCond,
89  IfBody,
90  Else,
91  ElseIfCond,
92  ElseIfBody,
93  EndIf,
94 
95  WhileCond,
96  WhileBody,
97  EndWhile,
98 
99  ForNext,
100  ForCond,
101  ForBody,
102  EndFor,
103 
104  Do,
105  DoWhile,
106  DoWhileCond,
107 
108  Return,
109 
110  Error,
111 
112  YieldToFunction,
113 
114  CheckMiniscript,
115 
116  Code,
117 };
118 
120  virtual ~ICoroutineCompiler();
121 
122  virtual void defineFunction(CoroutineFrameConstructor_t frameConstructor, CoroutineGetFrameParametersFunction_t frameGetParams) = 0;
123  virtual void addOp(CoroOps op, CoroutineFragmentFunction_t fragmentFunc) = 0;
124 };
125 
126 #define CORO_START_CODE_BLOCK(op) \
127  compiler->addOp(op, [](CoroutineRuntimeState &coroRuntime) -> VThreadState { \
128  Params *params = &static_cast<CoroStackFrame *>(coroRuntime._frame)->_params; \
129  Locals *locals = &static_cast<CoroStackFrame *>(coroRuntime._frame)->_locals; \
130  CoroutineReturnValueRef<ReturnValue_t> coroReturnValueRef = (static_cast<CoroStackFrame *>(coroRuntime._frame)->_rvRef);
131 
132 #define CORO_AWAIT_PUSHED_TASK \
133  return kVThreadReturn
134 
135 #define CORO_DISUSE_CODE_BLOCK_VARS \
136  (void)params; \
137  (void)locals; \
138  (void)coroReturnValueRef;
139 
140 #define CORO_END_CODE_BLOCK \
141  CORO_DISUSE_CODE_BLOCK_VARS \
142  return kVThreadReturn; \
143  });
144 
145 #define CORO_BEGIN_DEFINITION(type) \
146 CompiledCoroutine *type::ms_compiledCoro = nullptr;\
147 void type::compileCoroutine(ICoroutineCompiler *compiler) {
148 
149 #define CORO_END_DEFINITION \
150  }
151 
152 #define CORO_BEGIN_FUNCTION \
153  struct CoroStackFrame : public CoroutineStackFrame2 {\
154  Params _params;\
155  Locals _locals;\
156  CoroutineReturnValueRef<ReturnValue_t> _rvRef;\
157  explicit CoroStackFrame(const CompiledCoroutine *compiledCoro, const Params &params, const CoroutineReturnValueRef<ReturnValue_t> &rvRef)\
158  : CoroutineStackFrame2(compiledCoro), _params(params), _rvRef(rvRef) {\
159  }\
160  static CoroutineStackFrame2 *constructFrame(void *ptr, const CompiledCoroutine *compiledCoro, const CoroutineParamsBase &params, const CoroutineReturnValueRefBase &returnValueRef) {\
161  return new (ptr) CoroStackFrame(compiledCoro, static_cast<const Params &>(params), static_cast<const CoroutineReturnValueRef<ReturnValue_t>&>(returnValueRef));\
162  }\
163  static void getFrameParameters(size_t &outSize, size_t &outAlignment) { \
164  outSize = sizeof(CoroStackFrame); \
165  outAlignment = alignof(CoroStackFrame); \
166  }\
167  };\
168  compiler->defineFunction(CoroStackFrame::constructFrame, CoroStackFrame::getFrameParameters); \
169  CORO_START_CODE_BLOCK(CoroOps::BeginFunction)
170 
171 #define CORO_END_FUNCTION \
172  CORO_END_CODE_BLOCK \
173  CORO_START_CODE_BLOCK(CoroOps::EndFunction) \
174  CORO_END_CODE_BLOCK
175 
176 #define CORO_AWAIT(expr) \
177  (expr); \
178  CORO_END_CODE_BLOCK \
179  CORO_START_CODE_BLOCK(CoroOps::YieldToFunction) \
180  CORO_END_CODE_BLOCK \
181  CORO_START_CODE_BLOCK(CoroOps::Code)
182 
183 #define CORO_AWAIT_MINISCRIPT(expr) \
184  coroRuntime._miniscriptOutcome = ((expr)); \
185  CORO_END_CODE_BLOCK \
186  CORO_START_CODE_BLOCK(CoroOps::CheckMiniscript) \
187  CORO_END_CODE_BLOCK \
188  CORO_START_CODE_BLOCK(CoroOps::Code)
189 
190 #define CORO_IF(expr) \
191  CORO_END_CODE_BLOCK \
192  CORO_START_CODE_BLOCK(CoroOps::IfCond) \
193  coroRuntime._condition = !!(expr); \
194  CORO_END_CODE_BLOCK \
195  CORO_START_CODE_BLOCK(CoroOps::IfBody)
196 
197 #define CORO_ELSE \
198  CORO_END_CODE_BLOCK \
199  CORO_START_CODE_BLOCK(CoroOps::Else)
200 
201 #define CORO_ELSE_IF(expr) \
202  CORO_END_CODE_BLOCK \
203  CORO_START_CODE_BLOCK(CoroOps::ElseIfCond) \
204  coroRuntime._condition = !!(expr); \
205  CORO_END_CODE_BLOCK \
206  CORO_START_CODE_BLOCK(CoroOps::ElseIfBody)
207 
208 #define CORO_END_IF \
209  CORO_END_CODE_BLOCK \
210  CORO_START_CODE_BLOCK(CoroOps::EndIf)
211 
212 #define CORO_WHILE(expr) \
213  CORO_END_CODE_BLOCK \
214  CORO_START_CODE_BLOCK(CoroOps::WhileCond) \
215  coroRuntime._condition = !!(expr); \
216  CORO_END_CODE_BLOCK \
217  CORO_START_CODE_BLOCK(CoroOps::WhileBody)
218 
219 #define CORO_END_WHILE \
220  CORO_END_CODE_BLOCK \
221  CORO_START_CODE_BLOCK(CoroOps::EndWhile)
222 
223 #define CORO_DO \
224  CORO_END_CODE_BLOCK \
225  CORO_START_CODE_BLOCK(CoroOps::Do)
226 
227 #define CORO_DO_WHILE(expr) \
228  CORO_END_CODE_BLOCK \
229  CORO_START_CODE_BLOCK(CoroOps::DoWhileCond) \
230  coroCondition = !(expr); \
231  CORO_END_CODE_BLOCK \
232  CORO_START_CODE_BLOCK(CoroOps::DoWhile)
233 
234 #define CORO_FOR(initExpr, condExpr, nextExpr) \
235  (initExpr); \
236  CORO_END_CODE_BLOCK \
237  CORO_START_CODE_BLOCK(CoroOps::ForNext) \
238  (nextExpr); \
239  CORO_END_CODE_BLOCK \
240  CORO_START_CODE_BLOCK(CoroOps::ForCond) \
241  coroRuntime._condition = !!(condExpr); \
242  CORO_END_CODE_BLOCK \
243  CORO_START_CODE_BLOCK(CoroOps::ForBody)
244 
245 #define CORO_END_FOR \
246  CORO_END_CODE_BLOCK \
247  CORO_START_CODE_BLOCK(CoroOps::EndFor)
248 
249 #define CORO_RETURN_VALUE(expr) \
250  coroReturnValueRef.set((expr)); \
251  CORO_END_CODE_BLOCK \
252  CORO_START_CODE_BLOCK(CoroOps::Return)
253 
254 #define CORO_ERROR \
255  CORO_END_CODE_BLOCK \
256  CORO_START_CODE_BLOCK(CoroOps::Error)
257 
258 
259 #define CORO_RETURN \
260  coroReturnValueRef.voidSet(); \
261  CORO_END_CODE_BLOCK \
262  CORO_START_CODE_BLOCK(CoroOps::Return)
263 
264 #define CORO_RETURN_CALL(func, ...) \
265  coroFrame->pushFrame<CoroAutoFrame<func> >(coroReturnValueRef._returnValue, __VA_ARGS__); \
266  CORO_END_CODE_BLOCK \
267  CORO_START_CODE_BLOCK(CoroOps::YieldToFunction) \
268  CORO_END_CODE_BLOCK \
269  CORO_START_CODE_BLOCK(CoroOps::Return)
270 
271 #define CORO_SET_CALL(dest, func, ...) \
272  CORO_AWAIT(coroRuntime._vthread->pushCoroutineWithReturn<func>(&(dest), __VA_ARGS__))
273 
274 #define CORO_CALL(func, ...) \
275  CORO_AWAIT(coroRuntime._vthread->pushCoroutine<func>(__VA_ARGS__))
276 
277 } // Namespace MTropolis
278 
279 #endif
Definition: coroutines.h:66
Definition: coroutine_exec.h:42
Definition: coroutines.h:36
Definition: coroutines.h:119
Definition: coroutines.h:50
Definition: vthread.h:52
Definition: vthread.h:133
Definition: actions.h:25