aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/codegen/LValue.h
blob: 3b44597fcc803fec796f5086fbf854a43ea08165 (plain) (blame)
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
/*
    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/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2015
 * LValues for use in the expression compiler.
 */

#pragma once

#include <libsolidity/codegen/ArrayUtils.h>
#include <liblangutil/SourceLocation.h>
#include <memory>
#include <vector>

namespace dev
{
namespace solidity
{

class Declaration;
class Type;
class TupleType;
class ArrayType;
class CompilerContext;
class VariableDeclaration;

/**
 * Abstract class used to retrieve, delete and store data in lvalues/variables.
 */
class LValue
{
protected:
    explicit LValue(CompilerContext& _compilerContext, Type const* _dataType = nullptr):
        m_context(_compilerContext), m_dataType(_dataType) {}

public:
    virtual ~LValue() {}
    /// @returns the number of stack slots occupied by the lvalue reference
    virtual unsigned sizeOnStack() const { return 1; }
    /// Copies the value of the current lvalue to the top of the stack and, if @a _remove is true,
    /// also removes the reference from the stack.
    /// @a _location source location of the current expression, used for error reporting.
    virtual void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const = 0;
    /// Moves a value from the stack to the lvalue. Removes the value if @a _move is true.
    /// @a _location is the source location of the expression that caused this operation.
    /// Stack pre: value [lvalue_ref]
    /// Stack post: if !_move: value_of(lvalue_ref)
    virtual void storeValue(Type const& _sourceType,
        langutil::SourceLocation const& _location = {}, bool _move = false) const = 0;
    /// Stores zero in the lvalue. Removes the reference from the stack if @a _removeReference is true.
    /// @a _location is the source location of the requested operation
    virtual void setToZero(
        langutil::SourceLocation const& _location = {},
        bool _removeReference = true
    ) const = 0;

protected:
    CompilerContext& m_context;
    Type const* m_dataType;
};

/**
 * Local variable that is completely stored on the stack.
 */
class StackVariable: public LValue
{
public:
    StackVariable(CompilerContext& _compilerContext, VariableDeclaration const& _declaration);

    unsigned sizeOnStack() const override { return 0; }
    void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
    virtual void storeValue(
        Type const& _sourceType,
        langutil::SourceLocation const& _location = {},
        bool _move = false
    ) const override;
    virtual void setToZero(
        langutil::SourceLocation const& _location = {},
        bool _removeReference = true
    ) const override;

private:
    /// Base stack offset (@see CompilerContext::baseStackOffsetOfVariable) of the local variable.
    unsigned m_baseStackOffset;
    /// Number of stack elements occupied by the value (not the reference).
    unsigned m_size;
};

/**
 * Reference to some item in memory.
 */
class MemoryItem: public LValue
{
public:
    MemoryItem(CompilerContext& _compilerContext, Type const& _type, bool _padded = true);
    unsigned sizeOnStack() const override { return 1; }
    void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
    virtual void storeValue(
        Type const& _sourceType,
        langutil::SourceLocation const& _location = {},
        bool _move = false
    ) const override;
    virtual void setToZero(
        langutil::SourceLocation const& _location = {},
        bool _removeReference = true
    ) const override;
private:
    /// Special flag to deal with byte array elements.
    bool m_padded = false;
};

/**
 * Reference to some item in storage. On the stack this is <storage key> <offset_inside_value>,
 * where 0 <= offset_inside_value < 32 and an offset of i means that the value is multiplied
 * by 2**i before storing it.
 */
class StorageItem: public LValue
{
public:
    /// Constructs the LValue and pushes the location of @a _declaration onto the stack.
    StorageItem(CompilerContext& _compilerContext, VariableDeclaration const& _declaration);
    /// Constructs the LValue and assumes that the storage reference is already on the stack.
    StorageItem(CompilerContext& _compilerContext, Type const& _type);
    unsigned sizeOnStack() const override { return 2; }
    void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
    virtual void storeValue(
        Type const& _sourceType,
        langutil::SourceLocation const& _location = {},
        bool _move = false
    ) const override;
    virtual void setToZero(
        langutil::SourceLocation const& _location = {},
        bool _removeReference = true
    ) const override;
};

/**
 * Reference to a single byte inside a storage byte array.
 * Stack: <storage_ref> <byte_number>
 */
class StorageByteArrayElement: public LValue
{
public:
    /// Constructs the LValue and assumes that the storage reference is already on the stack.
    StorageByteArrayElement(CompilerContext& _compilerContext);
    unsigned sizeOnStack() const override { return 2; }
    void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
    virtual void storeValue(
        Type const& _sourceType,
        langutil::SourceLocation const& _location = {},
        bool _move = false
    ) const override;
    virtual void setToZero(
        langutil::SourceLocation const& _location = {},
        bool _removeReference = true
    ) const override;
};

/**
 * Reference to the "length" member of a dynamically-sized array. This is an LValue with special
 * semantics since assignments to it might reduce its length and thus arrays members have to be
 * deleted.
 */
class StorageArrayLength: public LValue
{
public:
    /// Constructs the LValue, assumes that the reference to the array head is already on the stack.
    StorageArrayLength(CompilerContext& _compilerContext, ArrayType const& _arrayType);
    void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
    virtual void storeValue(
        Type const& _sourceType,
        langutil::SourceLocation const& _location = {},
        bool _move = false
    ) const override;
    virtual void setToZero(
        langutil::SourceLocation const& _location = {},
        bool _removeReference = true
    ) const override;

private:
    ArrayType const& m_arrayType;
};

/**
 * Tuple object that can itself hold several LValues.
 */
class TupleObject: public LValue
{
public:
    /// Constructs the LValue assuming that the other LValues are present on the stack.
    /// Empty unique_ptrs are possible if e.g. some values should be ignored during assignment.
    TupleObject(CompilerContext& _compilerContext, std::vector<std::unique_ptr<LValue>>&& _lvalues);
    unsigned sizeOnStack() const override;
    void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
    virtual void storeValue(
        Type const& _sourceType,
        langutil::SourceLocation const& _location = {},
        bool _move = false
    ) const override;
    virtual void setToZero(
        langutil::SourceLocation const& _location = {},
        bool _removeReference = true
    ) const override;

private:
    std::vector<std::unique_ptr<LValue>> m_lvalues;
};

}
}