/src/solidity/libsolidity/codegen/CompilerUtils.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 | | * Routines used by both the compiler and the expression compiler. |
22 | | */ |
23 | | |
24 | | #pragma once |
25 | | |
26 | | #include <libsolidity/ast/ASTForward.h> |
27 | | #include <libsolidity/ast/TypeProvider.h> |
28 | | #include <libsolidity/interface/DebugSettings.h> |
29 | | #include <libsolidity/codegen/CompilerContext.h> |
30 | | #include <libsolidity/codegen/CompilerContext.h> |
31 | | |
32 | | namespace solidity::frontend |
33 | | { |
34 | | |
35 | | class Type; // forward |
36 | | |
37 | | class CompilerUtils |
38 | | { |
39 | | public: |
40 | | explicit CompilerUtils(CompilerContext& _context): m_context(_context) |
41 | 10.1M | {} |
42 | | |
43 | | /// Stores the initial value of the free-memory-pointer at its position; |
44 | | void initialiseFreeMemoryPointer(); |
45 | | /// Copies the free memory pointer to the stack. |
46 | | /// Stack pre: |
47 | | /// Stack post: <mem_start> |
48 | | void fetchFreeMemoryPointer(); |
49 | | /// Stores the free memory pointer from the stack. |
50 | | /// Stack pre: <mem_end> |
51 | | /// Stack post: |
52 | | void storeFreeMemoryPointer(); |
53 | | /// Allocates a number of bytes in memory as given on the stack. |
54 | | /// Stack pre: <size> |
55 | | /// Stack post: <mem_start> |
56 | | void allocateMemory(); |
57 | | /// Allocates a number of bytes in memory as given on the stack. |
58 | | /// Stack pre: |
59 | | /// Stack post: <mem_start> |
60 | | void allocateMemory(u256 const& size); |
61 | | /// Appends code that transforms memptr to (memptr - free_memptr) memptr |
62 | | /// Stack pre: <mem_end> |
63 | | /// Stack post: <size> <mem_start> |
64 | | void toSizeAfterFreeMemoryPointer(); |
65 | | |
66 | | /// Appends code that performs a revert, providing the given string data. |
67 | | /// Will also append an error signature corresponding to Error(string). |
68 | | /// @param _argumentType the type of the string argument, will be converted to memory string. |
69 | | /// Stack pre: string data |
70 | | /// Stack post: |
71 | | void revertWithStringData(Type const& _argumentType); |
72 | | |
73 | | void revertWithError( |
74 | | std::string const& _errorName, |
75 | | std::vector<Type const*> const& _parameterTypes, |
76 | | std::vector<Type const*> const& _argumentTypes |
77 | | ); |
78 | | |
79 | | /// Allocates a new array and copies the return data to it. |
80 | | /// If the EVM does not support return data, creates an empty array. |
81 | | void returnDataToArray(); |
82 | | |
83 | | /// Computes the absolute calldata offset of a tail given a base reference and the (absolute) |
84 | | /// offset of the tail pointer. Performs bounds checks. If @a _type is a dynamically sized array it also |
85 | | /// returns the array length on the stack. |
86 | | /// Stack pre: base_ref tail_ptr |
87 | | /// Stack post: tail_ref [length] |
88 | | void accessCalldataTail(Type const& _type); |
89 | | |
90 | | /// Loads data from memory to the stack. |
91 | | /// @param _offset offset in memory (or calldata) |
92 | | /// @param _type data type to load |
93 | | /// @param _fromCalldata if true, load from calldata, not from memory |
94 | | /// @param _padToWords if true, assume the data is padded to full words (32 bytes) |
95 | | /// @returns the number of bytes consumed in memory. |
96 | | unsigned loadFromMemory( |
97 | | unsigned _offset, |
98 | | Type const& _type, |
99 | | bool _fromCalldata, |
100 | | bool _padToWords |
101 | | ); |
102 | | /// Dynamic version of @see loadFromMemory, expects the memory offset on the stack. |
103 | | /// Stack pre: memory_offset |
104 | | /// Stack post: value... (memory_offset+length) |
105 | | void loadFromMemoryDynamic( |
106 | | Type const& _type, |
107 | | bool _fromCalldata = false, |
108 | | bool _padToWords = true, |
109 | | bool _keepUpdatedMemoryOffset = true |
110 | | ); |
111 | | /// Stores a 256 bit integer from stack in memory. |
112 | | /// @param _offset offset in memory |
113 | | void storeInMemory(unsigned _offset); |
114 | | |
115 | | /// Dynamic version of @see storeInMemory, expects the memory offset below the value on the stack |
116 | | /// and also updates that. For reference types, only copies the data pointer. Fails for |
117 | | /// non-memory-references. For string literals no value is available on the stack. |
118 | | /// @param _padToWords if true, adds zeros to pad to multiple of 32 bytes. Array elements |
119 | | /// are always padded (except for byte arrays), regardless of this parameter. |
120 | | /// @param _cleanup if true, adds code to cleanup the value before storing it. |
121 | | /// Stack pre: memory_offset value... |
122 | | /// Stack post: (memory_offset+length) |
123 | | void storeInMemoryDynamic(Type const& _type, bool _padToWords = true, bool _cleanup = true); |
124 | | |
125 | | /// Creates code that unpacks the arguments according to their types specified by a vector of TypePointers. |
126 | | /// From memory if @a _fromMemory is true, otherwise from call data. |
127 | | /// Calls revert if the supplied size is shorter than the static data requirements |
128 | | /// or if dynamic data pointers reach outside of the area. |
129 | | /// Also has a hard cap of 0x100000000 for any given length/offset field. |
130 | | /// Stack pre: <source_offset> <length> |
131 | | /// Stack post: <value0> <value1> ... <valuen> |
132 | | void abiDecode(TypePointers const& _typeParameters, bool _fromMemory = false); |
133 | | |
134 | | /// Copies values (of types @a _givenTypes) given on the stack to a location in memory given |
135 | | /// at the stack top, encoding them according to the ABI as the given types @a _targetTypes. |
136 | | /// Removes the values from the stack and leaves the updated memory pointer. |
137 | | /// Stack pre: <v1> <v2> ... <vn> <memptr> |
138 | | /// Stack post: <memptr_updated> |
139 | | /// Does not touch the memory-free pointer. |
140 | | /// @param _padToWords if false, all values are concatenated without padding. |
141 | | /// @param _copyDynamicDataInPlace if true, dynamic types is stored (without length) |
142 | | /// together with fixed-length data. |
143 | | /// @param _encodeAsLibraryTypes if true, encodes for a library function, e.g. does not |
144 | | /// convert storage pointer types to memory types. |
145 | | /// @note the locations of target reference types are ignored, because it will always be |
146 | | /// memory. |
147 | | void encodeToMemory( |
148 | | TypePointers const& _givenTypes, |
149 | | TypePointers const& _targetTypes, |
150 | | bool _padToWords, |
151 | | bool _copyDynamicDataInPlace, |
152 | | bool _encodeAsLibraryTypes = false |
153 | | ); |
154 | | |
155 | | /// Special case of @a encodeToMemory which assumes tight packing, e.g. no zero padding |
156 | | /// and dynamic data is encoded in-place. |
157 | | /// Stack pre: <value0> <value1> ... <valueN-1> <head_start> |
158 | | /// Stack post: <mem_ptr> |
159 | | void packedEncode( |
160 | | TypePointers const& _givenTypes, |
161 | | TypePointers const& _targetTypes, |
162 | | bool _encodeAsLibraryTypes = false |
163 | | ) |
164 | 0 | { |
165 | 0 | encodeToMemory(_givenTypes, _targetTypes, false, true, _encodeAsLibraryTypes); |
166 | 0 | } |
167 | | |
168 | | /// Special case of @a encodeToMemory which assumes that everything is padded to words |
169 | | /// and dynamic data is not copied in place (i.e. a proper ABI encoding). |
170 | | /// Stack pre: <value0> <value1> ... <valueN-1> <head_start> |
171 | | /// Stack post: <mem_ptr> |
172 | | void abiEncode( |
173 | | TypePointers const& _givenTypes, |
174 | | TypePointers const& _targetTypes, |
175 | | bool _encodeAsLibraryTypes = false |
176 | | ) |
177 | 32.4k | { |
178 | 32.4k | encodeToMemory(_givenTypes, _targetTypes, true, false, _encodeAsLibraryTypes); |
179 | 32.4k | } |
180 | | |
181 | | /// Special case of @a encodeToMemory which assumes that everything is padded to words |
182 | | /// and dynamic data is not copied in place (i.e. a proper ABI encoding). |
183 | | /// Uses a new, less tested encoder implementation. |
184 | | /// Stack pre: <value0> <value1> ... <valueN-1> <head_start> |
185 | | /// Stack post: <mem_ptr> |
186 | | void abiEncodeV2( |
187 | | TypePointers const& _givenTypes, |
188 | | TypePointers const& _targetTypes, |
189 | | bool _encodeAsLibraryTypes = false, |
190 | | bool _padToWordBoundaries = true |
191 | | ); |
192 | | |
193 | | /// Decodes data from ABI encoding into internal encoding. If @a _fromMemory is set to true, |
194 | | /// the data is taken from memory instead of from calldata. |
195 | | /// Can allocate memory. |
196 | | /// Stack pre: <source_offset> <length> |
197 | | /// Stack post: <value0> <value1> ... <valuen> |
198 | | void abiDecodeV2(TypePointers const& _parameterTypes, bool _fromMemory = false); |
199 | | |
200 | | /// Zero-initialises (the data part of) an already allocated memory array. |
201 | | /// Length has to be nonzero! |
202 | | /// Stack pre: <length> <memptr> |
203 | | /// Stack post: <updated_memptr> |
204 | | void zeroInitialiseMemoryArray(ArrayType const& _type); |
205 | | |
206 | | /// Copies full 32 byte words in memory (regions cannot overlap), i.e. may copy more than length. |
207 | | /// Length can be zero, in this case, it copies nothing. |
208 | | /// Stack pre: <size> <target> <source> |
209 | | /// Stack post: |
210 | | void memoryCopy32(); |
211 | | /// Copies data in memory (regions cannot overlap). |
212 | | /// Length can be zero, in this case, it copies nothing. |
213 | | /// Stack pre: <size> <target> <source> |
214 | | /// Stack post: |
215 | | void memoryCopy(); |
216 | | |
217 | | /// Stores the given string in memory. |
218 | | /// Stack pre: mempos |
219 | | /// Stack post: |
220 | | void storeStringData(bytesConstRef _data); |
221 | | |
222 | | /// Converts the combined and left-aligned (right-aligned if @a _rightAligned is true) |
223 | | /// external function type <address><function identifier> into two stack slots: |
224 | | /// address (right aligned), function identifier (right aligned) |
225 | | void splitExternalFunctionType(bool _rightAligned); |
226 | | /// Performs the opposite operation of splitExternalFunctionType(_rightAligned) |
227 | | void combineExternalFunctionType(bool _rightAligned); |
228 | | /// Appends code that combines the construction-time (if available) and runtime function |
229 | | /// entry label of the given function into a single stack slot. |
230 | | /// Note: This might cause the compilation queue of the runtime context to be extended. |
231 | | /// If @a _runtimeOnly, the entry label will include the runtime assembly tag. |
232 | | void pushCombinedFunctionEntryLabel(Declaration const& _function, bool _runtimeOnly = true); |
233 | | |
234 | | /// Appends code for an implicit or explicit type conversion. This includes erasing higher |
235 | | /// order bits (@see appendHighBitCleanup) when widening integer but also copy to memory |
236 | | /// if a reference type is converted from calldata or storage to memory. |
237 | | /// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be |
238 | | /// necessary. |
239 | | /// If @a _chopSignBits, the function resets the signed bits out of the width of the signed integer. |
240 | | /// If @a _asPartOfArgumentDecoding is true, failed conversions are flagged via REVERT, |
241 | | /// otherwise they are flagged with INVALID. |
242 | | void convertType( |
243 | | Type const& _typeOnStack, |
244 | | Type const& _targetType, |
245 | | bool _cleanupNeeded = false, |
246 | | bool _chopSignBits = false, |
247 | | bool _asPartOfArgumentDecoding = false |
248 | | ); |
249 | | |
250 | | /// Creates a zero-value for the given type and puts it onto the stack. This might allocate |
251 | | /// memory for memory references. |
252 | | void pushZeroValue(Type const& _type); |
253 | | /// Pushes a pointer to the stack that points to a (potentially shared) location in memory |
254 | | /// that always contains a zero. It is not allowed to write there. |
255 | | void pushZeroPointer(); |
256 | | |
257 | | /// Moves the value that is at the top of the stack to a stack variable. |
258 | | void moveToStackVariable(VariableDeclaration const& _variable); |
259 | | /// Copies an item that occupies @a _itemSize stack slots from a stack depth of @a _stackDepth |
260 | | /// to the top of the stack. |
261 | | void copyToStackTop(unsigned _stackDepth, unsigned _itemSize); |
262 | | /// Moves an item that occupies @a _itemSize stack slots and has items occupying @a _stackDepth |
263 | | /// slots above it to the top of the stack. |
264 | | void moveToStackTop(unsigned _stackDepth, unsigned _itemSize = 1); |
265 | | /// Moves @a _itemSize elements past @a _stackDepth other stack elements |
266 | | void moveIntoStack(unsigned _stackDepth, unsigned _itemSize = 1); |
267 | | /// Rotates the topmost @a _items items on the stack, such that the previously topmost element |
268 | | /// is bottom-most. |
269 | | void rotateStackUp(unsigned _items); |
270 | | /// Rotates the topmost @a _items items on the stack, such that the previously bottom-most element |
271 | | /// is now topmost. |
272 | | void rotateStackDown(unsigned _items); |
273 | | /// Removes the current value from the top of the stack. |
274 | | void popStackElement(Type const& _type); |
275 | | /// Removes element from the top of the stack _amount times. |
276 | | void popStackSlots(size_t _amount); |
277 | | /// Pops slots from the stack such that its height is _toHeight. |
278 | | /// Adds jump to _jumpTo. |
279 | | /// Readjusts the stack offset to the original value. |
280 | | void popAndJump(unsigned _toHeight, evmasm::AssemblyItem const& _jumpTo); |
281 | | |
282 | | template <class T> |
283 | | static unsigned sizeOnStack(std::vector<T> const& _variables); |
284 | | static unsigned sizeOnStack(std::vector<Type const*> const& _variableTypes); |
285 | | |
286 | | /// Helper function to shift top value on the stack to the left. |
287 | | /// Stack pre: <value> <shift_by_bits> |
288 | | /// Stack post: <shifted_value> |
289 | | void leftShiftNumberOnStack(unsigned _bits); |
290 | | |
291 | | /// Helper function to shift top value on the stack to the right. |
292 | | /// Stack pre: <value> <shift_by_bits> |
293 | | /// Stack post: <shifted_value> |
294 | | void rightShiftNumberOnStack(unsigned _bits); |
295 | | |
296 | | /// Appends code that computes the Keccak-256 hash of the topmost stack element of 32 byte type. |
297 | | void computeHashStatic(); |
298 | | |
299 | | /// Appends code that copies the code of the given contract to memory. |
300 | | /// Stack pre: Memory position |
301 | | /// Stack post: Updated memory position |
302 | | /// @param creation if true, copies creation code, if false copies runtime code. |
303 | | /// @note the contract has to be compiled already, so beware of cyclic dependencies! |
304 | | void copyContractCodeToMemory(ContractDefinition const& contract, bool _creationCode); |
305 | | |
306 | | /// Bytes we need to the start of call data. |
307 | | /// - The size in bytes of the function (hash) identifier. |
308 | | static unsigned const dataStartOffset; |
309 | | |
310 | | /// Position of the free-memory-pointer in memory; |
311 | | static size_t const freeMemoryPointer; |
312 | | /// Position of the memory slot that is always zero. |
313 | | static size_t const zeroPointer; |
314 | | /// Starting offset for memory available to the user (aka the contract). |
315 | | static size_t const generalPurposeMemoryStart; |
316 | | |
317 | | private: |
318 | | /// Appends code that cleans higher-order bits for integer types. |
319 | | void cleanHigherOrderBits(IntegerType const& _typeOnStack); |
320 | | |
321 | | /// Prepares the given type for storing in memory by shifting it if necessary. |
322 | | /// @param _cleanup if true, also cleanup the value when preparing to store it in memory |
323 | | unsigned prepareMemoryStore(Type const& _type, bool _padToWords, bool _cleanup = true); |
324 | | /// Loads type from memory assuming memory offset is on stack top. |
325 | | unsigned loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWords); |
326 | | |
327 | | CompilerContext& m_context; |
328 | | }; |
329 | | |
330 | | |
331 | | template <class T> |
332 | | unsigned CompilerUtils::sizeOnStack(std::vector<T> const& _variables) |
333 | 112k | { |
334 | 112k | unsigned size = 0; |
335 | 112k | for (T const& variable: _variables) |
336 | 167k | size += variable->annotation().type->sizeOnStack(); |
337 | 112k | return size; |
338 | 112k | } |
339 | | |
340 | | } |