diff options
Diffstat (limited to 'Compiler.cpp')
-rw-r--r-- | Compiler.cpp | 88 |
1 files changed, 68 insertions, 20 deletions
diff --git a/Compiler.cpp b/Compiler.cpp index 6ed6480f..eadfc204 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -25,6 +25,7 @@ #include <boost/range/adaptor/reversed.hpp> #include <libevmcore/Instruction.h> #include <libevmasm/Assembly.h> +#include <libevmcore/Params.h> #include <libsolidity/AST.h> #include <libsolidity/ExpressionCompiler.h> #include <libsolidity/CompilerUtils.h> @@ -53,31 +54,45 @@ void Compiler::compileContract(ContractDefinition const& _contract, m_context = CompilerContext(); // clear it just in case { CompilerContext::LocationSetter locationSetterRunTime(m_context, _contract); - CompilerUtils(m_context).initialiseFreeMemoryPointer(); initializeContext(_contract, _contracts); appendFunctionSelector(_contract); - set<Declaration const*> functions = m_context.getFunctionsWithoutCode(); - while (!functions.empty()) - { - for (Declaration const* function: functions) - { - m_context.setStackOffset(0); - function->accept(*this); - } - functions = m_context.getFunctionsWithoutCode(); - } + appendFunctionsWithoutCode(); } // Swap the runtime context with the creation-time context swap(m_context, m_runtimeContext); CompilerContext::LocationSetter locationSetterCreationTime(m_context, _contract); - CompilerUtils(m_context).initialiseFreeMemoryPointer(); initializeContext(_contract, _contracts); packIntoContractCreator(_contract, m_runtimeContext); if (m_optimize) m_context.optimise(m_optimizeRuns); } +void Compiler::compileClone( + ContractDefinition const& _contract, + map<ContractDefinition const*, bytes const*> const& _contracts +) +{ + m_context = CompilerContext(); // clear it just in case + initializeContext(_contract, _contracts); + + appendInitAndConstructorCode(_contract); + + //@todo determine largest return size of all runtime functions + eth::AssemblyItem runtimeSub = m_context.addSubroutine(getCloneRuntime()); + solAssert(runtimeSub.data() < numeric_limits<size_t>::max(), ""); + m_runtimeSub = size_t(runtimeSub.data()); + + // stack contains sub size + m_context << eth::Instruction::DUP1 << runtimeSub << u256(0) << eth::Instruction::CODECOPY; + m_context << u256(0) << eth::Instruction::RETURN; + + appendFunctionsWithoutCode(); + + if (m_optimize) + m_context.optimise(m_optimizeRuns); +} + eth::AssemblyItem Compiler::getFunctionEntryLabel(FunctionDefinition const& _function) const { return m_runtimeContext.getFunctionEntryLabelIfExists(_function); @@ -86,13 +101,14 @@ eth::AssemblyItem Compiler::getFunctionEntryLabel(FunctionDefinition const& _fun void Compiler::initializeContext(ContractDefinition const& _contract, map<ContractDefinition const*, bytes const*> const& _contracts) { + CompilerUtils(m_context).initialiseFreeMemoryPointer(); m_context.setCompiledContracts(_contracts); m_context.setInheritanceHierarchy(_contract.getLinearizedBaseContracts()); registerStateVariables(_contract); m_context.resetVisitedNodes(&_contract); } -void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext) +void Compiler::appendInitAndConstructorCode(ContractDefinition const& _contract) { // Determine the arguments that are used for the base constructors. std::vector<ContractDefinition const*> const& bases = _contract.getLinearizedBaseContracts(); @@ -126,22 +142,22 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp appendConstructor(*constructor); else if (auto c = m_context.getNextConstructor(_contract)) appendBaseConstructor(*c); +} + +void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext) +{ + appendInitAndConstructorCode(_contract); eth::AssemblyItem runtimeSub = m_context.addSubroutine(_runtimeContext.getAssembly()); solAssert(runtimeSub.data() < numeric_limits<size_t>::max(), ""); m_runtimeSub = size_t(runtimeSub.data()); + // stack contains sub size m_context << eth::Instruction::DUP1 << runtimeSub << u256(0) << eth::Instruction::CODECOPY; m_context << u256(0) << eth::Instruction::RETURN; // 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(); - } + appendFunctionsWithoutCode(); } void Compiler::appendBaseConstructor(FunctionDefinition const& _constructor) @@ -618,6 +634,20 @@ bool Compiler::visit(PlaceholderStatement const& _placeholderStatement) return true; } +void Compiler::appendFunctionsWithoutCode() +{ + set<Declaration const*> functions = m_context.getFunctionsWithoutCode(); + while (!functions.empty()) + { + for (Declaration const* function: functions) + { + m_context.setStackOffset(0); + function->accept(*this); + } + functions = m_context.getFunctionsWithoutCode(); + } +} + void Compiler::appendModifierOrFunctionCode() { solAssert(m_currentFunction, ""); @@ -674,3 +704,21 @@ void Compiler::compileExpression(Expression const& _expression, TypePointer cons if (_targetType) CompilerUtils(m_context).convertType(*_expression.getType(), *_targetType); } + +eth::Assembly Compiler::getCloneRuntime() +{ + eth::Assembly a; + a << eth::Instruction::CALLDATASIZE; + a << u256(0) << eth::Instruction::DUP1 << eth::Instruction::CALLDATACOPY; + //@todo adjust for larger return values, make this dynamic. + a << u256(0x20) << u256(0) << eth::Instruction::CALLDATASIZE; + a << u256(0) << eth::Instruction::DUP1; + // this is the address which has to be substituted by the linker. + //@todo implement as special "marker" AssemblyItem. + a << u256("0xcafecafecafecafecafecafecafecafecafecafe"); + a << u256(eth::c_callGas + 10) << eth::Instruction::GAS << eth::Instruction::SUB; + a << eth::Instruction::CALLCODE; + //@todo adjust for larger return values, make this dynamic. + a << u256(0x20) << u256(0) << eth::Instruction::RETURN; + return a; +} |