/src/solidity/libsolidity/codegen/CompilerContext.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | This file is part of solidity. |
3 | | |
4 | | solidity is free software: you can redistribute it and/or modify |
5 | | it under the terms of the GNU General Public License as published by |
6 | | the Free Software Foundation, either version 3 of the License, or |
7 | | (at your option) any later version. |
8 | | |
9 | | solidity is distributed in the hope that it will be useful, |
10 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | GNU General Public License for more details. |
13 | | |
14 | | You should have received a copy of the GNU General Public License |
15 | | along with solidity. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | // SPDX-License-Identifier: GPL-3.0 |
18 | | /** |
19 | | * @author Christian <c@ethdev.com> |
20 | | * @date 2014 |
21 | | * Utilities for the solidity compiler. |
22 | | */ |
23 | | |
24 | | #pragma once |
25 | | |
26 | | #include <libsolidity/ast/ASTAnnotations.h> |
27 | | #include <libsolidity/ast/ASTForward.h> |
28 | | #include <libsolidity/ast/Types.h> |
29 | | #include <libsolidity/codegen/ABIFunctions.h> |
30 | | |
31 | | #include <libsolidity/interface/DebugSettings.h> |
32 | | #include <libsolidity/interface/OptimiserSettings.h> |
33 | | |
34 | | #include <libevmasm/Assembly.h> |
35 | | #include <libevmasm/Instruction.h> |
36 | | #include <liblangutil/ErrorReporter.h> |
37 | | #include <liblangutil/EVMVersion.h> |
38 | | #include <libsolutil/Common.h> |
39 | | #include <libsolutil/ErrorCodes.h> |
40 | | |
41 | | #include <libyul/AsmAnalysisInfo.h> |
42 | | #include <libyul/backends/evm/EVMDialect.h> |
43 | | |
44 | | #include <functional> |
45 | | #include <ostream> |
46 | | #include <stack> |
47 | | #include <queue> |
48 | | #include <utility> |
49 | | #include <limits> |
50 | | |
51 | | namespace solidity::frontend |
52 | | { |
53 | | |
54 | | class Compiler; |
55 | | |
56 | | /** |
57 | | * Context to be shared by all units that compile the same contract. |
58 | | * It stores the generated bytecode and the position of identifiers in memory and on the stack. |
59 | | */ |
60 | | class CompilerContext |
61 | | { |
62 | | public: |
63 | | explicit CompilerContext( |
64 | | langutil::EVMVersion _evmVersion, |
65 | | RevertStrings _revertStrings, |
66 | | CompilerContext* _runtimeContext = nullptr |
67 | | ): |
68 | | m_asm(std::make_shared<evmasm::Assembly>(_runtimeContext != nullptr, std::string{})), |
69 | | m_evmVersion(_evmVersion), |
70 | | m_revertStrings(_revertStrings), |
71 | | m_reservedMemory{0}, |
72 | | m_runtimeContext(_runtimeContext), |
73 | | m_abiFunctions(m_evmVersion, m_revertStrings, m_yulFunctionCollector), |
74 | | m_yulUtilFunctions(m_evmVersion, m_revertStrings, m_yulFunctionCollector) |
75 | 19.9k | { |
76 | 19.9k | if (m_runtimeContext) |
77 | 9.97k | m_runtimeSub = size_t(m_asm->newSub(m_runtimeContext->m_asm).data()); |
78 | 19.9k | } |
79 | | |
80 | 19.6k | langutil::EVMVersion const& evmVersion() const { return m_evmVersion; } |
81 | | |
82 | 42.5k | void setUseABICoderV2(bool _value) { m_useABICoderV2 = _value; } |
83 | 27.2k | bool useABICoderV2() const { return m_useABICoderV2; } |
84 | | |
85 | | void addStateVariable(VariableDeclaration const& _declaration, u256 const& _storageOffset, unsigned _byteOffset); |
86 | | void addImmutable(VariableDeclaration const& _declaration); |
87 | | |
88 | | /// @returns the reserved memory for storing the value of the immutable @a _variable during contract creation. |
89 | | size_t immutableMemoryOffset(VariableDeclaration const& _variable) const; |
90 | | /// @returns a list of slot names referring to the stack slots of an immutable variable. |
91 | | static std::vector<std::string> immutableVariableSlotNames(VariableDeclaration const& _variable); |
92 | | |
93 | | /// @returns the reserved memory and resets it to mark it as used. |
94 | | size_t reservedMemory(); |
95 | | |
96 | | void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0); |
97 | | void removeVariable(Declaration const& _declaration); |
98 | | /// Removes all local variables currently allocated above _stackHeight. |
99 | | void removeVariablesAboveStackHeight(unsigned _stackHeight); |
100 | | /// Returns the number of currently allocated local variables. |
101 | | unsigned numberOfLocalVariables() const; |
102 | | |
103 | 19.7k | void setOtherCompilers(std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> const& _otherCompilers) { m_otherCompilers = _otherCompilers; } |
104 | | std::shared_ptr<evmasm::Assembly> compiledContract(ContractDefinition const& _contract) const; |
105 | | std::shared_ptr<evmasm::Assembly> compiledContractRuntime(ContractDefinition const& _contract) const; |
106 | | |
107 | 33.0k | void setStackOffset(int _offset) { m_asm->setDeposit(_offset); } |
108 | 74.4k | void adjustStackOffset(int _adjustment) { m_asm->adjustDeposit(_adjustment); } |
109 | 191k | unsigned stackHeight() const { solAssert(m_asm->deposit() >= 0, ""); return unsigned(m_asm->deposit()); } |
110 | | |
111 | | bool isLocalVariable(Declaration const* _declaration) const; |
112 | 5.07k | bool isStateVariable(Declaration const* _declaration) const { return m_stateVariables.count(_declaration) != 0; } |
113 | | |
114 | | /// @returns the entry label of the given function and creates it if it does not exist yet. |
115 | | evmasm::AssemblyItem functionEntryLabel(Declaration const& _declaration); |
116 | | /// @returns the entry label of the given function. Might return an AssemblyItem of type |
117 | | /// UndefinedItem if it does not exist yet. |
118 | | evmasm::AssemblyItem functionEntryLabelIfExists(Declaration const& _declaration) const; |
119 | | /// @returns the function that overrides the given declaration from the most derived class just |
120 | | /// above _base in the current inheritance hierarchy. |
121 | | FunctionDefinition const& superFunction(FunctionDefinition const& _function, ContractDefinition const& _base); |
122 | | /// Sets the contract currently being compiled - the most derived one. |
123 | 19.7k | void setMostDerivedContract(ContractDefinition const& _contract) { m_mostDerivedContract = &_contract; } |
124 | | ContractDefinition const& mostDerivedContract() const; |
125 | | |
126 | 11.9k | void setArithmetic(Arithmetic _value) { m_arithmetic = _value; } |
127 | 24.4k | Arithmetic arithmetic() const { return m_arithmetic; } |
128 | | |
129 | | /// @returns the next function in the queue of functions that are still to be compiled |
130 | | /// (i.e. that were referenced during compilation but where we did not yet generate code for). |
131 | | /// Returns nullptr if the queue is empty. Does not remove the function from the queue, |
132 | | /// that will only be done by startFunction below. |
133 | | Declaration const* nextFunctionToCompile() const; |
134 | | /// Resets function specific members, inserts the function entry label and marks the function |
135 | | /// as "having code". |
136 | | void startFunction(Declaration const& _function); |
137 | | |
138 | | /// Appends a call to the named low-level function and inserts the generator into the |
139 | | /// list of low-level-functions to be generated, unless it already exists. |
140 | | /// Note that the generator should not assume that objects are still alive when it is called, |
141 | | /// unless they are guaranteed to be alive for the whole run of the compiler (AST nodes, for example). |
142 | | void callLowLevelFunction( |
143 | | std::string const& _name, |
144 | | unsigned _inArgs, |
145 | | unsigned _outArgs, |
146 | | std::function<void(CompilerContext&)> const& _generator |
147 | | ); |
148 | | |
149 | | /// Appends a call to a yul function and registers the function as externally used. |
150 | | void callYulFunction( |
151 | | std::string const& _name, |
152 | | unsigned _inArgs, |
153 | | unsigned _outArgs |
154 | | ); |
155 | | |
156 | | /// Returns the tag of the named low-level function and inserts the generator into the |
157 | | /// list of low-level-functions to be generated, unless it already exists. |
158 | | /// Note that the generator should not assume that objects are still alive when it is called, |
159 | | /// unless they are guaranteed to be alive for the whole run of the compiler (AST nodes, for example). |
160 | | evmasm::AssemblyItem lowLevelFunctionTag( |
161 | | std::string const& _name, |
162 | | unsigned _inArgs, |
163 | | unsigned _outArgs, |
164 | | std::function<void(CompilerContext&)> const& _generator |
165 | | ); |
166 | | /// Generates the code for missing low-level functions, i.e. calls the generators passed above. |
167 | | void appendMissingLowLevelFunctions(); |
168 | 13.4k | ABIFunctions& abiFunctions() { return m_abiFunctions; } |
169 | 23.5k | YulUtilFunctions& utilFunctions() { return m_yulUtilFunctions; } |
170 | | |
171 | | /// Appends concatenation of all generated Yul functions to the bytecode |
172 | | /// and stores the Yul source code to be returned by @a generatedYulUtilityCode. |
173 | | /// Should be called exactly once on each context. |
174 | | void appendYulUtilityFunctions(OptimiserSettings const& _optimiserSettings); |
175 | 19.7k | bool appendYulUtilityFunctionsRan() const { return m_appendYulUtilityFunctionsRan; } |
176 | 0 | std::string const& generatedYulUtilityCode() const { return m_generatedYulUtilityCode; } |
177 | 12.2k | static std::string yulUtilityFileName() { return "#utility.yul"; } |
178 | | |
179 | | /// Returns the distance of the given local variable from the bottom of the stack (of the current function). |
180 | | unsigned baseStackOffsetOfVariable(Declaration const& _declaration) const; |
181 | | /// If supplied by a value returned by @ref baseStackOffsetOfVariable(variable), returns |
182 | | /// the distance of that variable from the current top of the stack. |
183 | | unsigned baseToCurrentStackOffset(unsigned _baseOffset) const; |
184 | | /// Converts an offset relative to the current stack height to a value that can be used later |
185 | | /// with baseToCurrentStackOffset to point to the same stack element. |
186 | | unsigned currentToBaseStackOffset(unsigned _offset) const; |
187 | | /// @returns pair of slot and byte offset of the value inside this slot. |
188 | | std::pair<u256, unsigned> storageLocationOfVariable(Declaration const& _declaration) const; |
189 | | |
190 | | /// Appends a JUMPI instruction to a new tag and @returns the tag |
191 | 15.7k | evmasm::AssemblyItem appendConditionalJump() { return m_asm->appendJumpI().tag(); } |
192 | | /// Appends a JUMPI instruction to @a _tag |
193 | 22.4k | CompilerContext& appendConditionalJumpTo(evmasm::AssemblyItem const& _tag) { m_asm->appendJumpI(_tag); return *this; } |
194 | | /// Appends a JUMP to a new tag and @returns the tag |
195 | 10.2k | evmasm::AssemblyItem appendJumpToNew() { return m_asm->appendJump().tag(); } |
196 | | /// Appends a JUMP to a tag already on the stack |
197 | | CompilerContext& appendJump(evmasm::AssemblyItem::JumpType _jumpType = evmasm::AssemblyItem::JumpType::Ordinary); |
198 | | /// Appends code to revert with a Panic(uint256) error. |
199 | | CompilerContext& appendPanic(util::PanicCode _code); |
200 | | /// Appends code to revert with a Panic(uint256) error if the topmost stack element is nonzero. |
201 | | CompilerContext& appendConditionalPanic(util::PanicCode _code); |
202 | | /// Appends a REVERT(0, 0) call |
203 | | /// @param _message is an optional revert message used in debug mode |
204 | | CompilerContext& appendRevert(std::string const& _message = ""); |
205 | | /// Appends a conditional REVERT-call, either forwarding the RETURNDATA or providing the |
206 | | /// empty string. Consumes the condition. |
207 | | /// If the current EVM version does not support RETURNDATA, uses REVERT but does not forward |
208 | | /// the data. |
209 | | /// @param _message is an optional revert message used in debug mode |
210 | | CompilerContext& appendConditionalRevert(bool _forwardReturnData = false, std::string const& _message = ""); |
211 | | /// Appends a JUMP to a specific tag |
212 | | CompilerContext& appendJumpTo( |
213 | | evmasm::AssemblyItem const& _tag, |
214 | | evmasm::AssemblyItem::JumpType _jumpType = evmasm::AssemblyItem::JumpType::Ordinary |
215 | 57.6k | ) { *m_asm << _tag.pushTag(); return appendJump(_jumpType); } |
216 | | /// Appends pushing of a new tag and @returns the new tag. |
217 | 49.1k | evmasm::AssemblyItem pushNewTag() { return m_asm->append(m_asm->newPushTag()).tag(); } |
218 | | /// @returns a new tag without pushing any opcodes or data |
219 | 39.2k | evmasm::AssemblyItem newTag() { return m_asm->newTag(); } |
220 | | /// @returns a new tag identified by name. |
221 | | evmasm::AssemblyItem namedTag(std::string const& _name, size_t _params, size_t _returns, std::optional<uint64_t> _sourceID) |
222 | 49.5k | { |
223 | 49.5k | return m_asm->namedTag(_name, _params, _returns, _sourceID); |
224 | 49.5k | } |
225 | | /// Adds a subroutine to the code (in the data section) and pushes its size (via a tag) |
226 | | /// on the stack. @returns the pushsub assembly item. |
227 | 143 | evmasm::AssemblyItem addSubroutine(evmasm::AssemblyPointer const& _assembly) { return m_asm->appendSubroutine(_assembly); } |
228 | | /// Pushes the size of the subroutine. |
229 | 10.1k | void pushSubroutineSize(size_t _subRoutine) { m_asm->pushSubroutineSize(_subRoutine); } |
230 | | /// Pushes the offset of the subroutine. |
231 | 9.89k | void pushSubroutineOffset(size_t _subRoutine) { m_asm->pushSubroutineOffset(_subRoutine); } |
232 | | /// Pushes the size of the final program |
233 | 1.02k | void appendProgramSize() { m_asm->appendProgramSize(); } |
234 | | /// Adds data to the data section, pushes a reference to the stack |
235 | 542 | evmasm::AssemblyItem appendData(bytes const& _data) { return m_asm->append(_data); } |
236 | | /// Appends the address (virtual, will be filled in by linker) of a library. |
237 | 102 | void appendLibraryAddress(std::string const& _identifier) { m_asm->appendLibraryAddress(_identifier); } |
238 | | /// Appends an immutable variable. The value will be filled in by the constructor. |
239 | 80 | void appendImmutable(std::string const& _identifier) { m_asm->appendImmutable(_identifier); } |
240 | | /// Appends an assignment to an immutable variable. Only valid in creation code. |
241 | 374 | void appendImmutableAssignment(std::string const& _identifier) { m_asm->appendImmutableAssignment(_identifier); } |
242 | | /// Appends a zero-address that can be replaced by something else at deploy time (if the |
243 | | /// position in bytecode is known). |
244 | 217 | void appendDeployTimeAddress() { m_asm->append(evmasm::PushDeployTimeAddress); } |
245 | | /// Resets the stack of visited nodes with a new stack having only @c _node |
246 | | void resetVisitedNodes(ASTNode const* _node); |
247 | | /// Pops the stack of visited nodes |
248 | 213k | void popVisitedNodes() { m_visitedNodes.pop(); updateSourceLocation(); } |
249 | | /// Pushes an ASTNode to the stack of visited nodes |
250 | 213k | void pushVisitedNodes(ASTNode const* _node) { m_visitedNodes.push(_node); updateSourceLocation(); } |
251 | | |
252 | | /// Append elements to the current instruction list and adjust @a m_stackOffset. |
253 | 199k | CompilerContext& operator<<(evmasm::AssemblyItem const& _item) { m_asm->append(_item); return *this; } |
254 | 704k | CompilerContext& operator<<(evmasm::Instruction _instruction) { m_asm->append(_instruction); return *this; } |
255 | 257k | CompilerContext& operator<<(u256 const& _value) { m_asm->append(_value); return *this; } |
256 | 0 | CompilerContext& operator<<(bytes const& _data) { m_asm->append(_data); return *this; } |
257 | | |
258 | | /// Appends inline assembly (strict-EVM dialect for the current version). |
259 | | /// @param _assembly the assembly text, should be a block. |
260 | | /// @param _localVariables assigns stack positions to variables with the last one being the stack top |
261 | | /// @param _externallyUsedFunctions a set of function names that are not to be renamed or removed. |
262 | | /// @param _system if true, this is a "system-level" assembly where all functions use named labels |
263 | | /// and the code is marked to be exported as "compiler-generated assembly utility file". |
264 | | /// @param _optimiserSettings settings for the Yul optimiser, which is run in this function already. |
265 | | /// @param _sourceName the name of the assembly file to be used for source locations |
266 | | void appendInlineAssembly( |
267 | | std::string const& _assembly, |
268 | | std::vector<std::string> const& _localVariables = std::vector<std::string>(), |
269 | | std::set<std::string> const& _externallyUsedFunctions = std::set<std::string>(), |
270 | | bool _system = false, |
271 | | OptimiserSettings const& _optimiserSettings = OptimiserSettings::none(), |
272 | | std::string _sourceName = "--CODEGEN--" |
273 | | ); |
274 | | |
275 | | /// If m_revertStrings is debug, @returns inline assembly code that |
276 | | /// stores @param _message at the free memory pointer and reverts. |
277 | | /// Otherwise returns "revert(0, 0)". |
278 | | std::string revertReasonIfDebug(std::string const& _message = ""); |
279 | | |
280 | | void optimizeYul(yul::Object& _object, yul::EVMDialect const& _dialect, OptimiserSettings const& _optimiserSetting, std::set<yul::YulString> const& _externalIdentifiers = {}); |
281 | | |
282 | | /// Appends arbitrary data to the end of the bytecode. |
283 | 9.97k | void appendToAuxiliaryData(bytes const& _data) { m_asm->appendToAuxiliaryData(_data); } |
284 | | |
285 | | /// Run optimisation step. |
286 | 9.89k | void optimise(OptimiserSettings const& _settings) { m_asm->optimise(translateOptimiserSettings(_settings)); } |
287 | | |
288 | | /// @returns the runtime context if in creation mode and runtime context is set, nullptr otherwise. |
289 | 24.3k | CompilerContext* runtimeContext() const { return m_runtimeContext; } |
290 | | /// @returns the identifier of the runtime subroutine. |
291 | 39.8k | size_t runtimeSub() const { return m_runtimeSub; } |
292 | | |
293 | | /// @returns a const reference to the underlying assembly. |
294 | 0 | evmasm::Assembly const& assembly() const { return *m_asm; } |
295 | | /// @returns a shared pointer to the assembly. |
296 | | /// Should be avoided except when adding sub-assemblies. |
297 | 20.6k | std::shared_ptr<evmasm::Assembly> assemblyPtr() const { return m_asm; } |
298 | | |
299 | | /** |
300 | | * Helper class to pop the visited nodes stack when a scope closes |
301 | | */ |
302 | | class LocationSetter: public ScopeGuard |
303 | | { |
304 | | public: |
305 | | LocationSetter(CompilerContext& _compilerContext, ASTNode const& _node): |
306 | 199k | ScopeGuard([&]{ _compilerContext.popVisitedNodes(); }) { _compilerContext.pushVisitedNodes(&_node); } |
307 | | }; |
308 | | |
309 | 45.4k | void setModifierDepth(size_t _modifierDepth) { m_asm->m_currentModifierDepth = _modifierDepth; } |
310 | | |
311 | 511 | RevertStrings revertStrings() const { return m_revertStrings; } |
312 | | |
313 | | private: |
314 | | /// Updates source location set in the assembly. |
315 | | void updateSourceLocation(); |
316 | | |
317 | | evmasm::Assembly::OptimiserSettings translateOptimiserSettings(OptimiserSettings const& _settings); |
318 | | |
319 | | /** |
320 | | * Helper class that manages function labels and ensures that referenced functions are |
321 | | * compiled in a specific order. |
322 | | */ |
323 | | struct FunctionCompilationQueue |
324 | | { |
325 | | /// @returns the entry label of the given function and creates it if it does not exist yet. |
326 | | /// @param _context compiler context used to create a new tag if needed |
327 | | evmasm::AssemblyItem entryLabel(Declaration const& _declaration, CompilerContext& _context); |
328 | | /// @returns the entry label of the given function. Might return an AssemblyItem of type |
329 | | /// UndefinedItem if it does not exist yet. |
330 | | evmasm::AssemblyItem entryLabelIfExists(Declaration const& _declaration) const; |
331 | | |
332 | | /// @returns the next function in the queue of functions that are still to be compiled |
333 | | /// (i.e. that were referenced during compilation but where we did not yet generate code for). |
334 | | /// Returns nullptr if the queue is empty. Does not remove the function from the queue, |
335 | | /// that will only be done by startFunction below. |
336 | | Declaration const* nextFunctionToCompile() const; |
337 | | /// Informs the queue that we are about to compile the given function, i.e. removes |
338 | | /// the function from the queue of functions to compile. |
339 | | void startFunction(Declaration const& _function); |
340 | | |
341 | | /// Labels pointing to the entry points of functions. |
342 | | std::map<Declaration const*, evmasm::AssemblyItem> m_entryLabels; |
343 | | /// Set of functions for which we did not yet generate code. |
344 | | std::set<Declaration const*> m_alreadyCompiledFunctions; |
345 | | /// Queue of functions that still need to be compiled (important to be a queue to maintain |
346 | | /// determinism even in the presence of a non-deterministic allocator). |
347 | | /// Mutable because we will throw out some functions earlier than needed. |
348 | | mutable std::queue<Declaration const*> m_functionsToCompile; |
349 | | } m_functionCompilationQueue; |
350 | | |
351 | | evmasm::AssemblyPointer m_asm; |
352 | | /// Version of the EVM to compile against. |
353 | | langutil::EVMVersion m_evmVersion; |
354 | | RevertStrings const m_revertStrings; |
355 | | bool m_useABICoderV2 = false; |
356 | | /// Other already compiled contracts to be used in contract creation calls. |
357 | | std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> m_otherCompilers; |
358 | | /// Storage offsets of state variables |
359 | | std::map<Declaration const*, std::pair<u256, unsigned>> m_stateVariables; |
360 | | /// Memory offsets reserved for the values of immutable variables during contract creation. |
361 | | std::map<VariableDeclaration const*, size_t> m_immutableVariables; |
362 | | /// Total amount of reserved memory. Reserved memory is used to store immutable variables during contract creation. |
363 | | /// This has to be finalized before initialiseFreeMemoryPointer() is called. That function |
364 | | /// will reset the optional to verify that. |
365 | | std::optional<size_t> m_reservedMemory = {0}; |
366 | | /// Offsets of local variables on the stack (relative to stack base). |
367 | | /// This needs to be a stack because if a modifier contains a local variable and this |
368 | | /// modifier is applied twice, the position of the variable needs to be restored |
369 | | /// after the nested modifier is left. |
370 | | std::map<Declaration const*, std::vector<unsigned>> m_localVariables; |
371 | | /// The contract currently being compiled. Virtual function lookup starts from this contarct. |
372 | | ContractDefinition const* m_mostDerivedContract = nullptr; |
373 | | /// Whether to use checked arithmetic. |
374 | | Arithmetic m_arithmetic = Arithmetic::Checked; |
375 | | /// Stack of current visited AST nodes, used for location attachment |
376 | | std::stack<ASTNode const*> m_visitedNodes; |
377 | | /// The runtime context if in Creation mode, this is used for generating tags that would be stored into the storage and then used at runtime. |
378 | | CompilerContext *m_runtimeContext; |
379 | | /// The index of the runtime subroutine. |
380 | | size_t m_runtimeSub = std::numeric_limits<size_t>::max(); |
381 | | /// An index of low-level function labels by name. |
382 | | std::map<std::string, evmasm::AssemblyItem> m_lowLevelFunctions; |
383 | | /// Collector for yul functions. |
384 | | MultiUseYulFunctionCollector m_yulFunctionCollector; |
385 | | /// Set of externally used yul functions. |
386 | | std::set<std::string> m_externallyUsedYulFunctions; |
387 | | /// Generated Yul code used as utility. Source references from the bytecode can point here. |
388 | | /// Produced from @a m_yulFunctionCollector. |
389 | | std::string m_generatedYulUtilityCode; |
390 | | /// Container for ABI functions to be generated. |
391 | | ABIFunctions m_abiFunctions; |
392 | | /// Container for Yul Util functions to be generated. |
393 | | YulUtilFunctions m_yulUtilFunctions; |
394 | | /// The queue of low-level functions to generate. |
395 | | std::queue<std::tuple<std::string, unsigned, unsigned, std::function<void(CompilerContext&)>>> m_lowLevelFunctionGenerationQueue; |
396 | | /// Flag to check that appendYulUtilityFunctions() was called exactly once |
397 | | bool m_appendYulUtilityFunctionsRan = false; |
398 | | }; |
399 | | |
400 | | } |