diff options
Diffstat (limited to 'libsolidity/inlineasm')
-rw-r--r-- | libsolidity/inlineasm/AsmCodeGen.cpp | 42 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmCodeGen.h | 18 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmStack.cpp | 2 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmStack.h | 22 |
4 files changed, 55 insertions, 29 deletions
diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libsolidity/inlineasm/AsmCodeGen.cpp index 1caaa677..d094aa97 100644 --- a/libsolidity/inlineasm/AsmCodeGen.cpp +++ b/libsolidity/inlineasm/AsmCodeGen.cpp @@ -81,7 +81,7 @@ public: explicit CodeTransform( GeneratorState& _state, assembly::Block const& _block, - assembly::CodeGenerator::IdentifierAccess const& _identifierAccess = assembly::CodeGenerator::IdentifierAccess() + assembly::ExternalIdentifierAccess const& _identifierAccess = assembly::ExternalIdentifierAccess() ): m_state(_state), m_scope(*m_state.scopes.at(&_block)), @@ -160,15 +160,23 @@ public: { return; } - solAssert(m_identifierAccess, "Identifier not found and no external access available."); - if (!m_identifierAccess(_identifier, m_state.assembly, CodeGenerator::IdentifierContext::RValue)) + solAssert( + m_identifierAccess.resolve && m_identifierAccess.generateCode, + "Identifier not found and no external access available." + ); + // @TODO refactor: Store resolved identifier. + size_t size = m_identifierAccess.resolve(_identifier, IdentifierContext::RValue); + if (size != size_t(-1)) + m_identifierAccess.generateCode(_identifier, IdentifierContext::RValue, m_state.assembly); + else { m_state.addError( Error::Type::DeclarationError, "Identifier not found or not unique", _identifier.location ); - m_state.assembly.append(u256(0)); + for (size_t i = 0; i < size; ++i) + m_state.assembly.append(u256(0)); } } void operator()(FunctionalInstruction const& _instr) @@ -236,12 +244,20 @@ private: m_state.assembly.append(solidity::Instruction::POP); return; } - solAssert(m_identifierAccess, "Identifier not found and no external access available."); - if (!m_identifierAccess(_variableName, m_state.assembly, CodeGenerator::IdentifierContext::LValue)) + solAssert( + m_identifierAccess.resolve && m_identifierAccess.generateCode, + "Identifier not found and no external access available." + ); + size_t size = m_identifierAccess.resolve(_variableName, IdentifierContext::LValue); + if (size != size_t(-1)) + m_identifierAccess.generateCode(_variableName, IdentifierContext::LValue, m_state.assembly); + else + { m_state.addError( Error::Type::DeclarationError, "Identifier \"" + string(_variableName.name) + "\" not found, not unique or not lvalue." ); + } } /// Determines the stack height difference to the given variables. Automatically generates @@ -289,34 +305,34 @@ private: GeneratorState& m_state; Scope& m_scope; int const m_initialDeposit; - assembly::CodeGenerator::IdentifierAccess m_identifierAccess; + ExternalIdentifierAccess m_identifierAccess; }; -bool assembly::CodeGenerator::typeCheck(assembly::CodeGenerator::IdentifierAccess const& _identifierAccess) +bool assembly::CodeGenerator::typeCheck(ExternalIdentifierAccess const& _identifierAccess) { size_t initialErrorLen = m_errors.size(); eth::Assembly assembly; GeneratorState state(m_errors, assembly); - if (!(AsmAnalyzer(state.scopes, m_errors, !!_identifierAccess)).analyze(m_parsedData)) + if (!(AsmAnalyzer(state.scopes, m_errors, !!_identifierAccess.resolve)).analyze(m_parsedData)) return false; CodeTransform(state, m_parsedData, _identifierAccess); return m_errors.size() == initialErrorLen; } -eth::Assembly assembly::CodeGenerator::assemble(assembly::CodeGenerator::IdentifierAccess const& _identifierAccess) +eth::Assembly assembly::CodeGenerator::assemble(ExternalIdentifierAccess const& _identifierAccess) { eth::Assembly assembly; GeneratorState state(m_errors, assembly); - if (!(AsmAnalyzer(state.scopes, m_errors, !!_identifierAccess)).analyze(m_parsedData)) + if (!(AsmAnalyzer(state.scopes, m_errors, !!_identifierAccess.resolve)).analyze(m_parsedData)) solAssert(false, "Assembly error"); CodeTransform(state, m_parsedData, _identifierAccess); return assembly; } -void assembly::CodeGenerator::assemble(eth::Assembly& _assembly, assembly::CodeGenerator::IdentifierAccess const& _identifierAccess) +void assembly::CodeGenerator::assemble(eth::Assembly& _assembly, ExternalIdentifierAccess const& _identifierAccess) { GeneratorState state(m_errors, _assembly); - if (!(AsmAnalyzer(state.scopes, m_errors, !!_identifierAccess)).analyze(m_parsedData)) + if (!(AsmAnalyzer(state.scopes, m_errors, !!_identifierAccess.resolve)).analyze(m_parsedData)) solAssert(false, "Assembly error"); CodeTransform(state, m_parsedData, _identifierAccess); } diff --git a/libsolidity/inlineasm/AsmCodeGen.h b/libsolidity/inlineasm/AsmCodeGen.h index bd71812e..f259a36c 100644 --- a/libsolidity/inlineasm/AsmCodeGen.h +++ b/libsolidity/inlineasm/AsmCodeGen.h @@ -22,8 +22,10 @@ #pragma once -#include <functional> #include <libsolidity/interface/Exceptions.h> +#include <libsolidity/inlineasm/AsmStack.h> + +#include <functional> namespace dev { @@ -36,27 +38,19 @@ namespace solidity namespace assembly { struct Block; -struct Identifier; class CodeGenerator { public: - enum class IdentifierContext { LValue, RValue }; - /// Function type that is called for external identifiers. Such a function should search for - /// the identifier and append appropriate assembly items to the assembly. If in lvalue context, - /// the value to assign is assumed to be on the stack and an assignment is to be performed. - /// If in rvalue context, the function is assumed to append instructions to - /// push the value of the identifier onto the stack. On error, the function should return false. - using IdentifierAccess = std::function<bool(assembly::Identifier const&, eth::Assembly&, IdentifierContext)>; CodeGenerator(Block const& _parsedData, ErrorList& _errors): m_parsedData(_parsedData), m_errors(_errors) {} /// Performs type checks and @returns false on error. /// Actually runs the full code generation but discards the result. - bool typeCheck(IdentifierAccess const& _identifierAccess = IdentifierAccess()); + bool typeCheck(ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess()); /// Performs code generation and @returns the result. - eth::Assembly assemble(IdentifierAccess const& _identifierAccess = IdentifierAccess()); + eth::Assembly assemble(ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess()); /// Performs code generation and appends generated to to _assembly. - void assemble(eth::Assembly& _assembly, IdentifierAccess const& _identifierAccess = IdentifierAccess()); + void assemble(eth::Assembly& _assembly, ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess()); private: Block const& m_parsedData; diff --git a/libsolidity/inlineasm/AsmStack.cpp b/libsolidity/inlineasm/AsmStack.cpp index 8d011cf8..09084642 100644 --- a/libsolidity/inlineasm/AsmStack.cpp +++ b/libsolidity/inlineasm/AsmStack.cpp @@ -66,7 +66,7 @@ eth::Assembly InlineAssemblyStack::assemble() bool InlineAssemblyStack::parseAndAssemble( string const& _input, eth::Assembly& _assembly, - CodeGenerator::IdentifierAccess const& _identifierAccess + ExternalIdentifierAccess const& _identifierAccess ) { ErrorList errors; diff --git a/libsolidity/inlineasm/AsmStack.h b/libsolidity/inlineasm/AsmStack.h index 4d5a99a4..b6e4952a 100644 --- a/libsolidity/inlineasm/AsmStack.h +++ b/libsolidity/inlineasm/AsmStack.h @@ -22,10 +22,10 @@ #pragma once +#include <libsolidity/interface/Exceptions.h> + #include <string> #include <functional> -#include <libsolidity/interface/Exceptions.h> -#include <libsolidity/inlineasm/AsmCodeGen.h> namespace dev { @@ -39,6 +39,22 @@ class Scanner; namespace assembly { struct Block; +struct Identifier; + +enum class IdentifierContext { LValue, RValue }; + +/// Object that is used to resolve references and generate code for access to identifiers external +/// to inline assembly (not used in standalone assembly mode). +struct ExternalIdentifierAccess +{ + /// Resolve a an external reference given by the identifier in the given context. + /// @returns the size of the value (number of stack slots) or size_t(-1) if not found. + std::function<size_t(assembly::Identifier const&, IdentifierContext)> resolve; + /// Generate code for retrieving the value (rvalue context) or storing the value (lvalue context) + /// of an identifier. The code should be appended to the assembly. In rvalue context, the value is supposed + /// to be put onto the stack, in lvalue context, the value is assumed to be at the top of the stack. + std::function<void(assembly::Identifier const&, IdentifierContext, eth::Assembly&)> generateCode; +}; class InlineAssemblyStack { @@ -56,7 +72,7 @@ public: bool parseAndAssemble( std::string const& _input, eth::Assembly& _assembly, - CodeGenerator::IdentifierAccess const& _identifierAccess = CodeGenerator::IdentifierAccess() + ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess() ); ErrorList const& errors() const { return m_errors; } |