forked from ethereum/solidity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAbstractAssembly.h
183 lines (155 loc) · 8.3 KB
/
AbstractAssembly.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
/*
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
/**
* @date 2017
* Abstract assembly interface, subclasses of which are to be used with the generic
* bytecode generator.
*/
#pragma once
#include <libyul/ASTForward.h>
#include <libsolutil/Common.h>
#include <libsolutil/CommonData.h>
#include <libsolutil/Numeric.h>
#include <liblangutil/EVMVersion.h>
#include <functional>
#include <memory>
#include <optional>
namespace solidity::langutil
{
struct SourceLocation;
}
namespace solidity::evmasm
{
enum class Instruction: uint8_t;
}
namespace solidity::yul
{
struct Identifier;
///
/// Assembly class that abstracts both the libevmasm assembly and the new Yul assembly.
///
class AbstractAssembly
{
public:
using LabelID = size_t;
using SubID = size_t;
using ContainerID = uint8_t;
using FunctionID = uint16_t;
enum class JumpType { Ordinary, IntoFunction, OutOfFunction };
virtual ~AbstractAssembly() = default;
/// Set a new source location valid starting from the next instruction.
virtual void setSourceLocation(langutil::SourceLocation const& _location) = 0;
/// Retrieve the current height of the stack. This does not have to be zero
/// at the beginning.
virtual int stackHeight() const = 0;
virtual void setStackHeight(int height) = 0;
/// Append an EVM instruction.
virtual void appendInstruction(evmasm::Instruction _instruction) = 0;
/// Append a constant.
virtual void appendConstant(u256 const& _constant) = 0;
/// Append a label.
virtual void appendLabel(LabelID _labelId) = 0;
/// Append a label reference.
virtual void appendLabelReference(LabelID _labelId) = 0;
/// Generate a new unique label.
virtual LabelID newLabelId() = 0;
/// Returns a label identified by the given name. Creates it if it does not yet exist.
virtual LabelID namedLabel(std::string const& _name, size_t _params, size_t _returns, std::optional<size_t> _sourceID) = 0;
/// Append a reference to a to-be-linked symbol.
/// Currently, we assume that the value is always a 20 byte number.
virtual void appendLinkerSymbol(std::string const& _name) = 0;
/// Append raw bytes that stay untouched by the optimizer.
virtual void appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) = 0;
/// Append a jump instruction.
/// @param _stackDiffAfter the stack adjustment after this instruction.
/// This is helpful to stack height analysis if there is no continuing control flow.
virtual void appendJump(int _stackDiffAfter, JumpType _jumpType = JumpType::Ordinary) = 0;
/// Append a jump-to-immediate operation.
/// @param _stackDiffAfter the stack adjustment after this instruction.
virtual void appendJumpTo(LabelID _labelId, int _stackDiffAfter = 0, JumpType _jumpType = JumpType::Ordinary) = 0;
/// Append a jump-to-if-immediate operation.
virtual void appendJumpToIf(LabelID _labelId, JumpType _jumpType = JumpType::Ordinary) = 0;
/// Append the assembled size as a constant.
virtual void appendAssemblySize() = 0;
/// Creates a new sub-assembly, which can be referenced using dataSize and dataOffset.
virtual std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::string _name = "") = 0;
/// Registers a new function with given signature and returns its ID.
/// The function is initially empty and its body must be filled with instructions.
/// `_rets` even for non-returning function matters in case of stack height calculation.
virtual FunctionID registerFunction(uint8_t _args, uint8_t _rets, bool _nonReturning) = 0;
/// Selects a function as a target for newly appended instructions.
/// May only be called after the main code section is already filled and
/// must not be called when another function is already selected.
/// Filling the same function more than once is not allowed.
/// @a endFunction() must be called at the end to finalize the function.
virtual void beginFunction(FunctionID _functionID) = 0;
/// Finalizes the process of filling a function body and switches back to the main code section.
/// Must not be called if no function is selected.
/// Must be called after filling the main yul section
virtual void endFunction() = 0;
/// Appends function call to a function under given ID
virtual void appendFunctionCall(FunctionID _functionID) = 0;
/// Appends an instruction that returns values from the current function.
/// Only allowed inside a function body.
virtual void appendFunctionReturn() = 0;
/// Appends the offset of the given sub-assembly or data.
virtual void appendDataOffset(std::vector<SubID> const& _subPath) = 0;
/// Appends the size of the given sub-assembly or data.
virtual void appendDataSize(std::vector<SubID> const& _subPath) = 0;
/// Appends the given data to the assembly and returns its ID.
virtual SubID appendData(bytes const& _data) = 0;
/// Appends loading an immutable variable.
virtual void appendImmutable(std::string const& _identifier) = 0;
/// Appends an assignment to an immutable variable.
virtual void appendImmutableAssignment(std::string const& _identifier) = 0;
/// Appends an operation that loads 32 bytes of data from a known offset relative to the start of the static_aux_data area of the EOF data section.
/// Note that static_aux_data is only a part or the data section.
/// It is preceded by the pre_deploy_data, whose size is not determined before the bytecode is assembled, and which cannot be accessed using this function.
/// The function is meant to allow indexing into static_aux_data in a way that's independent of the size of pre_deploy_data.
virtual void appendAuxDataLoadN(uint16_t _offset) = 0;
/// Appends EOF contract creation instruction which takes creation code from subcontainer with _containerID.
virtual void appendEOFCreate(ContainerID _containerID) = 0;
/// Appends EOF contract return instruction which returns a subcontainer ID (_containerID) with auxiliary data filled in.
virtual void appendReturnContract(ContainerID _containerID) = 0;
/// Appends data to the very end of the bytecode. Repeated calls concatenate.
/// EOF auxiliary data in data section and the auxiliary data are different things.
virtual void appendToAuxiliaryData(bytes const& _data) = 0;
/// Appends a SWAPN with 1-based indexing for @arg _depth. I.e. a depth of 1 would be equivalent to emitting SWAP1.
/// @arg _depth ranges from 1 to 256.
virtual void appendSwapN(size_t _depth) = 0;
/// Appends a DUPN with 1-based indexing for @arg _depth. I.e. a depth of 1 would be equivalent to emitting DUP1.
/// @arg _depth ranges from 1 to 256.
virtual void appendDupN(size_t _depth) = 0;
/// Mark this assembly as invalid. Any attempt to request bytecode from it should throw.
virtual void markAsInvalid() = 0;
/// @returns the EVM version the assembly targets.
virtual langutil::EVMVersion evmVersion() const = 0;
};
enum class IdentifierContext { LValue, RValue, VariableDeclaration, NonExternal };
/// Object that is used to resolve references and generate code for access to identifiers external
/// to inline assembly (not used in standalone assembly mode).
struct ExternalIdentifierAccess
{
using Resolver = std::function<bool(Identifier const&, IdentifierContext, bool /*_crossesFunctionBoundary*/)>;
/// Resolve an external reference given by the identifier in the given context.
/// @returns the size of the value (number of stack slots) or size_t(-1) if not found.
Resolver resolve;
using CodeGenerator = std::function<void(Identifier const&, IdentifierContext, yul::AbstractAssembly&)>;
/// Generate code for retrieving the value (rvalue context) or storing the value (lvalue context)
/// of an identifier. The code should be appended to the assembly. In rvalue context, the value is supposed
/// to be put onto the stack, in lvalue context, the value is assumed to be at the top of the stack.
CodeGenerator generateCode;
};
}