/src/solidity/libyul/SideEffects.h
Line | Count | Source |
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 | | #pragma once |
20 | | |
21 | | #include <algorithm> |
22 | | #include <set> |
23 | | |
24 | | namespace solidity::yul |
25 | | { |
26 | | |
27 | | /** |
28 | | * Side effects of code. |
29 | | * |
30 | | * The default-constructed value applies to the "empty code". |
31 | | */ |
32 | | struct SideEffects |
33 | | { |
34 | | /// Corresponds to the effect that a Yul-builtin has on a generic data location (storage, memory |
35 | | /// and other blockchain state). |
36 | | enum Effect |
37 | | { |
38 | | None, |
39 | | Read, |
40 | | Write |
41 | | }; |
42 | | |
43 | | friend Effect operator+(Effect const& _a, Effect const& _b) |
44 | 572M | { |
45 | 572M | return static_cast<Effect>(std::max(static_cast<int>(_a), static_cast<int>(_b))); |
46 | 572M | } |
47 | | |
48 | | /// If true, expressions in this code can be freely moved and copied without altering the |
49 | | /// semantics. |
50 | | /// At statement level, it means that functions containing this code can be |
51 | | /// called multiple times, their calls can be rearranged and calls can also be |
52 | | /// deleted without changing the semantics. |
53 | | /// This means it cannot depend on storage, memory or transient storage, cannot have any side-effects, |
54 | | /// but it can depend on state that is constant across an EVM-call. |
55 | | bool movable = true; |
56 | | /// If true, the expressions in this code can be moved or copied (together with their arguments) |
57 | | /// across control flow branches and instructions as long as these instructions' 'effects' do |
58 | | /// not influence the 'effects' of the aforementioned expressions. |
59 | | bool movableApartFromEffects = true; |
60 | | /// If true, the code can be removed without changing the semantics. |
61 | | bool canBeRemoved = true; |
62 | | /// If true, the code can be removed without changing the semantics as long as |
63 | | /// the whole program does not contain the msize instruction. |
64 | | bool canBeRemovedIfNoMSize = true; |
65 | | /// If false, the code calls a for-loop or a recursive function, and therefore potentially loops |
66 | | /// infinitely. All builtins are set to true by default, even `invalid()`. |
67 | | bool cannotLoop = true; |
68 | | /// Can write, read or have no effect on the blockchain state, when the value of `otherState` is |
69 | | /// `Write`, `Read` or `None` respectively. |
70 | | Effect otherState = None; |
71 | | /// Can write, read or have no effect on storage, when the value of `storage` is `Write`, `Read` |
72 | | /// or `None` respectively. When the value is `Write`, the expression can invalidate storage, |
73 | | /// potentially indirectly through external calls. |
74 | | Effect storage = None; |
75 | | /// Can write, read or have no effect on memory, when the value of `memory` is `Write`, `Read` |
76 | | /// or `None` respectively. Note that, when the value is `Read`, the expression can have an |
77 | | /// effect on `msize()`. |
78 | | Effect memory = None; |
79 | | /// Can write, read or have no effect on transient storage, when the value of `transientStorage` is `Write`, `Read` |
80 | | /// or `None` respectively. When the value is `Write`, the expression can invalidate transient storage, |
81 | | /// potentially indirectly through external calls. |
82 | | Effect transientStorage = None; |
83 | | |
84 | | /// @returns the worst-case side effects. |
85 | | static SideEffects worst() |
86 | 47.6M | { |
87 | 47.6M | return SideEffects{false, false, false, false, false, Write, Write, Write, Write}; |
88 | 47.6M | } |
89 | | |
90 | | /// @returns the combined side effects of two pieces of code. |
91 | | SideEffects operator+(SideEffects const& _other) |
92 | 143M | { |
93 | 143M | return SideEffects{ |
94 | 143M | movable && _other.movable, |
95 | 143M | movableApartFromEffects && _other.movableApartFromEffects, |
96 | 143M | canBeRemoved && _other.canBeRemoved, |
97 | 143M | canBeRemovedIfNoMSize && _other.canBeRemovedIfNoMSize, |
98 | 143M | cannotLoop && _other.cannotLoop, |
99 | 143M | otherState + _other.otherState, |
100 | 143M | storage + _other.storage, |
101 | 143M | memory + _other.memory, |
102 | 143M | transientStorage + _other.transientStorage |
103 | 143M | }; |
104 | 143M | } |
105 | | |
106 | | /// Adds the side effects of another piece of code to this side effect. |
107 | | SideEffects& operator+=(SideEffects const& _other) |
108 | 143M | { |
109 | 143M | *this = *this + _other; |
110 | 143M | return *this; |
111 | 143M | } |
112 | | |
113 | | bool operator==(SideEffects const& _other) const |
114 | 45.6M | { |
115 | 45.6M | return |
116 | 45.6M | movable == _other.movable && |
117 | 45.6M | movableApartFromEffects == _other.movableApartFromEffects && |
118 | 45.6M | canBeRemoved == _other.canBeRemoved && |
119 | 45.6M | canBeRemovedIfNoMSize == _other.canBeRemovedIfNoMSize && |
120 | 45.6M | cannotLoop == _other.cannotLoop && |
121 | 45.6M | otherState == _other.otherState && |
122 | 45.6M | storage == _other.storage && |
123 | 45.6M | memory == _other.memory && |
124 | 45.6M | transientStorage == _other.transientStorage; |
125 | 45.6M | } |
126 | | }; |
127 | | |
128 | | } |