Coverage Report

Created: 2025-09-04 07:34

/src/solidity/libsolidity/codegen/ir/IRGenerationContext.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
 * Class that contains contextual information during IR generation.
20
 */
21
22
#pragma once
23
24
#include <libsolidity/ast/AST.h>
25
#include <libsolidity/codegen/ir/IRVariable.h>
26
#include <libsolidity/interface/DebugSettings.h>
27
28
#include <libsolidity/codegen/MultiUseYulFunctionCollector.h>
29
#include <libsolidity/codegen/ir/Common.h>
30
31
#include <liblangutil/CharStreamProvider.h>
32
#include <liblangutil/DebugInfoSelection.h>
33
#include <liblangutil/EVMVersion.h>
34
35
#include <libsolutil/Common.h>
36
37
#include <set>
38
#include <string>
39
#include <memory>
40
#include <deque>
41
42
namespace solidity::frontend
43
{
44
45
class YulUtilFunctions;
46
class ABIFunctions;
47
48
using DispatchQueue = std::deque<FunctionDefinition const*>;
49
using InternalDispatchMap = std::map<YulArity, DispatchQueue>;
50
51
/**
52
 * Class that contains contextual information during IR generation.
53
 */
54
class IRGenerationContext
55
{
56
public:
57
  enum class ExecutionContext { Creation, Deployed };
58
59
  IRGenerationContext(
60
    langutil::EVMVersion _evmVersion,
61
    std::optional<uint8_t> _eofVersion,
62
    ExecutionContext _executionContext,
63
    RevertStrings _revertStrings,
64
    std::map<std::string, unsigned> _sourceIndices,
65
    langutil::DebugInfoSelection const& _debugInfoSelection,
66
    langutil::CharStreamProvider const* _soliditySourceProvider
67
  ):
68
    m_evmVersion(_evmVersion),
69
    m_eofVersion(_eofVersion),
70
    m_executionContext(_executionContext),
71
    m_revertStrings(_revertStrings),
72
    m_sourceIndices(std::move(_sourceIndices)),
73
    m_debugInfoSelection(_debugInfoSelection),
74
    m_soliditySourceProvider(_soliditySourceProvider)
75
14.2k
  {}
76
77
44.8k
  MultiUseYulFunctionCollector& functionCollector() { return m_functions; }
78
79
  /// Adds a Solidity function to the function generation queue and returns the name of the
80
  /// corresponding Yul function.
81
  std::string enqueueFunctionForCodeGeneration(FunctionDefinition const& _function);
82
83
  /// Pops one item from the function generation queue. Must not be called if the queue is empty.
84
  FunctionDefinition const* dequeueFunctionForCodeGeneration();
85
86
41.9k
  bool functionGenerationQueueEmpty() { return m_functionGenerationQueue.empty(); }
87
88
  /// Sets the most derived contract (the one currently being compiled)>
89
  void setMostDerivedContract(ContractDefinition const& _mostDerivedContract)
90
9.52k
  {
91
9.52k
    m_mostDerivedContract = &_mostDerivedContract;
92
9.52k
  }
93
  ContractDefinition const& mostDerivedContract() const;
94
95
96
  IRVariable const& addLocalVariable(VariableDeclaration const& _varDecl);
97
21.5k
  bool isLocalVariable(VariableDeclaration const& _varDecl) const { return m_localVariables.count(&_varDecl); }
98
  IRVariable const& localVariable(VariableDeclaration const& _varDecl);
99
  void resetLocalVariables();
100
101
  /// Registers an immutable variable of the contract.
102
  /// Should only be called at construction time.
103
  void registerImmutableVariable(VariableDeclaration const& _varDecl);
104
  void registerLibraryAddressImmutable();
105
  size_t libraryAddressImmutableOffset() const;
106
  size_t libraryAddressImmutableOffsetRelative() const;
107
  /// @returns the reserved memory for storing the value of the
108
  /// immutable @a _variable during contract creation.
109
  size_t immutableMemoryOffset(VariableDeclaration const& _variable) const;
110
  size_t immutableMemoryOffsetRelative(VariableDeclaration const& _variable) const;
111
  /// @returns the reserved memory and resets it to mark it as used.
112
  /// Intended to be used only once for initializing the free memory pointer
113
  /// to after the area used for immutables.
114
  size_t reservedMemory();
115
  size_t reservedMemorySize() const;
116
117
  void addStateVariable(VariableDeclaration const& _varDecl, u256 _storageOffset, unsigned _byteOffset);
118
13.2k
  bool isStateVariable(VariableDeclaration const& _varDecl) const { return m_stateVariables.count(&_varDecl); }
119
  std::pair<u256, unsigned> storageLocationOfStateVariable(VariableDeclaration const& _varDecl) const
120
6.79k
  {
121
6.79k
    solAssert(isStateVariable(_varDecl), "");
122
6.79k
    return m_stateVariables.at(&_varDecl);
123
6.79k
  }
124
125
  std::string newYulVariable();
126
127
  void initializeInternalDispatch(InternalDispatchMap _internalDispatchMap);
128
  InternalDispatchMap consumeInternalDispatchMap();
129
23.8k
  bool internalDispatchClean() const { return m_internalDispatchMap.empty(); }
130
131
  /// Notifies the context that a function call that needs to go through internal dispatch was
132
  /// encountered while visiting the AST. This ensures that the corresponding dispatch function
133
  /// gets added to the dispatch map even if there are no entries in it (which may happen if
134
  /// the code contains a call to an uninitialized function variable).
135
  void internalFunctionCalledThroughDispatch(YulArity const& _arity);
136
137
  /// Adds a function to the internal dispatch.
138
  void addToInternalDispatch(FunctionDefinition const& _function);
139
140
  /// @returns a new copy of the utility function generator (but using the same function set).
141
  YulUtilFunctions utils();
142
143
2.47k
  langutil::EVMVersion evmVersion() const { return m_evmVersion; }
144
11.5k
  std::optional<uint8_t> eofVersion() const { return m_eofVersion; }
145
23
  ExecutionContext executionContext() const { return m_executionContext; }
146
147
193
  void setArithmetic(Arithmetic _value) { m_arithmetic = _value; }
148
12.3k
  Arithmetic arithmetic() const { return m_arithmetic; }
149
150
  ABIFunctions abiFunctions();
151
152
20.5k
  RevertStrings revertStrings() const { return m_revertStrings; }
153
154
9.52k
  util::UniqueVector<ContractDefinition const*> const& subObjectsCreated() const { return m_subObjects; }
155
90
  void addSubObject(ContractDefinition const* _contractDefinition) { m_subObjects.pushBack(_contractDefinition); }
156
157
9.52k
  bool memoryUnsafeInlineAssemblySeen() const { return m_memoryUnsafeInlineAssemblySeen; }
158
64
  void setMemoryUnsafeInlineAssemblySeen() { m_memoryUnsafeInlineAssemblySeen = true; }
159
160
130k
  std::map<std::string, unsigned> const& sourceIndices() const { return m_sourceIndices; }
161
111k
  void markSourceUsed(std::string const& _name) { m_usedSourceNames.insert(_name); }
162
9.52k
  std::set<std::string> const& usedSourceNames() const { return m_usedSourceNames; }
163
164
0
  bool immutableRegistered(VariableDeclaration const& _varDecl) const { return m_immutableVariables.count(&_varDecl); }
165
166
135k
  langutil::DebugInfoSelection debugInfoSelection() const { return m_debugInfoSelection; }
167
121k
  langutil::CharStreamProvider const* soliditySourceProvider() const { return m_soliditySourceProvider; }
168
4.76k
  std::map<VariableDeclaration const*, size_t> const& immutableVariables() const { return m_immutableVariables; }
169
  void setImmutableVariables(std::map<VariableDeclaration const*, size_t> _immutableVariables)
170
0
  {
171
0
    solAssert(m_eofVersion.has_value());
172
0
    solAssert(m_executionContext == ExecutionContext::Deployed);
173
0
    m_immutableVariables = std::move(_immutableVariables);
174
0
  }
175
  void setLibraryAddressImmutableOffset(size_t _libraryAddressImmutableOffset)
176
0
  {
177
0
    solAssert(m_eofVersion.has_value());
178
0
    solAssert(m_executionContext == ExecutionContext::Deployed);
179
0
    m_libraryAddressImmutableOffset = _libraryAddressImmutableOffset;
180
0
  }
181
182
private:
183
  langutil::EVMVersion m_evmVersion;
184
  std::optional<uint8_t> m_eofVersion;
185
  ExecutionContext m_executionContext;
186
  RevertStrings m_revertStrings;
187
  std::map<std::string, unsigned> m_sourceIndices;
188
  std::set<std::string> m_usedSourceNames;
189
  ContractDefinition const* m_mostDerivedContract = nullptr;
190
  std::map<VariableDeclaration const*, IRVariable> m_localVariables;
191
  /// Memory offsets reserved for the values of immutable variables during contract creation.
192
  /// This map is empty in the legacy runtime context and may be not empty in EOF runtime context.
193
  std::map<VariableDeclaration const*, size_t> m_immutableVariables;
194
  std::optional<size_t> m_libraryAddressImmutableOffset;
195
  /// Total amount of reserved memory. Reserved memory is used to store
196
  /// immutable variables during contract creation.
197
  std::optional<size_t> m_reservedMemory = {0};
198
  /// Storage offsets of state variables
199
  std::map<VariableDeclaration const*, std::pair<u256, unsigned>> m_stateVariables;
200
  MultiUseYulFunctionCollector m_functions;
201
  size_t m_varCounter = 0;
202
  /// Whether to use checked or wrapping arithmetic.
203
  Arithmetic m_arithmetic = Arithmetic::Checked;
204
205
  /// Flag indicating whether any memory-unsafe inline assembly block was seen.
206
  bool m_memoryUnsafeInlineAssemblySeen = false;
207
208
  /// Function definitions queued for code generation. They're the Solidity functions whose calls
209
  /// were discovered by the IR generator during AST traversal.
210
  /// Note that the queue gets filled in a lazy way - new definitions can be added while the
211
  /// collected ones get removed and traversed.
212
  /// The order and duplicates are relevant here
213
  /// (see: IRGenerationContext::[enqueue|dequeue]FunctionForCodeGeneration)
214
  DispatchQueue m_functionGenerationQueue;
215
216
  /// Collection of functions that need to be callable via internal dispatch.
217
  /// Note that having a key with an empty set of functions is a valid situation. It means that
218
  /// the code contains a call via a pointer even though a specific function is never assigned to it.
219
  /// It will fail at runtime but the code must still compile.
220
  InternalDispatchMap m_internalDispatchMap;
221
222
  util::UniqueVector<ContractDefinition const*> m_subObjects;
223
224
  langutil::DebugInfoSelection m_debugInfoSelection = {};
225
  langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr;
226
};
227
228
}