diff options
author | chriseth <c@ethdev.com> | 2015-09-10 18:01:05 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2015-09-11 21:21:37 +0800 |
commit | a9edc7b1a601747f96e47fe60a5fc10df489696f (patch) | |
tree | 8165a9a44cc6cf23f6a8d8b152facfe3fd65a909 /libsolidity | |
parent | 337fde9d11adac85800b405a3fdb4bcd09039ebf (diff) | |
download | dexon-solidity-a9edc7b1a601747f96e47fe60a5fc10df489696f.tar dexon-solidity-a9edc7b1a601747f96e47fe60a5fc10df489696f.tar.gz dexon-solidity-a9edc7b1a601747f96e47fe60a5fc10df489696f.tar.bz2 dexon-solidity-a9edc7b1a601747f96e47fe60a5fc10df489696f.tar.lz dexon-solidity-a9edc7b1a601747f96e47fe60a5fc10df489696f.tar.xz dexon-solidity-a9edc7b1a601747f96e47fe60a5fc10df489696f.tar.zst dexon-solidity-a9edc7b1a601747f96e47fe60a5fc10df489696f.zip |
Transition from bytecode to more general linker objects.
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/Compiler.cpp | 15 | ||||
-rw-r--r-- | libsolidity/Compiler.h | 19 | ||||
-rw-r--r-- | libsolidity/CompilerContext.cpp | 2 | ||||
-rw-r--r-- | libsolidity/CompilerContext.h | 10 | ||||
-rw-r--r-- | libsolidity/CompilerStack.cpp | 42 | ||||
-rw-r--r-- | libsolidity/CompilerStack.h | 27 | ||||
-rw-r--r-- | libsolidity/ExpressionCompiler.cpp | 9 |
7 files changed, 68 insertions, 56 deletions
diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 8394efa3..0b4fd20d 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -48,8 +48,9 @@ private: unsigned stackHeight; }; -void Compiler::compileContract(ContractDefinition const& _contract, - map<ContractDefinition const*, bytes const*> const& _contracts) +void Compiler::compileContract( + ContractDefinition const& _contract, + std::map<const ContractDefinition*, eth::Assembly const*> const& _contracts) { m_context = CompilerContext(); // clear it just in case { @@ -70,7 +71,7 @@ void Compiler::compileContract(ContractDefinition const& _contract, void Compiler::compileClone( ContractDefinition const& _contract, - map<ContractDefinition const*, bytes const*> const& _contracts + map<ContractDefinition const*, eth::Assembly const*> const& _contracts ) { m_context = CompilerContext(); // clear it just in case @@ -98,11 +99,13 @@ eth::AssemblyItem Compiler::functionEntryLabel(FunctionDefinition const& _functi return m_runtimeContext.functionEntryLabelIfExists(_function); } -void Compiler::initializeContext(ContractDefinition const& _contract, - map<ContractDefinition const*, bytes const*> const& _contracts) +void Compiler::initializeContext( + ContractDefinition const& _contract, + map<ContractDefinition const*, eth::Assembly const*> const& _compiledContracts +) { CompilerUtils(m_context).initialiseFreeMemoryPointer(); - m_context.setCompiledContracts(_contracts); + m_context.setCompiledContracts(_compiledContracts); m_context.setInheritanceHierarchy(_contract.linearizedBaseContracts()); registerStateVariables(_contract); m_context.resetVisitedNodes(&_contract); diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index f283683f..7e1d3222 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -42,16 +42,19 @@ public: { } - void compileContract(ContractDefinition const& _contract, - std::map<ContractDefinition const*, bytes const*> const& _contracts); + void compileContract( + ContractDefinition const& _contract, + std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts + ); /// Compiles a contract that uses CALLCODE to call into a pre-deployed version of the given /// contract at runtime, but contains the full creation-time code. void compileClone( ContractDefinition const& _contract, - std::map<ContractDefinition const*, bytes const*> const& _contracts + std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts ); - bytes assembledBytecode() { return m_context.assembledBytecode(); } - bytes runtimeBytecode() { return m_context.assembledRuntimeBytecode(m_runtimeSub); } + eth::Assembly const& assembly() { return m_context.assembly(); } + eth::LinkerObject assembledObject() { return m_context.assembledObject(); } + eth::LinkerObject runtimeObject() { return m_context.assembledRuntimeObject(m_runtimeSub); } /// @arg _sourceCodes is the map of input files to source code strings /// @arg _inJsonFromat shows whether the out should be in Json format Json::Value streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const @@ -69,8 +72,10 @@ public: private: /// Registers the non-function objects inside the contract with the context. - void initializeContext(ContractDefinition const& _contract, - std::map<ContractDefinition const*, bytes const*> const& _contracts); + void initializeContext( + ContractDefinition const& _contract, + std::map<ContractDefinition const*, eth::Assembly const*> const& _compiledContracts + ); /// 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. void packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext); diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp index af93578f..717627a5 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/CompilerContext.cpp @@ -65,7 +65,7 @@ void CompilerContext::removeVariable(VariableDeclaration const& _declaration) m_localVariables.erase(&_declaration); } -bytes const& CompilerContext::compiledContract(const ContractDefinition& _contract) const +eth::Assembly const& CompilerContext::compiledContract(const ContractDefinition& _contract) const { auto ret = m_compiledContracts.find(&_contract); solAssert(ret != m_compiledContracts.end(), "Compiled contract not found."); diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 590c8797..34b63a9c 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -47,8 +47,8 @@ public: void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0); void removeVariable(VariableDeclaration const& _declaration); - void setCompiledContracts(std::map<ContractDefinition const*, bytes const*> const& _contracts) { m_compiledContracts = _contracts; } - bytes const& compiledContract(ContractDefinition const& _contract) const; + void setCompiledContracts(std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts) { m_compiledContracts = _contracts; } + eth::Assembly const& compiledContract(ContractDefinition const& _contract) const; void setStackOffset(int _offset) { m_asm.setDeposit(_offset); } void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } @@ -135,8 +135,8 @@ public: return m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat); } - bytes assembledBytecode() { return m_asm.assemble(); } - bytes assembledRuntimeBytecode(size_t _subIndex) { m_asm.assemble(); return m_asm.data(u256(_subIndex)); } + eth::LinkerObject const& assembledObject() { return m_asm.assemble(); } + eth::LinkerObject const& assembledRuntimeObject(size_t _subIndex) { return m_asm.sub(_subIndex).assemble(); } /** * Helper class to pop the visited nodes stack when a scope closes @@ -164,7 +164,7 @@ private: /// Magic global variables like msg, tx or this, distinguished by type. std::set<Declaration const*> m_magicGlobals; /// Other already compiled contracts to be used in contract creation calls. - std::map<ContractDefinition const*, bytes const*> m_compiledContracts; + std::map<ContractDefinition const*, eth::Assembly const*> m_compiledContracts; /// Storage offsets of state variables std::map<Declaration const*, std::pair<u256, unsigned>> m_stateVariables; /// Offsets of local variables on the stack (relative to stack base). diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 385533b2..3da982a4 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -153,7 +153,7 @@ void CompilerStack::compile(bool _optimize, unsigned _runs) if (!m_parseSuccessful) parse(); - map<ContractDefinition const*, bytes const*> contractBytecode; + map<ContractDefinition const*, eth::Assembly const*> compiledContracts; for (Source const* source: m_sourceOrder) for (ASTPointer<ASTNode> const& node: source->ast->nodes()) if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get())) @@ -161,26 +161,24 @@ void CompilerStack::compile(bool _optimize, unsigned _runs) if (!contract->isFullyImplemented()) continue; shared_ptr<Compiler> compiler = make_shared<Compiler>(_optimize, _runs); - compiler->compileContract(*contract, contractBytecode); + compiler->compileContract(*contract, compiledContracts); Contract& compiledContract = m_contracts.at(contract->name()); - compiledContract.bytecode = compiler->assembledBytecode(); - compiledContract.runtimeBytecode = compiler->runtimeBytecode(); - compiledContract.compiler = move(compiler); - compiler = make_shared<Compiler>(_optimize, _runs); - compiler->compileContract(*contract, contractBytecode); - contractBytecode[compiledContract.contract] = &compiledContract.bytecode; + compiledContract.compiler = compiler; + compiledContract.object = compiler->assembledObject(); + compiledContract.runtimeObject = compiler->runtimeObject(); + compiledContracts[compiledContract.contract] = &compiler->assembly(); Compiler cloneCompiler(_optimize, _runs); - cloneCompiler.compileClone(*contract, contractBytecode); - compiledContract.cloneBytecode = cloneCompiler.assembledBytecode(); + cloneCompiler.compileClone(*contract, compiledContracts); + compiledContract.cloneObject = cloneCompiler.assembledObject(); } } -bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize) +eth::LinkerObject const& CompilerStack::compile(string const& _sourceCode, bool _optimize) { parse(_sourceCode); compile(_optimize); - return bytecode(); + return object(); } eth::AssemblyItems const* CompilerStack::assemblyItems(string const& _contractName) const @@ -195,24 +193,28 @@ eth::AssemblyItems const* CompilerStack::runtimeAssemblyItems(string const& _con return currentContract.compiler ? &contract(_contractName).compiler->runtimeAssemblyItems() : nullptr; } -bytes const& CompilerStack::bytecode(string const& _contractName) const +eth::LinkerObject const& CompilerStack::object(string const& _contractName) const { - return contract(_contractName).bytecode; + return contract(_contractName).object; } -bytes const& CompilerStack::runtimeBytecode(string const& _contractName) const +eth::LinkerObject const& CompilerStack::runtimeObject(string const& _contractName) const { - return contract(_contractName).runtimeBytecode; + return contract(_contractName).runtimeObject; } -bytes const& CompilerStack::cloneBytecode(string const& _contractName) const +eth::LinkerObject const& CompilerStack::cloneObject(string const& _contractName) const { - return contract(_contractName).cloneBytecode; + return contract(_contractName).cloneObject; } dev::h256 CompilerStack::contractCodeHash(string const& _contractName) const { - return dev::sha3(runtimeBytecode(_contractName)); + auto const& obj = runtimeObject(_contractName); + if (obj.bytecode.empty() || !obj.linkReferences.empty()) + return dev::h256(); + else + return dev::sha3(obj.bytecode); } Json::Value CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes, bool _inJsonFormat) const @@ -305,7 +307,7 @@ size_t CompilerStack::functionEntryPoint( return 0; } -bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize) +eth::LinkerObject CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize) { CompilerStack stack; return stack.compile(_sourceCode, _optimize); diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 0d812e02..8db8aff4 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -32,6 +32,7 @@ #include <libdevcore/Common.h> #include <libdevcore/FixedHash.h> #include <libevmasm/SourceLocation.h> +#include <libevmasm/LinkerObject.h> namespace dev { @@ -92,23 +93,25 @@ public: /// Compiles the source units that were previously added and parsed. void compile(bool _optimize = false, unsigned _runs = 200); /// Parses and compiles the given source code. - /// @returns the compiled bytecode - bytes const& compile(std::string const& _sourceCode, bool _optimize = false); + /// @returns the compiled linker object + eth::LinkerObject const& compile(std::string const& _sourceCode, bool _optimize = false); - /// @returns the assembled bytecode for a contract. - bytes const& bytecode(std::string const& _contractName = "") const; - /// @returns the runtime bytecode for the contract, i.e. the code that is returned by the constructor. - bytes const& runtimeBytecode(std::string const& _contractName = "") const; + /// @returns the assembled bytecode for a contract (empty if it has to be linked or lacks implementation). + eth::LinkerObject const& object(std::string const& _contractName = "") const; + /// @returns the runtime bytecode for the contract (empty if it has to be linked or lacks implementation). + eth::LinkerObject const& runtimeObject(std::string const& _contractName = "") const; /// @returns the bytecode of a contract that uses an already deployed contract via CALLCODE. /// The returned bytes will contain a sequence of 20 bytes of the format "XXX...XXX" which have to /// substituted by the actual address. Note that this sequence starts end ends in three X /// characters but can contain anything in between. - bytes const& cloneBytecode(std::string const& _contractName = "") const; + eth::LinkerObject const& cloneObject(std::string const& _contractName = "") const; /// @returns normal contract assembly items eth::AssemblyItems const* assemblyItems(std::string const& _contractName = "") const; /// @returns runtime contract assembly items eth::AssemblyItems const* runtimeAssemblyItems(std::string const& _contractName = "") const; - /// @returns hash of the runtime bytecode for the contract, i.e. the code that is returned by the constructor. + /// @returns hash of the runtime bytecode for the contract, i.e. the code that is + /// returned by the constructor or the zero-h256 if the contract still needs to be linked or + /// does not have runtime code. dev::h256 contractCodeHash(std::string const& _contractName = "") const; /// Streams a verbose version of the assembly to @a _outStream. @@ -146,7 +149,7 @@ public: /// Compile the given @a _sourceCode to bytecode. If a scanner is provided, it is used for /// scanning the source code - this is useful for printing exception information. - static bytes staticCompile(std::string const& _sourceCode, bool _optimize = false); + static eth::LinkerObject staticCompile(std::string const& _sourceCode, bool _optimize = false); /// Helper function for logs printing. Do only use in error cases, it's quite expensive. /// line and columns are numbered starting from 1 with following order: @@ -170,9 +173,9 @@ private: { ContractDefinition const* contract = nullptr; std::shared_ptr<Compiler> compiler; - bytes bytecode; - bytes runtimeBytecode; - bytes cloneBytecode; + eth::LinkerObject object; + eth::LinkerObject runtimeObject; + eth::LinkerObject cloneObject; std::shared_ptr<InterfaceHandler> interfaceHandler; mutable std::unique_ptr<std::string const> interface; mutable std::unique_ptr<std::string const> solidityInterface; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index d5a8362e..9cecf6b6 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -454,12 +454,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) ContractDefinition const& contract = dynamic_cast<ContractType const&>(*function.returnParameterTypes().front()).contractDefinition(); // copy the contract's code into memory - bytes const& bytecode = m_context.compiledContract(contract); + eth::Assembly const& assembly = m_context.compiledContract(contract); utils().fetchFreeMemoryPointer(); - m_context << u256(bytecode.size()) << eth::Instruction::DUP1; - //@todo could be done by actually appending the Assembly, but then we probably need to compile - // multiple times. Will revisit once external fuctions are inlined. - m_context.appendData(bytecode); + // pushes size + eth::AssemblyItem subroutine = m_context.addSubroutine(assembly); + m_context << eth::Instruction::DUP1 << subroutine; m_context << eth::Instruction::DUP4 << eth::Instruction::CODECOPY; m_context << eth::Instruction::ADD; |