From 261731f7eea48902983c55163d377e26bbca07da Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 23 May 2017 19:21:14 +0200 Subject: [PATCH] Adapt EVM codegen to new namespace. --- libjulia/backends/evm/EVMCodeTransform.cpp | 234 ++++++++++++++- libjulia/backends/evm/EVMCodeTransform.h | 272 +++++------------- libsolidity/CMakeLists.txt | 4 +- libsolidity/analysis/ReferencesResolver.cpp | 4 +- libsolidity/analysis/TypeChecker.cpp | 10 +- libsolidity/codegen/CompilerContext.cpp | 10 +- libsolidity/codegen/ContractCompiler.cpp | 8 +- libsolidity/inlineasm/AsmAnalysis.cpp | 6 +- libsolidity/inlineasm/AsmAnalysis.h | 4 +- libsolidity/inlineasm/AsmCodeGen.cpp | 22 +- libsolidity/inlineasm/AsmCodeGen.h | 4 +- libsolidity/inlineasm/AsmStack.cpp | 4 +- libsolidity/inlineasm/AsmStack.h | 23 +- ...endAssemblyStack.cpp => AssemblyStack.cpp} | 16 +- ...BackendAssemblyStack.h => AssemblyStack.h} | 14 +- solc/CommandLineInterface.cpp | 18 +- solc/CommandLineInterface.h | 4 +- 17 files changed, 364 insertions(+), 293 deletions(-) rename libsolidity/interface/{MultiBackendAssemblyStack.cpp => AssemblyStack.cpp} (80%) rename libsolidity/interface/{MultiBackendAssemblyStack.h => AssemblyStack.h} (85%) diff --git a/libjulia/backends/evm/EVMCodeTransform.cpp b/libjulia/backends/evm/EVMCodeTransform.cpp index 990df707f..18c3e63cc 100644 --- a/libjulia/backends/evm/EVMCodeTransform.cpp +++ b/libjulia/backends/evm/EVMCodeTransform.cpp @@ -18,4 +18,236 @@ * Common code generator for translating Julia / inline assembly to EVM and EVM1.5. */ -#include +#include + +#include +#include + +#include + +using namespace std; +using namespace dev; +using namespace dev::julia; +using namespace dev::solidity; +using namespace dev::solidity::assembly; + +CodeTransform::CodeTransform( + ErrorList& _errors, + AbstractAssembly& _assembly, + Block const& _block, + AsmAnalysisInfo& _analysisInfo, + ExternalIdentifierAccess const& _identifierAccess, + int _initialStackHeight +): + m_errors(_errors), + m_assembly(_assembly), + m_info(_analysisInfo), + m_scope(*_analysisInfo.scopes.at(&_block)), + m_identifierAccess(_identifierAccess), + m_initialStackHeight(_initialStackHeight) +{ + int blockStartStackHeight = m_assembly.stackHeight(); + std::for_each(_block.statements.begin(), _block.statements.end(), boost::apply_visitor(*this)); + + m_assembly.setSourceLocation(_block.location); + + // pop variables + for (auto const& identifier: m_scope.identifiers) + if (identifier.second.type() == typeid(Scope::Variable)) + m_assembly.appendInstruction(solidity::Instruction::POP); + + int deposit = m_assembly.stackHeight() - blockStartStackHeight; + solAssert(deposit == 0, "Invalid stack height at end of block."); +} + +void CodeTransform::operator()(const FunctionDefinition&) +{ + solAssert(false, "Function definition not removed during desugaring phase."); +} + +void CodeTransform::generateAssignment(Identifier const& _variableName, SourceLocation const& _location) +{ + auto var = m_scope.lookup(_variableName.name); + if (var) + { + Scope::Variable const& _var = boost::get(*var); + if (int heightDiff = variableHeightDiff(_var, _location, true)) + m_assembly.appendInstruction(solidity::swapInstruction(heightDiff - 1)); + m_assembly.appendInstruction(solidity::Instruction::POP); + } + else + { + solAssert( + m_identifierAccess.generateCode, + "Identifier not found and no external access available." + ); + m_identifierAccess.generateCode(_variableName, IdentifierContext::LValue, m_assembly); + } +} + +int CodeTransform::variableHeightDiff(solidity::assembly::Scope::Variable const& _var, SourceLocation const& _location, bool _forSwap) +{ + int heightDiff = m_assembly.stackHeight() - _var.stackHeight; + if (heightDiff <= (_forSwap ? 1 : 0) || heightDiff > (_forSwap ? 17 : 16)) + { + //@TODO move this to analysis phase. + m_errors.push_back(make_shared( + Error::Type::TypeError, + "Variable inaccessible, too deep inside stack (" + boost::lexical_cast(heightDiff) + ")", + _location + )); + return 0; + } + else + return heightDiff; +} + +void CodeTransform::expectDeposit(int _deposit, int _oldHeight) +{ + solAssert(m_assembly.stackHeight() == _oldHeight + _deposit, "Invalid stack deposit."); +} + +void CodeTransform::checkStackHeight(void const* _astElement) +{ + solAssert(m_info.stackHeightInfo.count(_astElement), "Stack height for AST element not found."); + solAssert( + m_info.stackHeightInfo.at(_astElement) == m_assembly.stackHeight() - m_initialStackHeight, + "Stack height mismatch between analysis and code generation phase." + ); +} + +void CodeTransform::assignLabelIdIfUnset(Scope::Label& _label) +{ + if (!_label.id) + _label.id.reset(m_assembly.newLabelId()); +} + +void CodeTransform::operator()(Block const& _block) +{ + CodeTransform(m_errors, m_assembly, _block, m_info, m_identifierAccess, m_initialStackHeight); + checkStackHeight(&_block); +} + +void CodeTransform::operator()(Switch const&) +{ + solAssert(false, "Switch not removed during desugaring phase."); +} + +void CodeTransform::operator()(VariableDeclaration const& _varDecl) +{ + int expectedItems = _varDecl.variables.size(); + int height = m_assembly.stackHeight(); + boost::apply_visitor(*this, *_varDecl.value); + expectDeposit(expectedItems, height); + for (auto const& variable: _varDecl.variables) + { + auto& var = boost::get(m_scope.identifiers.at(variable.name)); + var.stackHeight = height++; + var.active = true; + } +} + +void CodeTransform::operator()(Assignment const& _assignment) +{ + int height = m_assembly.stackHeight(); + boost::apply_visitor(*this, *_assignment.value); + expectDeposit(1, height); + m_assembly.setSourceLocation(_assignment.location); + generateAssignment(_assignment.variableName, _assignment.location); + checkStackHeight(&_assignment); +} + +void CodeTransform::operator()(StackAssignment const& _assignment) +{ + m_assembly.setSourceLocation(_assignment.location); + generateAssignment(_assignment.variableName, _assignment.location); + checkStackHeight(&_assignment); +} + +void CodeTransform::operator()(Label const& _label) +{ + m_assembly.setSourceLocation(_label.location); + solAssert(m_scope.identifiers.count(_label.name), ""); + Scope::Label& label = boost::get(m_scope.identifiers.at(_label.name)); + assignLabelIdIfUnset(label); + m_assembly.appendLabel(*label.id); + checkStackHeight(&_label); +} + +void CodeTransform::operator()(FunctionCall const&) +{ + solAssert(false, "Function call not removed during desugaring phase."); +} + +void CodeTransform::operator()(FunctionalInstruction const& _instr) +{ + for (auto it = _instr.arguments.rbegin(); it != _instr.arguments.rend(); ++it) + { + int height = m_assembly.stackHeight(); + boost::apply_visitor(*this, *it); + expectDeposit(1, height); + } + (*this)(_instr.instruction); + checkStackHeight(&_instr); +} + +void CodeTransform::operator()(assembly::Identifier const& _identifier) +{ + m_assembly.setSourceLocation(_identifier.location); + // First search internals, then externals. + if (m_scope.lookup(_identifier.name, Scope::NonconstVisitor( + [=](Scope::Variable& _var) + { + if (int heightDiff = variableHeightDiff(_var, _identifier.location, false)) + m_assembly.appendInstruction(solidity::dupInstruction(heightDiff)); + else + // Store something to balance the stack + m_assembly.appendConstant(u256(0)); + }, + [=](Scope::Label& _label) + { + assignLabelIdIfUnset(_label); + m_assembly.appendLabelReference(*_label.id); + }, + [=](Scope::Function&) + { + solAssert(false, "Function not removed during desugaring."); + } + ))) + { + return; + } + solAssert( + m_identifierAccess.generateCode, + "Identifier not found and no external access available." + ); + m_identifierAccess.generateCode(_identifier, IdentifierContext::RValue, m_assembly); + checkStackHeight(&_identifier); +} + +void CodeTransform::operator()(assembly::Literal const& _literal) +{ + m_assembly.setSourceLocation(_literal.location); + if (_literal.kind == assembly::LiteralKind::Number) + m_assembly.appendConstant(u256(_literal.value)); + else if (_literal.kind == assembly::LiteralKind::Boolean) + { + if (_literal.value == "true") + m_assembly.appendConstant(u256(1)); + else + m_assembly.appendConstant(u256(0)); + } + else + { + solAssert(_literal.value.size() <= 32, ""); + m_assembly.appendConstant(u256(h256(_literal.value, h256::FromBinary, h256::AlignLeft))); + } + checkStackHeight(&_literal); +} + +void CodeTransform::operator()(assembly::Instruction const& _instruction) +{ + m_assembly.setSourceLocation(_instruction.location); + m_assembly.appendInstruction(_instruction.instruction); + checkStackHeight(&_instruction); +} diff --git a/libjulia/backends/evm/EVMCodeTransform.h b/libjulia/backends/evm/EVMCodeTransform.h index ce0fced79..5408a3aae 100644 --- a/libjulia/backends/evm/EVMCodeTransform.h +++ b/libjulia/backends/evm/EVMCodeTransform.h @@ -18,236 +18,102 @@ * Common code generator for translating Julia / inline assembly to EVM and EVM1.5. */ +#include + +#include + +#include +#include + +#include + +namespace dev +{ +namespace solidity +{ +namespace assembly +{ +struct Literal; +struct Block; +struct Switch; +struct Label; +struct FunctionalInstruction; +struct Assignment; +struct VariableDeclaration; +struct Instruction; +struct Identifier; +struct StackAssignment; +struct FunctionDefinition; +struct FunctionCall; + +struct AsmAnalysisInfo; +} +} +namespace julia +{ class CodeTransform: public boost::static_visitor<> { public: - /// Create the code transformer which appends assembly to _state.assembly when called - /// with parsed assembly data. + /// Create the code transformer which appends assembly to _assembly as a side-effect + /// of its creation. /// @param _identifierAccess used to resolve identifiers external to the inline assembly - explicit CodeTransform( - GeneratorState& _state, + CodeTransform( + solidity::ErrorList& _errors, julia::AbstractAssembly& _assembly, - assembly::Block const& _block, - assembly::ExternalIdentifierAccess const& _identifierAccess = assembly::ExternalIdentifierAccess() - ): CodeTransform(_state, _assembly, _block, _identifierAccess, _assembly.stackHeight()) + solidity::assembly::Block const& _block, + solidity::assembly::AsmAnalysisInfo& _analysisInfo, + ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess() + ): CodeTransform(_errors, _assembly, _block, _analysisInfo, _identifierAccess, _assembly.stackHeight()) { } private: CodeTransform( - GeneratorState& _state, + solidity::ErrorList& _errors, julia::AbstractAssembly& _assembly, - assembly::Block const& _block, - assembly::ExternalIdentifierAccess const& _identifierAccess, + solidity::assembly::Block const& _block, + solidity::assembly::AsmAnalysisInfo& _analysisInfo, + ExternalIdentifierAccess const& _identifierAccess, int _initialStackHeight - ): - m_state(_state), - m_assembly(_assembly), - m_scope(*m_state.info.scopes.at(&_block)), - m_identifierAccess(_identifierAccess), - m_initialStackHeight(_initialStackHeight) - { - int blockStartStackHeight = m_assembly.stackHeight(); - std::for_each(_block.statements.begin(), _block.statements.end(), boost::apply_visitor(*this)); - - m_assembly.setSourceLocation(_block.location); - - // pop variables - for (auto const& identifier: m_scope.identifiers) - if (identifier.second.type() == typeid(Scope::Variable)) - m_assembly.appendInstruction(solidity::Instruction::POP); - - int deposit = m_assembly.stackHeight() - blockStartStackHeight; - solAssert(deposit == 0, "Invalid stack height at end of block."); - } + ); public: - void operator()(assembly::Instruction const& _instruction) - { - m_assembly.setSourceLocation(_instruction.location); - m_assembly.appendInstruction(_instruction.instruction); - checkStackHeight(&_instruction); - } - void operator()(assembly::Literal const& _literal) - { - m_assembly.setSourceLocation(_literal.location); - if (_literal.kind == assembly::LiteralKind::Number) - m_assembly.appendConstant(u256(_literal.value)); - else if (_literal.kind == assembly::LiteralKind::Boolean) - { - if (_literal.value == "true") - m_assembly.appendConstant(u256(1)); - else - m_assembly.appendConstant(u256(0)); - } - else - { - solAssert(_literal.value.size() <= 32, ""); - m_assembly.appendConstant(u256(h256(_literal.value, h256::FromBinary, h256::AlignLeft))); - } - checkStackHeight(&_literal); - } - void operator()(assembly::Identifier const& _identifier) - { - m_assembly.setSourceLocation(_identifier.location); - // First search internals, then externals. - if (m_scope.lookup(_identifier.name, Scope::NonconstVisitor( - [=](Scope::Variable& _var) - { - if (int heightDiff = variableHeightDiff(_var, _identifier.location, false)) - m_assembly.appendInstruction(solidity::dupInstruction(heightDiff)); - else - // Store something to balance the stack - m_assembly.appendConstant(u256(0)); - }, - [=](Scope::Label& _label) - { - assignLabelIdIfUnset(_label); - m_assembly.appendLabelReference(*_label.id); - }, - [=](Scope::Function&) - { - solAssert(false, "Function not removed during desugaring."); - } - ))) - { - return; - } - solAssert( - m_identifierAccess.generateCode, - "Identifier not found and no external access available." - ); - m_identifierAccess.generateCode(_identifier, IdentifierContext::RValue, m_assembly); - checkStackHeight(&_identifier); - } - void operator()(FunctionalInstruction const& _instr) - { - for (auto it = _instr.arguments.rbegin(); it != _instr.arguments.rend(); ++it) - { - int height = m_assembly.stackHeight(); - boost::apply_visitor(*this, *it); - expectDeposit(1, height); - } - (*this)(_instr.instruction); - checkStackHeight(&_instr); - } - void operator()(assembly::FunctionCall const&) - { - solAssert(false, "Function call not removed during desugaring phase."); - } - void operator()(Label const& _label) - { - m_assembly.setSourceLocation(_label.location); - solAssert(m_scope.identifiers.count(_label.name), ""); - Scope::Label& label = boost::get(m_scope.identifiers.at(_label.name)); - assignLabelIdIfUnset(label); - m_assembly.appendLabel(*label.id); - checkStackHeight(&_label); - } - void operator()(StackAssignment const& _assignment) - { - m_assembly.setSourceLocation(_assignment.location); - generateAssignment(_assignment.variableName, _assignment.location); - checkStackHeight(&_assignment); - } - void operator()(assembly::Assignment const& _assignment) - { - int height = m_assembly.stackHeight(); - boost::apply_visitor(*this, *_assignment.value); - expectDeposit(1, height); - m_assembly.setSourceLocation(_assignment.location); - generateAssignment(_assignment.variableName, _assignment.location); - checkStackHeight(&_assignment); - } - void operator()(assembly::VariableDeclaration const& _varDecl) - { - int expectedItems = _varDecl.variables.size(); - boost::apply_visitor(*this, *_varDecl.value); - expectDeposit(expectedItems, height); - for (auto const& variable: _varDecl.variables) - { - auto& var = boost::get(m_scope.identifiers.at(variable.name)); - var.stackHeight = height++; - var.active = true; - } - } - void operator()(assembly::Block const& _block) - { - CodeTransform(m_state, m_assembly, _block, m_identifierAccess, m_initialStackHeight); - checkStackHeight(&_block); - } - void operator()(assembly::FunctionDefinition const&) - { - solAssert(false, "Function definition not removed during desugaring phase."); - } + void operator()(solidity::assembly::Instruction const& _instruction); + void operator()(solidity::assembly::Literal const& _literal); + void operator()(solidity::assembly::Identifier const& _identifier); + void operator()(solidity::assembly::FunctionalInstruction const& _instr); + void operator()(solidity::assembly::FunctionCall const&); + void operator()(solidity::assembly::Label const& _label); + void operator()(solidity::assembly::StackAssignment const& _assignment); + void operator()(solidity::assembly::Assignment const& _assignment); + void operator()(solidity::assembly::VariableDeclaration const& _varDecl); + void operator()(solidity::assembly::Block const& _block); + void operator()(solidity::assembly::Switch const& _switch); + void operator()(solidity::assembly::FunctionDefinition const&); private: - void generateAssignment(assembly::Identifier const& _variableName, SourceLocation const& _location) - { - auto var = m_scope.lookup(_variableName.name); - if (var) - { - Scope::Variable const& _var = boost::get(*var); - if (int heightDiff = variableHeightDiff(_var, _location, true)) - m_assembly.appendInstruction(solidity::swapInstruction(heightDiff - 1)); - m_assembly.appendInstruction(solidity::Instruction::POP); - } - else - { - solAssert( - m_identifierAccess.generateCode, - "Identifier not found and no external access available." - ); - m_identifierAccess.generateCode(_variableName, IdentifierContext::LValue, m_assembly); - } - } + void generateAssignment(solidity::assembly::Identifier const& _variableName, SourceLocation const& _location); /// Determines the stack height difference to the given variables. Automatically generates /// errors if it is not yet in scope or the height difference is too large. Returns 0 on /// errors and the (positive) stack height difference otherwise. - int variableHeightDiff(Scope::Variable const& _var, SourceLocation const& _location, bool _forSwap) - { - int heightDiff = m_assembly.stackHeight() - _var.stackHeight; - if (heightDiff <= (_forSwap ? 1 : 0) || heightDiff > (_forSwap ? 17 : 16)) - { - //@TODO move this to analysis phase. - m_state.errors.push_back(make_shared( - Error::Type::TypeError, - "Variable inaccessible, too deep inside stack (" + boost::lexical_cast(heightDiff) + ")", - _location - )); - return 0; - } - else - return heightDiff; - } + int variableHeightDiff(solidity::assembly::Scope::Variable const& _var, SourceLocation const& _location, bool _forSwap); - void expectDeposit(int _deposit, int _oldHeight) - { - solAssert(m_assembly.stackHeight() == _oldHeight + _deposit, "Invalid stack deposit."); - } + void expectDeposit(int _deposit, int _oldHeight); - void checkStackHeight(void const* _astElement) - { - solAssert(m_state.info.stackHeightInfo.count(_astElement), "Stack height for AST element not found."); - solAssert( - m_state.info.stackHeightInfo.at(_astElement) == m_assembly.stackHeight() - m_initialStackHeight, - "Stack height mismatch between analysis and code generation phase." - ); - } + void checkStackHeight(void const* _astElement); /// Assigns the label's id to a value taken from eth::Assembly if it has not yet been set. - void assignLabelIdIfUnset(Scope::Label& _label) - { - if (!_label.id) - _label.id.reset(m_assembly.newLabelId()); - } + void assignLabelIdIfUnset(solidity::assembly::Scope::Label& _label); - - GeneratorState& m_state; + solidity::ErrorList& m_errors; julia::AbstractAssembly& m_assembly; - Scope& m_scope; + solidity::assembly::AsmAnalysisInfo& m_info; + solidity::assembly::Scope& m_scope; ExternalIdentifierAccess m_identifierAccess; int const m_initialStackHeight; }; + +} +} diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index bcc47e5a3..2342f0f93 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -7,10 +7,12 @@ aux_source_directory(formal SRC_LIST) aux_source_directory(interface SRC_LIST) aux_source_directory(parsing SRC_LIST) aux_source_directory(inlineasm SRC_LIST) +# Until we have a clear separation, libjulia has to be included here +aux_source_directory(../libjulia SRC_LIST) set(EXECUTABLE solidity) -file(GLOB HEADERS "*/*.h") +file(GLOB HEADERS "*/*.h" "../libjulia/backends/evm/*") include_directories(BEFORE ..) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 9433976aa..83ea17c7d 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -166,8 +166,8 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) // The only purpose of this step is to fill the inline assembly annotation with // external references. ErrorList errorsIgnored; - assembly::ExternalIdentifierAccess::Resolver resolver = - [&](assembly::Identifier const& _identifier, assembly::IdentifierContext) { + julia::ExternalIdentifierAccess::Resolver resolver = + [&](assembly::Identifier const& _identifier, julia::IdentifierContext) { auto declarations = m_resolver.nameFromCurrentScope(_identifier.name); bool isSlot = boost::algorithm::ends_with(_identifier.name, "_slot"); bool isOffset = boost::algorithm::ends_with(_identifier.name, "_offset"); diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 8161a3a12..ad22cc663 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -631,9 +631,9 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) { // External references have already been resolved in a prior stage and stored in the annotation. // We run the resolve step again regardless. - assembly::ExternalIdentifierAccess::Resolver identifierAccess = [&]( + julia::ExternalIdentifierAccess::Resolver identifierAccess = [&]( assembly::Identifier const& _identifier, - assembly::IdentifierContext _context + julia::IdentifierContext _context ) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); @@ -650,7 +650,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) typeError(_identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); return size_t(-1); } - else if (_context != assembly::IdentifierContext::RValue) + else if (_context != julia::IdentifierContext::RValue) { typeError(_identifier.location, "Storage variables cannot be assigned to."); return size_t(-1); @@ -677,13 +677,13 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) return size_t(-1); } } - else if (_context == assembly::IdentifierContext::LValue) + else if (_context == julia::IdentifierContext::LValue) { typeError(_identifier.location, "Only local variables can be assigned to in inline assembly."); return size_t(-1); } - if (_context == assembly::IdentifierContext::RValue) + if (_context == julia::IdentifierContext::RValue) { solAssert(!!declaration->type(), "Type of declaration required but not yet determined."); if (dynamic_cast(declaration)) diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 5c4f88c4c..404a3af63 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -266,10 +266,10 @@ void CompilerContext::appendInlineAssembly( int startStackHeight = stackHeight(); - assembly::ExternalIdentifierAccess identifierAccess; + julia::ExternalIdentifierAccess identifierAccess; identifierAccess.resolve = [&]( assembly::Identifier const& _identifier, - assembly::IdentifierContext + julia::IdentifierContext ) { auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name); @@ -277,7 +277,7 @@ void CompilerContext::appendInlineAssembly( }; identifierAccess.generateCode = [&]( assembly::Identifier const& _identifier, - assembly::IdentifierContext _context, + julia::IdentifierContext _context, julia::AbstractAssembly& _assembly ) { @@ -285,14 +285,14 @@ void CompilerContext::appendInlineAssembly( solAssert(it != _localVariables.end(), ""); int stackDepth = _localVariables.end() - it; int stackDiff = _assembly.stackHeight() - startStackHeight + stackDepth; - if (_context == assembly::IdentifierContext::LValue) + if (_context == julia::IdentifierContext::LValue) stackDiff -= 1; if (stackDiff < 1 || stackDiff > 16) BOOST_THROW_EXCEPTION( CompilerError() << errinfo_comment("Stack too deep (" + to_string(stackDiff) + "), try removing local variables.") ); - if (_context == assembly::IdentifierContext::RValue) + if (_context == julia::IdentifierContext::RValue) _assembly.appendInstruction(dupInstruction(stackDiff)); else { diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 41940e1a6..e79bb6dc8 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -522,21 +522,21 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) ErrorList errors; assembly::CodeGenerator codeGen(errors); unsigned startStackHeight = m_context.stackHeight(); - assembly::ExternalIdentifierAccess identifierAccess; - identifierAccess.resolve = [&](assembly::Identifier const& _identifier, assembly::IdentifierContext) + julia::ExternalIdentifierAccess identifierAccess; + identifierAccess.resolve = [&](assembly::Identifier const& _identifier, julia::IdentifierContext) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); if (ref == _inlineAssembly.annotation().externalReferences.end()) return size_t(-1); return ref->second.valueSize; }; - identifierAccess.generateCode = [&](assembly::Identifier const& _identifier, assembly::IdentifierContext _context, julia::AbstractAssembly& _assembly) + identifierAccess.generateCode = [&](assembly::Identifier const& _identifier, julia::IdentifierContext _context, julia::AbstractAssembly& _assembly) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); solAssert(ref != _inlineAssembly.annotation().externalReferences.end(), ""); Declaration const* decl = ref->second.declaration; solAssert(!!decl, ""); - if (_context == assembly::IdentifierContext::RValue) + if (_context == julia::IdentifierContext::RValue) { int const depositBefore = _assembly.stackHeight(); solAssert(!!decl->type(), "Type of declaration required but not yet determined."); diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp index d022ecf6f..60caaa1db 100644 --- a/libsolidity/inlineasm/AsmAnalysis.cpp +++ b/libsolidity/inlineasm/AsmAnalysis.cpp @@ -41,7 +41,7 @@ using namespace dev::solidity::assembly; AsmAnalyzer::AsmAnalyzer( AsmAnalysisInfo& _analysisInfo, ErrorList& _errors, - ExternalIdentifierAccess::Resolver const& _resolver + julia::ExternalIdentifierAccess::Resolver const& _resolver ): m_resolver(_resolver), m_info(_analysisInfo), m_errors(_errors) { @@ -123,7 +123,7 @@ bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier) { size_t stackSize(-1); if (m_resolver) - stackSize = m_resolver(_identifier, IdentifierContext::RValue); + stackSize = m_resolver(_identifier, julia::IdentifierContext::RValue); if (stackSize == size_t(-1)) { // Only add an error message if the callback did not do it. @@ -393,7 +393,7 @@ bool AsmAnalyzer::checkAssignment(assembly::Identifier const& _variable, size_t variableSize = 1; } else if (m_resolver) - variableSize = m_resolver(_variable, IdentifierContext::LValue); + variableSize = m_resolver(_variable, julia::IdentifierContext::LValue); if (variableSize == size_t(-1)) { // Only add message if the callback did not. diff --git a/libsolidity/inlineasm/AsmAnalysis.h b/libsolidity/inlineasm/AsmAnalysis.h index 9f022b12e..613abf384 100644 --- a/libsolidity/inlineasm/AsmAnalysis.h +++ b/libsolidity/inlineasm/AsmAnalysis.h @@ -64,7 +64,7 @@ public: AsmAnalyzer( AsmAnalysisInfo& _analysisInfo, ErrorList& _errors, - ExternalIdentifierAccess::Resolver const& _resolver = ExternalIdentifierAccess::Resolver() + julia::ExternalIdentifierAccess::Resolver const& _resolver = julia::ExternalIdentifierAccess::Resolver() ); bool analyze(assembly::Block const& _block); @@ -94,7 +94,7 @@ private: /// we enter the block. int m_virtualVariablesInNextBlock = 0; int m_stackHeight = 0; - ExternalIdentifierAccess::Resolver const& m_resolver; + julia::ExternalIdentifierAccess::Resolver const& m_resolver; Scope* m_currentScope = nullptr; AsmAnalysisInfo& m_info; ErrorList& m_errors; diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libsolidity/inlineasm/AsmCodeGen.cpp index ce2d8a1d8..6a44faaca 100644 --- a/libsolidity/inlineasm/AsmCodeGen.cpp +++ b/libsolidity/inlineasm/AsmCodeGen.cpp @@ -32,7 +32,8 @@ #include #include -#include +#include +#include #include @@ -48,15 +49,6 @@ using namespace dev; using namespace dev::solidity; using namespace dev::solidity::assembly; -struct GeneratorState -{ - GeneratorState(ErrorList& _errors, AsmAnalysisInfo& _analysisInfo): - errors(_errors), info(_analysisInfo) {} - - ErrorList& errors; - AsmAnalysisInfo info; -}; - class EthAssemblyAdapter: public julia::AbstractAssembly { public: @@ -110,13 +102,12 @@ private: eth::Assembly assembly::CodeGenerator::assemble( Block const& _parsedData, AsmAnalysisInfo& _analysisInfo, - ExternalIdentifierAccess const& _identifierAccess + julia::ExternalIdentifierAccess const& _identifierAccess ) { eth::Assembly assembly; - GeneratorState state(m_errors, _analysisInfo); EthAssemblyAdapter assemblyAdapter(assembly); - CodeTransform(state, assemblyAdapter, _parsedData, _identifierAccess); + julia::CodeTransform(m_errors, assemblyAdapter, _parsedData, _analysisInfo, _identifierAccess); return assembly; } @@ -124,10 +115,9 @@ void assembly::CodeGenerator::assemble( Block const& _parsedData, AsmAnalysisInfo& _analysisInfo, eth::Assembly& _assembly, - ExternalIdentifierAccess const& _identifierAccess + julia::ExternalIdentifierAccess const& _identifierAccess ) { - GeneratorState state(m_errors, _analysisInfo); EthAssemblyAdapter assemblyAdapter(_assembly); - CodeTransform(state, assemblyAdapter, _parsedData, _identifierAccess); + julia::CodeTransform(m_errors, assemblyAdapter, _parsedData, _analysisInfo, _identifierAccess); } diff --git a/libsolidity/inlineasm/AsmCodeGen.h b/libsolidity/inlineasm/AsmCodeGen.h index e830e047d..1b43d2f61 100644 --- a/libsolidity/inlineasm/AsmCodeGen.h +++ b/libsolidity/inlineasm/AsmCodeGen.h @@ -48,14 +48,14 @@ public: eth::Assembly assemble( Block const& _parsedData, AsmAnalysisInfo& _analysisInfo, - ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess() + julia::ExternalIdentifierAccess const& _identifierAccess = julia::ExternalIdentifierAccess() ); /// Performs code generation and appends generated to to _assembly. void assemble( Block const& _parsedData, AsmAnalysisInfo& _analysisInfo, eth::Assembly& _assembly, - ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess() + julia::ExternalIdentifierAccess const& _identifierAccess = julia::ExternalIdentifierAccess() ); private: diff --git a/libsolidity/inlineasm/AsmStack.cpp b/libsolidity/inlineasm/AsmStack.cpp index c2a7d8ea8..2e63465f4 100644 --- a/libsolidity/inlineasm/AsmStack.cpp +++ b/libsolidity/inlineasm/AsmStack.cpp @@ -42,7 +42,7 @@ using namespace dev::solidity::assembly; bool InlineAssemblyStack::parse( shared_ptr const& _scanner, - ExternalIdentifierAccess::Resolver const& _resolver + julia::ExternalIdentifierAccess::Resolver const& _resolver ) { m_parserResult = make_shared(); @@ -73,7 +73,7 @@ eth::Assembly InlineAssemblyStack::assemble() bool InlineAssemblyStack::parseAndAssemble( string const& _input, eth::Assembly& _assembly, - ExternalIdentifierAccess const& _identifierAccess + julia::ExternalIdentifierAccess const& _identifierAccess ) { ErrorList errors; diff --git a/libsolidity/inlineasm/AsmStack.h b/libsolidity/inlineasm/AsmStack.h index e223ccc91..23072a881 100644 --- a/libsolidity/inlineasm/AsmStack.h +++ b/libsolidity/inlineasm/AsmStack.h @@ -24,7 +24,7 @@ #include -#include +#include #include #include @@ -43,23 +43,6 @@ 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 -{ - using Resolver = std::function; - /// 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. - Resolver resolve; - using CodeGenerator = std::function; - /// 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. - CodeGenerator generateCode; -}; - class InlineAssemblyStack { public: @@ -67,7 +50,7 @@ public: /// @return false or error. bool parse( std::shared_ptr const& _scanner, - ExternalIdentifierAccess::Resolver const& _externalIdentifierResolver = ExternalIdentifierAccess::Resolver() + julia::ExternalIdentifierAccess::Resolver const& _externalIdentifierResolver = julia::ExternalIdentifierAccess::Resolver() ); /// Converts the parser result back into a string form (not necessarily the same form /// as the source form, but it should parse into the same parsed form again). @@ -79,7 +62,7 @@ public: bool parseAndAssemble( std::string const& _input, eth::Assembly& _assembly, - ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess() + julia::ExternalIdentifierAccess const& _identifierAccess = julia::ExternalIdentifierAccess() ); ErrorList const& errors() const { return m_errors; } diff --git a/libsolidity/interface/MultiBackendAssemblyStack.cpp b/libsolidity/interface/AssemblyStack.cpp similarity index 80% rename from libsolidity/interface/MultiBackendAssemblyStack.cpp rename to libsolidity/interface/AssemblyStack.cpp index cf16b6275..c4bd63c41 100644 --- a/libsolidity/interface/MultiBackendAssemblyStack.cpp +++ b/libsolidity/interface/AssemblyStack.cpp @@ -20,7 +20,7 @@ */ -#include +#include #include #include @@ -35,17 +35,17 @@ using namespace dev; using namespace dev::solidity; -Scanner const& MultiBackendAssemblyStack::scanner() const +Scanner const& AssemblyStack::scanner() const { solAssert(m_scanner, ""); return *m_scanner; } -bool MultiBackendAssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string const& _source) +bool AssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string const& _source) { m_analysisSuccessful = false; m_scanner = make_shared(CharStream(_source), _sourceName); - m_parserResult = assembly::Parser(m_errors, m_input == Input::JULIA).parse(m_scanner); + m_parserResult = assembly::Parser(m_errors, m_language == Language::JULIA).parse(m_scanner); if (!m_errors.empty()) return false; solAssert(m_parserResult, ""); @@ -56,13 +56,13 @@ bool MultiBackendAssemblyStack::parseAndAnalyze(std::string const& _sourceName, return m_analysisSuccessful; } -eth::LinkerObject MultiBackendAssemblyStack::assemble() +eth::LinkerObject AssemblyStack::assemble(Machine _machine) { solAssert(m_analysisSuccessful, ""); solAssert(m_parserResult, ""); solAssert(m_analysisInfo, ""); - switch (m_targetMachine) + switch (_machine) { case Machine::EVM: { @@ -78,8 +78,8 @@ eth::LinkerObject MultiBackendAssemblyStack::assemble() return eth::LinkerObject(); } -string MultiBackendAssemblyStack::print() +string AssemblyStack::print() { solAssert(m_parserResult, ""); - return assembly::AsmPrinter(m_input == Input::JULIA)(*m_parserResult); + return assembly::AsmPrinter(m_language == Language::JULIA)(*m_parserResult); } diff --git a/libsolidity/interface/MultiBackendAssemblyStack.h b/libsolidity/interface/AssemblyStack.h similarity index 85% rename from libsolidity/interface/MultiBackendAssemblyStack.h rename to libsolidity/interface/AssemblyStack.h index fed9e8f95..4aba48465 100644 --- a/libsolidity/interface/MultiBackendAssemblyStack.h +++ b/libsolidity/interface/AssemblyStack.h @@ -43,15 +43,14 @@ struct Block; * Full assembly stack that can support EVM-assembly and JULIA as input and EVM, EVM1.5 and * eWasm as output. */ -class MultiBackendAssemblyStack +class AssemblyStack { public: - enum class Input { JULIA, Assembly }; + enum class Language { JULIA, Assembly }; enum class Machine { EVM, EVM15, eWasm }; - MultiBackendAssemblyStack(Input _input = Input::Assembly, Machine _targetMachine = Machine::EVM): - m_input(_input), - m_targetMachine(_targetMachine) + explicit AssemblyStack(Language _language = Language::Assembly): + m_language(_language) {} /// @returns the scanner used during parsing @@ -61,7 +60,7 @@ public: bool parseAndAnalyze(std::string const& _sourceName, std::string const& _source); /// Run the assembly step (should only be called after parseAndAnalyze). - eth::LinkerObject assemble(); + eth::LinkerObject assemble(Machine _machine); ErrorList const& errors() const { return m_errors; } @@ -70,8 +69,7 @@ public: private: - Input m_input = Input::Assembly; - Machine m_targetMachine = Machine::EVM; + Language m_language = Language::Assembly; std::shared_ptr m_scanner; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 701cf1636..c14a46e8a 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include @@ -717,9 +717,9 @@ bool CommandLineInterface::processInput() { // switch to assembly mode m_onlyAssemble = true; - using Input = MultiBackendAssemblyStack::Input; - using Machine = MultiBackendAssemblyStack::Machine; - Input input = m_args.count(g_argJulia) ? Input::JULIA : Input::Assembly; + using Input = AssemblyStack::Language; + using Machine = AssemblyStack::Machine; + Input inputLanguage = m_args.count(g_argJulia) ? Input::JULIA : Input::Assembly; Machine targetMachine = Machine::EVM; if (m_args.count(g_argMachine)) { @@ -736,7 +736,7 @@ bool CommandLineInterface::processInput() return false; } } - return assemble(input, targetMachine); + return assemble(inputLanguage, targetMachine); } if (m_args.count(g_argLink)) { @@ -1023,15 +1023,15 @@ void CommandLineInterface::writeLinkedFiles() } bool CommandLineInterface::assemble( - MultiBackendAssemblyStack::Input _input, - MultiBackendAssemblyStack::Machine _targetMachine + AssemblyStack::Language _language, + AssemblyStack::Machine _targetMachine ) { bool successful = true; - map assemblyStacks; + map assemblyStacks; for (auto const& src: m_sourceCodes) { - auto& stack = assemblyStacks[src.first] = MultiBackendAssemblyStack(_input, _targetMachine); + auto& stack = assemblyStacks[src.first] = AssemblyStack(_language); try { if (!stack.parseAndAnalyze(src.first, src.second)) diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 8c79e32db..b482c20b7 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -22,7 +22,7 @@ #pragma once #include -#include +#include #include #include @@ -54,7 +54,7 @@ private: bool link(); void writeLinkedFiles(); - bool assemble(MultiBackendAssemblyStack::Input _input, MultiBackendAssemblyStack::Machine _targetMachine); + bool assemble(AssemblyStack::Language _language, AssemblyStack::Machine _targetMachine); void outputCompilationResults();