aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/codegen/ContractCompiler.h
blob: 9ab006f6ecc586fd41e96261d5961e5b70beff9e (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
/*
    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 2014
 * Code generator for contracts.
 */

#pragma once

#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/codegen/CompilerContext.h>
#include <libevmasm/Assembly.h>
#include <functional>
#include <ostream>

namespace dev {
namespace solidity {

/**
 * Code generator at the contract level. Can be used to generate code for exactly one contract
 * either either in "runtime mode" or "creation mode".
 */
class ContractCompiler: private ASTConstVisitor
{
public:
    explicit ContractCompiler(ContractCompiler* _runtimeCompiler, CompilerContext& _context, bool _optimise, size_t _optimise_runs = 200):
        m_optimise(_optimise),
        m_optimise_runs(_optimise_runs),
        m_runtimeCompiler(_runtimeCompiler),
        m_context(_context)
    {
        m_context = CompilerContext(_context.evmVersion(), _runtimeCompiler ? &_runtimeCompiler->m_context : nullptr);
    }

    void compileContract(
        ContractDefinition const& _contract,
        std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> const& _otherCompilers
    );
    /// Compiles the constructor part of the contract.
    /// @returns the identifier of the runtime sub-assembly.
    size_t compileConstructor(
        ContractDefinition const& _contract,
        std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> const& _otherCompilers
    );

private:
    /// Registers the non-function objects inside the contract with the context and stores the basic
    /// information about the contract like the AST annotations.
    void initializeContext(
        ContractDefinition const& _contract,
        std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> const& _otherCompilers
    );
    /// Adds the code that is run at creation time. Should be run after exchanging the run-time context
    /// with a new and initialized context. Adds the constructor code.
    /// @returns the identifier of the runtime sub assembly
    size_t packIntoContractCreator(ContractDefinition const& _contract);
    /// Appends code that deploys the given contract as a library.
    /// Will also add code that modifies the contract in memory by injecting the current address
    /// for the call protector.
    size_t deployLibrary(ContractDefinition const& _contract);
    /// Appends state variable initialisation and constructor code.
    void appendInitAndConstructorCode(ContractDefinition const& _contract);
    void appendBaseConstructor(FunctionDefinition const& _constructor);
    void appendConstructor(FunctionDefinition const& _constructor);
    /// Appends code that returns a boolean flag on the stack that tells whether
    /// the contract has been called via delegatecall (false) or regular call (true).
    /// This is done by inserting a specific push constant as the first instruction
    /// whose data will be modified in memory at deploy time.
    void appendDelegatecallCheck();
    /// Appends the function selector. Is called recursively to create a binary search tree.
    /// @a _runs the number of intended executions of the contract to tune the split point.
    void appendInternalSelector(
        std::map<FixedHash<4>, eth::AssemblyItem const> const& _entryPoints,
        std::vector<FixedHash<4>> const& _ids,
        eth::AssemblyItem const& _notFoundTag,
        size_t _runs
    );
    void appendFunctionSelector(ContractDefinition const& _contract);
    void appendCallValueCheck();
    void appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary);

    void registerStateVariables(ContractDefinition const& _contract);
    void initializeStateVariables(ContractDefinition const& _contract);

    bool visit(VariableDeclaration const& _variableDeclaration) override;
    bool visit(FunctionDefinition const& _function) override;
    bool visit(InlineAssembly const& _inlineAssembly) override;
    bool visit(IfStatement const& _ifStatement) override;
    bool visit(WhileStatement const& _whileStatement) override;
    bool visit(ForStatement const& _forStatement) override;
    bool visit(Continue const& _continueStatement) override;
    bool visit(Break const& _breakStatement) override;
    bool visit(Return const& _return) override;
    bool visit(Throw const& _throw) override;
    bool visit(EmitStatement const& _emit) override;
    bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override;
    bool visit(ExpressionStatement const& _expressionStatement) override;
    bool visit(PlaceholderStatement const&) override;
    bool visit(Block const& _block) override;
    void endVisit(Block const& _block) override;

    /// Repeatedly visits all function which are referenced but which are not compiled yet.
    void appendMissingFunctions();

    /// Appends one layer of function modifier code of the current function, or the function
    /// body itself if the last modifier was reached.
    void appendModifierOrFunctionCode();

    void appendStackVariableInitialisation(VariableDeclaration const& _variable);
    void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer());

    /// Frees the variables of a certain scope (to be used when leaving).
    void popScopedVariables(ASTNode const* _node);

    /// Sets the stack height for the visited loop.
    void storeStackHeight(ASTNode const* _node);

    bool const m_optimise;
    size_t const m_optimise_runs = 200;
    /// Pointer to the runtime compiler in case this is a creation compiler.
    ContractCompiler* m_runtimeCompiler = nullptr;
    CompilerContext& m_context;
    /// Tag to jump to for a "break" statement and the stack height after freeing the local loop variables.
    std::vector<std::pair<eth::AssemblyItem, unsigned>> m_breakTags;
    /// Tag to jump to for a "continue" statement and the stack height after freeing the local loop variables.
    std::vector<std::pair<eth::AssemblyItem, unsigned>> m_continueTags;
    /// Tag to jump to for a "return" statement and the stack height after freeing the local function or modifier variables.
    /// Needs to be stacked because of modifiers.
    std::vector<std::pair<eth::AssemblyItem, unsigned>> m_returnTags;
    unsigned m_modifierDepth = 0;
    FunctionDefinition const* m_currentFunction = nullptr;

    // arguments for base constructors, filled in derived-to-base order
    std::map<FunctionDefinition const*, ASTNode const*> const* m_baseArguments;

    /// Stores the variables that were declared inside a specific scope, for each modifier depth.
    std::map<unsigned, std::map<ASTNode const*, unsigned>> m_scopeStackHeight;
};

}
}