aboutsummaryrefslogtreecommitdiffstats
path: root/Compiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Compiler.cpp')
-rw-r--r--Compiler.cpp126
1 files changed, 28 insertions, 98 deletions
diff --git a/Compiler.cpp b/Compiler.cpp
index c7656363..93784adf 100644
--- a/Compiler.cpp
+++ b/Compiler.cpp
@@ -28,7 +28,6 @@
#include <libsolidity/Compiler.h>
#include <libsolidity/ExpressionCompiler.h>
#include <libsolidity/CompilerUtils.h>
-#include <libsolidity/CallGraph.h>
using namespace std;
@@ -40,31 +39,13 @@ void Compiler::compileContract(ContractDefinition const& _contract,
{
m_context = CompilerContext(); // clear it just in case
initializeContext(_contract, _contracts);
-
- for (ContractDefinition const* contract: _contract.getLinearizedBaseContracts())
- {
- for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
- if (!function->isConstructor())
- m_context.addFunction(*function);
-
- for (ASTPointer<VariableDeclaration> const& vardecl: contract->getStateVariables())
- if (vardecl->isPublic())
- m_context.addFunction(*vardecl);
-
- for (ASTPointer<ModifierDefinition> const& modifier: contract->getFunctionModifiers())
- m_context.addModifier(*modifier);
- }
-
appendFunctionSelector(_contract);
- for (ContractDefinition const* contract: _contract.getLinearizedBaseContracts())
+ set<Declaration const*> functions = m_context.getFunctionsWithoutCode();
+ while (!functions.empty())
{
- for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
- if (!function->isConstructor())
- function->accept(*this);
-
- for (ASTPointer<VariableDeclaration> const& vardecl: contract->getStateVariables())
- if (vardecl->isPublic())
- generateAccessorCode(*vardecl);
+ for (Declaration const* function: functions)
+ function->accept(*this);
+ functions = m_context.getFunctionsWithoutCode();
}
// Swap the runtime context with the creation-time context
@@ -77,72 +58,26 @@ void Compiler::initializeContext(ContractDefinition const& _contract,
map<ContractDefinition const*, bytes const*> const& _contracts)
{
m_context.setCompiledContracts(_contracts);
+ m_context.setInheritanceHierarchy(_contract.getLinearizedBaseContracts());
registerStateVariables(_contract);
}
void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext)
{
- std::vector<ContractDefinition const*> const& bases = _contract.getLinearizedBaseContracts();
-
- // Make all modifiers known to the context.
- for (ContractDefinition const* contract: bases)
- for (ASTPointer<ModifierDefinition> const& modifier: contract->getFunctionModifiers())
- m_context.addModifier(*modifier);
-
// arguments for base constructors, filled in derived-to-base order
map<ContractDefinition const*, vector<ASTPointer<Expression>> const*> baseArguments;
- set<FunctionDefinition const*> neededFunctions;
- set<ASTNode const*> nodesUsedInConstructors;
- // Determine the arguments that are used for the base constructors and also which functions
- // are needed at compile time.
+ // Determine the arguments that are used for the base constructors.
+ std::vector<ContractDefinition const*> const& bases = _contract.getLinearizedBaseContracts();
for (ContractDefinition const* contract: bases)
- {
- if (FunctionDefinition const* constructor = contract->getConstructor())
- nodesUsedInConstructors.insert(constructor);
for (ASTPointer<InheritanceSpecifier> const& base: contract->getBaseContracts())
{
ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>(
base->getName()->getReferencedDeclaration());
solAssert(baseContract, "");
if (baseArguments.count(baseContract) == 0)
- {
baseArguments[baseContract] = &base->getArguments();
- for (ASTPointer<Expression> const& arg: base->getArguments())
- nodesUsedInConstructors.insert(arg.get());
- }
}
- }
-
- auto functionOverrideResolver = [&](string const& _name) -> FunctionDefinition const*
- {
- for (ContractDefinition const* contract: bases)
- for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
- if (!function->isConstructor() && function->getName() == _name)
- return function.get();
- return nullptr;
- };
- auto modifierOverrideResolver = [&](string const& _name) -> ModifierDefinition const*
- {
- return &m_context.getFunctionModifier(_name);
- };
-
- neededFunctions = getFunctionsCalled(nodesUsedInConstructors, functionOverrideResolver,
- modifierOverrideResolver);
-
- // First add all overrides (or the functions themselves if there is no override)
- for (FunctionDefinition const* fun: neededFunctions)
- {
- FunctionDefinition const* override = nullptr;
- if (!fun->isConstructor())
- override = functionOverrideResolver(fun->getName());
- if (!!override && neededFunctions.count(override))
- m_context.addFunction(*override);
- }
- // now add the rest
- for (FunctionDefinition const* fun: neededFunctions)
- if (fun->isConstructor() || functionOverrideResolver(fun->getName()) != fun)
- m_context.addFunction(*fun);
// Call constructors in base-to-derived order.
// The Constructor for the most derived contract is called later.
@@ -164,10 +99,14 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp
m_context << eth::Instruction::DUP1 << sub << u256(0) << eth::Instruction::CODECOPY;
m_context << u256(0) << eth::Instruction::RETURN;
- // note that we have to explicitly include all used functions because of absolute jump
- // labels
- for (FunctionDefinition const* fun: neededFunctions)
- fun->accept(*this);
+ // note that we have to include the functions again because of absolute jump labels
+ set<Declaration const*> functions = m_context.getFunctionsWithoutCode();
+ while (!functions.empty())
+ {
+ for (Declaration const* function: functions)
+ function->accept(*this);
+ functions = m_context.getFunctionsWithoutCode();
+ }
}
void Compiler::appendBaseConstructorCall(FunctionDefinition const& _constructor,
@@ -201,16 +140,6 @@ void Compiler::appendConstructorCall(FunctionDefinition const& _constructor)
m_context << returnTag;
}
-set<FunctionDefinition const*> Compiler::getFunctionsCalled(set<ASTNode const*> const& _nodes,
- function<FunctionDefinition const*(string const&)> const& _resolveFunctionOverrides,
- function<ModifierDefinition const*(string const&)> const& _resolveModifierOverrides)
-{
- CallGraph callgraph(_resolveFunctionOverrides, _resolveModifierOverrides);
- for (ASTNode const* node: _nodes)
- callgraph.addNode(*node);
- return callgraph.getCalls();
-}
-
void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
{
map<FixedHash<4>, FunctionDescription> interfaceFunctions = _contract.getInterfaceFunctions();
@@ -292,19 +221,22 @@ void Compiler::registerStateVariables(ContractDefinition const& _contract)
m_context.addStateVariable(*variable);
}
-void Compiler::generateAccessorCode(VariableDeclaration const& _varDecl)
+bool Compiler::visit(VariableDeclaration const& _variableDeclaration)
{
- m_context.startNewFunction();
+ solAssert(_variableDeclaration.isStateVariable(), "Compiler visit to non-state variable declaration.");
+
+ m_context.startFunction(_variableDeclaration);
m_breakTags.clear();
m_continueTags.clear();
- m_context << m_context.getFunctionEntryLabel(_varDecl);
- ExpressionCompiler::appendStateVariableAccessor(m_context, _varDecl);
+ m_context << m_context.getFunctionEntryLabel(_variableDeclaration);
+ ExpressionCompiler::appendStateVariableAccessor(m_context, _variableDeclaration);
- unsigned sizeOnStack = _varDecl.getType()->getSizeOnStack();
- solAssert(sizeOnStack <= 15, "Illegal variable stack size detected");
- m_context << eth::dupInstruction(sizeOnStack + 1);
- m_context << eth::Instruction::JUMP;
+ unsigned sizeOnStack = _variableDeclaration.getType()->getSizeOnStack();
+ solAssert(sizeOnStack <= 15, "Stack too deep.");
+ m_context << eth::dupInstruction(sizeOnStack + 1) << eth::Instruction::JUMP;
+
+ return false;
}
bool Compiler::visit(FunctionDefinition const& _function)
@@ -313,7 +245,7 @@ bool Compiler::visit(FunctionDefinition const& _function)
// caller puts: [retarg0] ... [retargm] [return address] [arg0] ... [argn]
// although note that this reduces the size of the visible stack
- m_context.startNewFunction();
+ m_context.startFunction(_function);
m_returnTag = m_context.newTag();
m_breakTags.clear();
m_continueTags.clear();
@@ -321,8 +253,6 @@ bool Compiler::visit(FunctionDefinition const& _function)
m_currentFunction = &_function;
m_modifierDepth = 0;
- m_context << m_context.getFunctionEntryLabel(_function);
-
// stack upon entry: [return address] [arg0] [arg1] ... [argn]
// reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp]