forked from ethereum/solidity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathYulUtilFunctions.h
388 lines (308 loc) · 16.5 KB
/
YulUtilFunctions.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
/**
* Component that can generate various useful Yul functions.
*/
#pragma once
#include <liblangutil/EVMVersion.h>
#include <libsolidity/ast/Types.h>
#include <libsolidity/codegen/MultiUseYulFunctionCollector.h>
#include <libsolidity/interface/DebugSettings.h>
#include <memory>
#include <string>
#include <vector>
namespace solidity::frontend
{
class Type;
class ArrayType;
class MappingType;
class IntegerType;
class StructType;
/**
* Component that can generate various useful Yul functions.
*/
class YulUtilFunctions
{
public:
explicit YulUtilFunctions(
langutil::EVMVersion _evmVersion,
RevertStrings _revertStrings,
MultiUseYulFunctionCollector& _functionCollector
):
m_evmVersion(_evmVersion),
m_revertStrings(_revertStrings),
m_functionCollector(_functionCollector)
{}
/// @returns a function that combines the address and selector to a single value
/// for use in the ABI.
std::string combineExternalFunctionIdFunction();
/// @returns a function that splits the address and selector from a single value
/// for use in the ABI.
std::string splitExternalFunctionIdFunction();
/// @returns a function that copies raw bytes of dynamic length from calldata
/// or memory to memory.
/// Pads with zeros and might write more than exactly length.
std::string copyToMemoryFunction(bool _fromCalldata);
// @returns the name of a function that has the equivalent logic of an
// `assert` or `require` call.
std::string requireOrAssertFunction(bool _assert, Type const* _messageType = nullptr);
/// @returns the name of a function that takes a (cleaned) value of the given value type and
/// left-aligns it, usually for use in non-padded encoding.
std::string leftAlignFunction(Type const& _type);
std::string shiftLeftFunction(size_t _numBits);
std::string shiftLeftFunctionDynamic();
std::string shiftRightFunction(size_t _numBits);
std::string shiftRightFunctionDynamic();
std::string shiftRightSignedFunctionDynamic();
/// @returns the name of a function that performs a left shift and subsequent cleanup
/// and, if needed, prior cleanup.
/// If the amount to shift by is signed, a check for negativeness is performed.
/// signature: (value, amountToShift) -> result
std::string typedShiftLeftFunction(Type const& _type, Type const& _amountType);
std::string typedShiftRightFunction(Type const& _type, Type const& _amountType);
/// @returns the name of a function which replaces the
/// _numBytes bytes starting at byte position _shiftBytes (counted from the least significant
/// byte) by the _numBytes least significant bytes of `toInsert`.
/// signature: (value, toInsert) -> result
std::string updateByteSliceFunction(size_t _numBytes, size_t _shiftBytes);
/// signature: (value, shiftBytes, toInsert) -> result
std::string updateByteSliceFunctionDynamic(size_t _numBytes);
/// @returns the name of a function that rounds its input to the next multiple
/// of 32 or the input if it is a multiple of 32.
/// signature: (value) -> result
std::string roundUpFunction();
/// signature: (x, y) -> sum
std::string overflowCheckedIntAddFunction(IntegerType const& _type);
/// signature: (x, y) -> product
std::string overflowCheckedIntMulFunction(IntegerType const& _type);
/// @returns name of function to perform division on integers.
/// Checks for division by zero and the special case of
/// signed division of the smallest number by -1.
std::string overflowCheckedIntDivFunction(IntegerType const& _type);
/// @returns name of function to perform modulo on integers.
/// Reverts for modulo by zero.
std::string checkedIntModFunction(IntegerType const& _type);
/// @returns computes the difference between two values.
/// Assumes the input to be in range for the type.
/// signature: (x, y) -> diff
std::string overflowCheckedIntSubFunction(IntegerType const& _type);
/// @returns the name of a function that fetches the length of the given
/// array
/// signature: (array) -> length
std::string arrayLengthFunction(ArrayType const& _type);
/// @returns the name of a function that resizes a storage array
/// signature: (array, newLen)
std::string resizeDynamicArrayFunction(ArrayType const& _type);
/// @returns the name of a function that reduces the size of a storage array by one element
/// signature: (array)
std::string storageArrayPopFunction(ArrayType const& _type);
/// @returns the name of a function that pushes an element to a storage array
/// signature: (array, value)
std::string storageArrayPushFunction(ArrayType const& _type);
/// @returns the name of a function that pushes the base type's zero element to a storage array and returns storage slot and offset of the added element.
/// signature: (array) -> slot, offset
std::string storageArrayPushZeroFunction(ArrayType const& _type);
/// @returns the name of a function that will clear the storage area given
/// by the start and end (exclusive) parameters (slots).
/// signature: (start, end)
std::string clearStorageRangeFunction(Type const& _type);
/// @returns the name of a function that will clear the given storage array
/// signature: (slot) ->
std::string clearStorageArrayFunction(ArrayType const& _type);
/// Returns the name of a function that will convert a given length to the
/// size in memory (number of storage slots or calldata/memory bytes) it
/// will require.
/// signature: (length) -> size
std::string arrayConvertLengthToSize(ArrayType const& _type);
/// @returns the name of a function that computes the number of bytes required
/// to store an array in memory given its length (internally encoded, not ABI encoded).
/// The function reverts for too large lengths.
std::string arrayAllocationSizeFunction(ArrayType const& _type);
/// @returns the name of a function that converts a storage slot number
/// a memory pointer or a calldata pointer to the slot number / memory pointer / calldata pointer
/// for the data position of an array which is stored in that slot / memory area / calldata area.
std::string arrayDataAreaFunction(ArrayType const& _type);
/// @returns the name of a function that returns the slot and offset for the
/// given array and index
/// signature: (array, index) -> slot, offset
std::string storageArrayIndexAccessFunction(ArrayType const& _type);
/// @returns the name of a function that returns the memory address for the
/// given array base ref and index.
/// Causes invalid opcode on out of range access.
/// signature: (baseRef, index) -> address
std::string memoryArrayIndexAccessFunction(ArrayType const& _type);
/// @returns the name of a function that returns the calldata address for the
/// given array base ref and index.
/// signature: (baseRef, index) -> offset[, length]
std::string calldataArrayIndexAccessFunction(ArrayType const& _type);
/// @returns the name of a function that returns offset and length for array slice
/// for the given array offset, length and start and end indices for slice
/// signature: (arrayOffset, arrayLength, sliceStart, sliceEnd) -> offset, length
std::string calldataArrayIndexRangeAccess(ArrayType const& _type);
/// @returns the name of a function that follows a calldata tail while performing
/// bounds checks.
/// signature: (baseRef, tailPointer) -> offset[, length]
std::string accessCalldataTailFunction(Type const& _type);
/// @returns the name of a function that advances an array data pointer to the next element.
/// Only works for memory arrays, calldata arrays and storage arrays that every item occupies one or multiple full slots.
std::string nextArrayElementFunction(ArrayType const& _type);
/// @returns the name of a function that performs index access for mappings.
/// @param _mappingType the type of the mapping
/// @param _keyType the type of the value provided
std::string mappingIndexAccessFunction(MappingType const& _mappingType, Type const& _keyType);
/// @returns a function that reads a value type from storage.
/// Performs bit mask/sign extend cleanup and appropriate left / right shift, but not validation.
/// @param _splitFunctionTypes if false, returns the address and function signature in a
/// single variable.
std::string readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes);
std::string readFromStorageDynamic(Type const& _type, bool _splitFunctionTypes);
/// @returns a function that reads a value type from memory. Performs cleanup.
/// signature: (addr) -> value
std::string readFromMemory(Type const& _type);
/// @returns a function that reads a value type from calldata.
/// Reverts on invalid input.
/// signature: (addr) -> value
std::string readFromCalldata(Type const& _type);
/// @returns a function that extracts a value type from storage slot that has been
/// retrieved already.
/// Performs bit mask/sign extend cleanup and appropriate left / right shift, but not validation.
/// @param _splitFunctionTypes if false, returns the address and function signature in a
/// single variable.
std::string extractFromStorageValue(Type const& _type, size_t _offset, bool _splitFunctionTypes);
std::string extractFromStorageValueDynamic(Type const& _type, bool _splitFunctionTypes);
/// Returns the name of a function will write the given value to
/// the specified slot and offset. If offset is not given, it is expected as
/// runtime parameter.
/// signature: (slot, [offset,] value)
std::string updateStorageValueFunction(Type const& _type, std::optional<unsigned> const& _offset = std::optional<unsigned>());
/// Returns the name of a function that will write the given value to
/// the specified address.
/// Performs a cleanup before writing for value types.
/// signature: (memPtr, value) ->
std::string writeToMemoryFunction(Type const& _type);
/// Performs cleanup after reading from a potentially compressed storage slot.
/// The function does not perform any validation, it just masks or sign-extends
/// higher order bytes or left-aligns (in case of bytesNN).
/// The storage cleanup expects the value to be right-aligned with potentially
/// dirty higher order bytes.
/// @param _splitFunctionTypes if false, returns the address and function signature in a
/// single variable.
std::string cleanupFromStorageFunction(Type const& _type, bool _splitFunctionTypes);
/// @returns the name of a function that prepares a value of the given type
/// for being stored in storage. This usually includes cleanup and right-alignment
/// to fit the number of bytes in storage.
/// The resulting value might still have dirty higher order bits.
std::string prepareStoreFunction(Type const& _type);
/// @returns the name of a function that allocates memory.
/// Modifies the "free memory pointer"
/// Arguments: size
/// Return value: pointer
std::string allocationFunction();
/// @returns the name of the function that allocates temporary memory with predefined size
/// Return value: pointer
std::string allocationTemporaryMemoryFunction();
/// @returns the name of the function that releases previously allocated temporary memory
std::string releaseTemporaryMemoryFunction();
/// @returns the name of a function that zeroes an array.
/// signature: (dataStart, dataSizeInBytes) ->
std::string zeroMemoryArrayFunction(ArrayType const& _type);
/// @returns the name of a function that zeroes a chunk of memory.
/// signature: (dataStart, dataSizeInBytes) ->
std::string zeroMemoryFunction(Type const& _type);
/// @returns the name of a function that zeroes an array
/// where the base does not have simple zero value in memory.
/// signature: (dataStart, dataSizeInBytes) ->
std::string zeroComplexMemoryArrayFunction(ArrayType const& _type);
/// @returns the name of a function that allocates and zeroes a memory array.
/// For dynamic arrays it adds space for length and stores it.
/// signature: (length) -> memPtr
std::string allocateAndInitializeMemoryArrayFunction(ArrayType const& _type);
/// @returns the name of a function that allocates a memory struct (no
/// initialization takes place).
/// signature: () -> memPtr
std::string allocateMemoryStructFunction(StructType const& _type);
/// @returns the name of a function that allocates and zeroes a memory struct.
/// signature: () -> memPtr
std::string allocateAndInitializeMemoryStructFunction(StructType const& _type);
/// @returns the name of the function that converts a value of type @a _from
/// to a value of type @a _to. The resulting vale is guaranteed to be in range
/// (i.e. "clean"). Asserts on failure.
///
/// This is used for data being encoded or general type conversions in the code.
std::string conversionFunction(Type const& _from, Type const& _to);
/// @returns the name of the cleanup function for the given type and
/// adds its implementation to the requested functions.
/// The cleanup function defers to the validator function with "assert"
/// if there is no reasonable way to clean a value.
std::string cleanupFunction(Type const& _type);
/// @returns the name of the validator function for the given type and
/// adds its implementation to the requested functions.
/// @param _revertOnFailure if true, causes revert on invalid data,
/// otherwise an assertion failure.
///
/// This is used for data decoded from external sources.
std::string validatorFunction(Type const& _type, bool _revertOnFailure = false);
std::string packedHashFunction(std::vector<Type const*> const& _givenTypes, std::vector<Type const*> const& _targetTypes);
/// @returns the name of a function that reverts and uses returndata (if available)
/// as reason string.
std::string forwardingRevertFunction();
std::string incrementCheckedFunction(Type const& _type);
std::string decrementCheckedFunction(Type const& _type);
std::string negateNumberCheckedFunction(Type const& _type);
/// @returns the name of a function that returns the zero value for the
/// provided type.
/// @param _splitFunctionTypes if false, returns two zeroes
std::string zeroValueFunction(Type const& _type, bool _splitFunctionTypes = true);
/// @returns the name of a function that will set the given storage item to
/// zero
/// signature: (slot, offset) ->
std::string storageSetToZeroFunction(Type const& _type);
/// If revertStrings is debug, @returns inline assembly code that
/// stores @param _message in memory position 0 and reverts.
/// Otherwise returns "revert(0, 0)".
static std::string revertReasonIfDebug(RevertStrings revertStrings, std::string const& _message = "");
std::string revertReasonIfDebug(std::string const& _message = "");
/// Returns the name of a function that decodes an error message.
/// signature: () -> arrayPtr
///
/// Returns a newly allocated `bytes memory` array containing the decoded error message
/// or 0 on failure.
std::string tryDecodeErrorMessageFunction();
/// Returns a function name that returns a newly allocated `bytes` array that contains the return data.
///
/// If returndatacopy() is not supported by the underlying target, a empty array will be returned instead.
std::string extractReturndataFunction();
/// @returns function name that returns constructor arguments copied to memory
/// signature: () -> arguments
std::string copyConstructorArgumentsToMemoryFunction(
ContractDefinition const& _contract,
std::string const& _creationObjectName
);
private:
/// Special case of conversionFunction - handles everything that does not
/// use exactly one variable to hold the value.
std::string conversionFunctionSpecial(Type const& _from, Type const& _to);
/// @returns function name that extracts and returns byte array length
/// signature: (data) -> length
std::string extractByteArrayLengthFunction();
/// @returns the name of a function that reduces the size of a storage byte array by one element
/// signature: (byteArray)
std::string storageByteArrayPopFunction(ArrayType const& _type);
std::string readFromMemoryOrCalldata(Type const& _type, bool _fromCalldata);
langutil::EVMVersion m_evmVersion;
RevertStrings m_revertStrings;
MultiUseYulFunctionCollector& m_functionCollector;
};
}