mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Provide inline assembly to the code generator. (#840)
* Directly usable inline assembly. * Add missing header.
This commit is contained in:
parent
c547f9c24b
commit
77f4424589
@ -23,9 +23,12 @@
|
|||||||
#include <libsolidity/codegen/CompilerContext.h>
|
#include <libsolidity/codegen/CompilerContext.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
#include <libsolidity/codegen/Compiler.h>
|
#include <libsolidity/codegen/Compiler.h>
|
||||||
#include <libsolidity/interface/Version.h>
|
#include <libsolidity/interface/Version.h>
|
||||||
|
#include <libsolidity/inlineasm/AsmData.h>
|
||||||
|
#include <libsolidity/inlineasm/AsmStack.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -172,6 +175,51 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node)
|
|||||||
updateSourceLocation();
|
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)
|
void CompilerContext::injectVersionStampIntoSub(size_t _subIndex)
|
||||||
{
|
{
|
||||||
eth::Assembly& sub = m_asm.sub(_subIndex);
|
eth::Assembly& sub = m_asm.sub(_subIndex);
|
||||||
|
@ -132,6 +132,15 @@ public:
|
|||||||
CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; }
|
CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; }
|
||||||
CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); 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"
|
/// Prepends "PUSH <compiler version number> POP"
|
||||||
void injectVersionStampIntoSub(size_t _subIndex);
|
void injectVersionStampIntoSub(size_t _subIndex);
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <boost/range/adaptor/reversed.hpp>
|
#include <boost/range/adaptor/reversed.hpp>
|
||||||
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
#include <libdevcore/Common.h>
|
#include <libdevcore/Common.h>
|
||||||
#include <libdevcore/SHA3.h>
|
#include <libdevcore/SHA3.h>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <libevmasm/Assembly.h>
|
#include <libevmasm/Assembly.h>
|
||||||
#include <libevmasm/SourceLocation.h>
|
#include <libevmasm/SourceLocation.h>
|
||||||
|
#include <libsolidity/parsing/Scanner.h>
|
||||||
#include <libsolidity/inlineasm/AsmParser.h>
|
#include <libsolidity/inlineasm/AsmParser.h>
|
||||||
#include <libsolidity/inlineasm/AsmCodeGen.h>
|
#include <libsolidity/inlineasm/AsmCodeGen.h>
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ using namespace dev;
|
|||||||
using namespace dev::solidity;
|
using namespace dev::solidity;
|
||||||
using namespace dev::solidity::assembly;
|
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>();
|
m_parserResult = make_shared<Block>();
|
||||||
Parser parser(m_errors);
|
Parser parser(m_errors);
|
||||||
@ -49,3 +50,22 @@ eth::Assembly InlineAssemblyStack::assemble()
|
|||||||
return codeGen.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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <libsolidity/interface/Exceptions.h>
|
#include <libsolidity/interface/Exceptions.h>
|
||||||
|
#include <libsolidity/inlineasm/AsmCodeGen.h>
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
{
|
{
|
||||||
@ -47,6 +48,13 @@ public:
|
|||||||
bool parse(std::shared_ptr<Scanner> const& _scanner);
|
bool parse(std::shared_ptr<Scanner> const& _scanner);
|
||||||
eth::Assembly assemble();
|
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; }
|
ErrorList const& errors() const { return m_errors; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Loading…
Reference in New Issue
Block a user