|
|
@ -58,7 +58,10 @@ void Compiler::compileContract(ContractDefinition const& _contract, |
|
|
|
while (!functions.empty()) |
|
|
|
{ |
|
|
|
for (Declaration const* function: functions) |
|
|
|
{ |
|
|
|
m_context.setStackOffset(0); |
|
|
|
function->accept(*this); |
|
|
|
} |
|
|
|
functions = m_context.getFunctionsWithoutCode(); |
|
|
|
} |
|
|
|
|
|
|
@ -79,37 +82,38 @@ void Compiler::initializeContext(ContractDefinition const& _contract, |
|
|
|
|
|
|
|
void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext) |
|
|
|
{ |
|
|
|
// arguments for base constructors, filled in derived-to-base order
|
|
|
|
map<ContractDefinition const*, vector<ASTPointer<Expression>> const*> baseArguments; |
|
|
|
|
|
|
|
// 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()) |
|
|
|
for (auto const& modifier: constructor->getModifiers()) |
|
|
|
{ |
|
|
|
auto baseContract = dynamic_cast<ContractDefinition const*>( |
|
|
|
modifier->getName()->getReferencedDeclaration()); |
|
|
|
if (baseContract) |
|
|
|
if (m_baseArguments.count(baseContract->getConstructor()) == 0) |
|
|
|
m_baseArguments[baseContract->getConstructor()] = &modifier->getArguments(); |
|
|
|
} |
|
|
|
|
|
|
|
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(); |
|
|
|
} |
|
|
|
|
|
|
|
// Call constructors in base-to-derived order.
|
|
|
|
// The Constructor for the most derived contract is called later.
|
|
|
|
for (unsigned i = 1; i < bases.size(); i++) |
|
|
|
{ |
|
|
|
ContractDefinition const* base = bases[bases.size() - i]; |
|
|
|
solAssert(base, ""); |
|
|
|
initializeStateVariables(*base); |
|
|
|
FunctionDefinition const* baseConstructor = base->getConstructor(); |
|
|
|
if (!baseConstructor) |
|
|
|
continue; |
|
|
|
solAssert(baseArguments[base], ""); |
|
|
|
appendBaseConstructorCall(*baseConstructor, *baseArguments[base]); |
|
|
|
if (m_baseArguments.count(baseContract->getConstructor()) == 0) |
|
|
|
m_baseArguments[baseContract->getConstructor()] = &base->getArguments(); |
|
|
|
} |
|
|
|
} |
|
|
|
initializeStateVariables(_contract); |
|
|
|
if (_contract.getConstructor()) |
|
|
|
appendConstructorCall(*_contract.getConstructor()); |
|
|
|
// Initialization of state variables in base-to-derived order.
|
|
|
|
for (ContractDefinition const* contract: boost::adaptors::reverse(bases)) |
|
|
|
initializeStateVariables(*contract); |
|
|
|
|
|
|
|
if (FunctionDefinition const* constructor = _contract.getConstructor()) |
|
|
|
appendConstructor(*constructor); |
|
|
|
else if (auto c = m_context.getNextConstructor(_contract)) |
|
|
|
appendBaseConstructor(*c); |
|
|
|
|
|
|
|
eth::AssemblyItem sub = m_context.addSubroutine(_runtimeContext.getAssembly()); |
|
|
|
// stack contains sub size
|
|
|
@ -126,22 +130,23 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void Compiler::appendBaseConstructorCall(FunctionDefinition const& _constructor, |
|
|
|
vector<ASTPointer<Expression>> const& _arguments) |
|
|
|
void Compiler::appendBaseConstructor(FunctionDefinition const& _constructor) |
|
|
|
{ |
|
|
|
CompilerContext::LocationSetter locationSetter(m_context, &_constructor); |
|
|
|
FunctionType constructorType(_constructor); |
|
|
|
eth::AssemblyItem returnLabel = m_context.pushNewTag(); |
|
|
|
for (unsigned i = 0; i < _arguments.size(); ++i) |
|
|
|
compileExpression(*_arguments[i], constructorType.getParameterTypes()[i]); |
|
|
|
m_context.appendJumpTo(m_context.getFunctionEntryLabel(_constructor)); |
|
|
|
m_context << returnLabel; |
|
|
|
if (!constructorType.getParameterTypes().empty()) |
|
|
|
{ |
|
|
|
std::vector<ASTPointer<Expression>> const* arguments = m_baseArguments[&_constructor]; |
|
|
|
solAssert(arguments, ""); |
|
|
|
for (unsigned i = 0; i < arguments->size(); ++i) |
|
|
|
compileExpression(*(arguments->at(i)), constructorType.getParameterTypes()[i]); |
|
|
|
} |
|
|
|
_constructor.accept(*this); |
|
|
|
} |
|
|
|
|
|
|
|
void Compiler::appendConstructorCall(FunctionDefinition const& _constructor) |
|
|
|
void Compiler::appendConstructor(FunctionDefinition const& _constructor) |
|
|
|
{ |
|
|
|
CompilerContext::LocationSetter locationSetter(m_context, &_constructor); |
|
|
|
eth::AssemblyItem returnTag = m_context.pushNewTag(); |
|
|
|
// copy constructor arguments from code to memory and then to stack, they are supplied after the actual program
|
|
|
|
unsigned argumentSize = 0; |
|
|
|
for (ASTPointer<VariableDeclaration> const& var: _constructor.getParameters()) |
|
|
@ -155,8 +160,7 @@ void Compiler::appendConstructorCall(FunctionDefinition const& _constructor) |
|
|
|
m_context << eth::Instruction::CODECOPY; |
|
|
|
appendCalldataUnpacker(FunctionType(_constructor).getParameterTypes(), true); |
|
|
|
} |
|
|
|
m_context.appendJumpTo(m_context.getFunctionEntryLabel(_constructor)); |
|
|
|
m_context << returnTag; |
|
|
|
_constructor.accept(*this); |
|
|
|
} |
|
|
|
|
|
|
|
void Compiler::appendFunctionSelector(ContractDefinition const& _contract) |
|
|
@ -296,28 +300,36 @@ bool Compiler::visit(FunctionDefinition const& _function) |
|
|
|
// although note that this reduces the size of the visible stack
|
|
|
|
|
|
|
|
m_context.startFunction(_function); |
|
|
|
m_returnTag = m_context.newTag(); |
|
|
|
m_breakTags.clear(); |
|
|
|
m_continueTags.clear(); |
|
|
|
m_stackCleanupForReturn = 0; |
|
|
|
m_currentFunction = &_function; |
|
|
|
m_modifierDepth = 0; |
|
|
|
|
|
|
|
// stack upon entry: [return address] [arg0] [arg1] ... [argn]
|
|
|
|
// reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp]
|
|
|
|
|
|
|
|
unsigned parametersSize = CompilerUtils::getSizeOnStack(_function.getParameters()); |
|
|
|
m_context.adjustStackOffset(parametersSize); |
|
|
|
if (!_function.isConstructor()) |
|
|
|
// adding 1 for return address.
|
|
|
|
m_context.adjustStackOffset(parametersSize + 1); |
|
|
|
for (ASTPointer<VariableDeclaration const> const& variable: _function.getParameters()) |
|
|
|
{ |
|
|
|
m_context.addVariable(*variable, parametersSize); |
|
|
|
parametersSize -= variable->getType()->getSizeOnStack(); |
|
|
|
} |
|
|
|
|
|
|
|
for (ASTPointer<VariableDeclaration const> const& variable: _function.getReturnParameters()) |
|
|
|
m_context.addAndInitializeVariable(*variable); |
|
|
|
for (VariableDeclaration const* localVariable: _function.getLocalVariables()) |
|
|
|
m_context.addAndInitializeVariable(*localVariable); |
|
|
|
|
|
|
|
if (_function.isConstructor()) |
|
|
|
if (auto c = m_context.getNextConstructor(dynamic_cast<ContractDefinition const&>(*_function.getScope()))) |
|
|
|
appendBaseConstructor(*c); |
|
|
|
|
|
|
|
m_returnTag = m_context.newTag(); |
|
|
|
m_breakTags.clear(); |
|
|
|
m_continueTags.clear(); |
|
|
|
m_stackCleanupForReturn = 0; |
|
|
|
m_currentFunction = &_function; |
|
|
|
m_modifierDepth = 0; |
|
|
|
|
|
|
|
appendModifierOrFunctionCode(); |
|
|
|
|
|
|
|
m_context << m_returnTag; |
|
|
@ -352,8 +364,14 @@ bool Compiler::visit(FunctionDefinition const& _function) |
|
|
|
} |
|
|
|
//@todo assert that everything is in place now
|
|
|
|
|
|
|
|
m_context << eth::Instruction::JUMP; |
|
|
|
for (ASTPointer<VariableDeclaration const> const& variable: _function.getParameters() + _function.getReturnParameters()) |
|
|
|
m_context.removeVariable(*variable); |
|
|
|
for (VariableDeclaration const* localVariable: _function.getLocalVariables()) |
|
|
|
m_context.removeVariable(*localVariable); |
|
|
|
|
|
|
|
m_context.adjustStackOffset(-c_returnValuesSize); |
|
|
|
if (!_function.isConstructor()) |
|
|
|
m_context << eth::Instruction::JUMP; |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
@ -515,6 +533,16 @@ void Compiler::appendModifierOrFunctionCode() |
|
|
|
else |
|
|
|
{ |
|
|
|
ASTPointer<ModifierInvocation> const& modifierInvocation = m_currentFunction->getModifiers()[m_modifierDepth]; |
|
|
|
|
|
|
|
// constructor call should be excluded
|
|
|
|
if (dynamic_cast<ContractDefinition const*>(modifierInvocation->getName()->getReferencedDeclaration())) |
|
|
|
{ |
|
|
|
++m_modifierDepth; |
|
|
|
appendModifierOrFunctionCode(); |
|
|
|
--m_modifierDepth; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
ModifierDefinition const& modifier = m_context.getFunctionModifier(modifierInvocation->getName()->getName()); |
|
|
|
CompilerContext::LocationSetter locationSetter(m_context, &modifier); |
|
|
|
solAssert(modifier.getParameters().size() == modifierInvocation->getArguments().size(), ""); |
|
|
|