diff options
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/codegen/CompilerContext.cpp | 48 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.h | 9 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 1 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmStack.cpp | 22 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmStack.h | 8 |
5 files changed, 87 insertions, 1 deletions
diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index c1dc8dfb..3ac5bd3c 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -23,9 +23,12 @@ #include <libsolidity/codegen/CompilerContext.h> #include <utility> #include <numeric> +#include <boost/algorithm/string/replace.hpp> #include <libsolidity/ast/AST.h> #include <libsolidity/codegen/Compiler.h> #include <libsolidity/interface/Version.h> +#include <libsolidity/inlineasm/AsmData.h> +#include <libsolidity/inlineasm/AsmStack.h> using namespace std; @@ -172,6 +175,51 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node) updateSourceLocation(); } +void CompilerContext::appendInlineAssembly( + string const& _assembly, + vector<string> const& _localVariables, + map<string, string> const& _replacements +) +{ + string replacedAssembly; + string const* assembly = &_assembly; + if (!_replacements.empty()) + { + replacedAssembly = _assembly; + for (auto const& replacement: _replacements) + replacedAssembly = boost::algorithm::replace_all_copy(replacedAssembly, replacement.first, replacement.second); + assembly = &replacedAssembly; + } + + unsigned startStackHeight = stackHeight(); + auto identifierAccess = [&]( + assembly::Identifier const& _identifier, + eth::Assembly& _assembly, + assembly::CodeGenerator::IdentifierContext _context + ) { + auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name); + if (it == _localVariables.end()) + return false; + unsigned stackDepth = _localVariables.end() - it; + int stackDiff = _assembly.deposit() - startStackHeight + stackDepth; + if (stackDiff < 1 || stackDiff > 16) + BOOST_THROW_EXCEPTION( + CompilerError() << + errinfo_comment("Stack too deep, try removing local variables.") + ); + if (_context == assembly::CodeGenerator::IdentifierContext::RValue) + _assembly.append(dupInstruction(stackDiff)); + else + { + _assembly.append(swapInstruction(stackDiff)); + _assembly.append(Instruction::POP); + } + return true; + }; + + solAssert(assembly::InlineAssemblyStack().parseAndAssemble(*assembly, m_asm, identifierAccess), ""); +} + void CompilerContext::injectVersionStampIntoSub(size_t _subIndex) { eth::Assembly& sub = m_asm.sub(_subIndex); diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index a56335ce..0c1500b0 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -132,6 +132,15 @@ public: CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; } CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); return *this; } + /// Appends inline assembly. @a _replacements are string-matching replacements that are performed + /// prior to parsing the inline assembly. + /// @param _localVariables assigns stack positions to variables with the last one being the stack top + void appendInlineAssembly( + std::string const& _assembly, + std::vector<std::string> const& _localVariables = std::vector<std::string>(), + std::map<std::string, std::string> const& _replacements = std::map<std::string, std::string>{} + ); + /// Prepends "PUSH <compiler version number> POP" void injectVersionStampIntoSub(size_t _subIndex); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 3fbf27ce..41c14517 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -23,6 +23,7 @@ #include <utility> #include <numeric> #include <boost/range/adaptor/reversed.hpp> +#include <boost/algorithm/string/replace.hpp> #include <libdevcore/Common.h> #include <libdevcore/SHA3.h> #include <libsolidity/ast/AST.h> diff --git a/libsolidity/inlineasm/AsmStack.cpp b/libsolidity/inlineasm/AsmStack.cpp index c891678b..11c6e28f 100644 --- a/libsolidity/inlineasm/AsmStack.cpp +++ b/libsolidity/inlineasm/AsmStack.cpp @@ -24,6 +24,7 @@ #include <memory> #include <libevmasm/Assembly.h> #include <libevmasm/SourceLocation.h> +#include <libsolidity/parsing/Scanner.h> #include <libsolidity/inlineasm/AsmParser.h> #include <libsolidity/inlineasm/AsmCodeGen.h> @@ -32,7 +33,7 @@ using namespace dev; using namespace dev::solidity; using namespace dev::solidity::assembly; -bool InlineAssemblyStack::parse(const std::shared_ptr<Scanner>& _scanner) +bool InlineAssemblyStack::parse(shared_ptr<Scanner> const& _scanner) { m_parserResult = make_shared<Block>(); Parser parser(m_errors); @@ -49,3 +50,22 @@ eth::Assembly InlineAssemblyStack::assemble() return codeGen.assemble(); } +bool InlineAssemblyStack::parseAndAssemble( + string const& _input, + eth::Assembly& _assembly, + CodeGenerator::IdentifierAccess const& _identifierAccess +) +{ + ErrorList errors; + auto scanner = make_shared<Scanner>(CharStream(_input), "--CODEGEN--"); + auto parserResult = Parser(errors).parse(scanner); + if (!errors.empty()) + return false; + + CodeGenerator(*parserResult, errors).assemble(_assembly, _identifierAccess); + + // At this point, the assembly might be messed up, but we should throw an + // internal compiler error anyway. + return errors.empty(); +} + diff --git a/libsolidity/inlineasm/AsmStack.h b/libsolidity/inlineasm/AsmStack.h index 8a860e46..521f5fe7 100644 --- a/libsolidity/inlineasm/AsmStack.h +++ b/libsolidity/inlineasm/AsmStack.h @@ -25,6 +25,7 @@ #include <string> #include <functional> #include <libsolidity/interface/Exceptions.h> +#include <libsolidity/inlineasm/AsmCodeGen.h> namespace dev { @@ -47,6 +48,13 @@ public: bool parse(std::shared_ptr<Scanner> const& _scanner); eth::Assembly assemble(); + /// Parse and assemble a string in one run - for use in Solidity code generation itself. + bool parseAndAssemble( + std::string const& _input, + eth::Assembly& _assembly, + CodeGenerator::IdentifierAccess const& _identifierAccess = CodeGenerator::IdentifierAccess() + ); + ErrorList const& errors() const { return m_errors; } private: |