diff options
author | Alex Beregszaszi <alex@rtfs.hu> | 2017-06-09 18:23:40 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-09 18:23:40 +0800 |
commit | 76667fed4f9865c4a3a5a267c469446f8bce1bef (patch) | |
tree | 4f8d0d9eee83e30912e78685d6c0fbdc916521a9 /libsolidity | |
parent | 21e0b69dcb189fb52ac4e38959801582e02ca8fd (diff) | |
parent | 80227af08a72e37e35a0a8bfacadc1c201f1d114 (diff) | |
download | dexon-solidity-76667fed4f9865c4a3a5a267c469446f8bce1bef.tar.gz dexon-solidity-76667fed4f9865c4a3a5a267c469446f8bce1bef.tar.zst dexon-solidity-76667fed4f9865c4a3a5a267c469446f8bce1bef.zip |
Merge pull request #2304 from ethereum/evm15asm
Implementation of EVM 1.5 backend
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/analysis/ReferencesResolver.cpp | 14 | ||||
-rw-r--r-- | libsolidity/analysis/ReferencesResolver.h | 7 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 3 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.cpp | 3 | ||||
-rw-r--r-- | libsolidity/codegen/ContractCompiler.cpp | 23 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmAnalysis.cpp | 36 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmAnalysis.h | 7 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmCodeGen.cpp | 43 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmCodeGen.h | 10 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmScope.cpp | 8 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmScope.h | 4 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmStack.cpp | 6 | ||||
-rw-r--r-- | libsolidity/interface/AssemblyStack.cpp | 15 | ||||
-rw-r--r-- | libsolidity/interface/AssemblyStack.h | 4 |
14 files changed, 134 insertions, 49 deletions
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index b70b0f0e..edf2fc02 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -169,7 +169,7 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) ErrorList errors; ErrorReporter errorsIgnored(errors); julia::ExternalIdentifierAccess::Resolver resolver = - [&](assembly::Identifier const& _identifier, julia::IdentifierContext) { + [&](assembly::Identifier const& _identifier, julia::IdentifierContext, bool _crossesFunctionBoundary) { 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"); @@ -188,6 +188,12 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) } if (declarations.size() != 1) return size_t(-1); + if (auto var = dynamic_cast<VariableDeclaration const*>(declarations.front())) + if (var->isLocalVariable() && _crossesFunctionBoundary) + { + declarationError(_identifier.location, "Cannot access local Solidity variables from inside an inline assembly function."); + return size_t(-1); + } _inlineAssembly.annotation().externalReferences[&_identifier].isSlot = isSlot; _inlineAssembly.annotation().externalReferences[&_identifier].isOffset = isOffset; _inlineAssembly.annotation().externalReferences[&_identifier].declaration = declarations.front(); @@ -315,6 +321,12 @@ void ReferencesResolver::fatalTypeError(SourceLocation const& _location, string m_errorReporter.fatalTypeError(_location, _description); } +void ReferencesResolver::declarationError(SourceLocation const& _location, string const& _description) +{ + m_errorOccurred = true; + m_errorReporter.declarationError(_location, _description); +} + void ReferencesResolver::fatalDeclarationError(SourceLocation const& _location, string const& _description) { m_errorOccurred = true; diff --git a/libsolidity/analysis/ReferencesResolver.h b/libsolidity/analysis/ReferencesResolver.h index bbde19f9..fef2e73f 100644 --- a/libsolidity/analysis/ReferencesResolver.h +++ b/libsolidity/analysis/ReferencesResolver.h @@ -75,10 +75,13 @@ private: /// Adds a new error to the list of errors. void typeError(SourceLocation const& _location, std::string const& _description); - /// Adds a new error to the list of errors and throws to abort type checking. + /// Adds a new error to the list of errors and throws to abort reference resolving. void fatalTypeError(SourceLocation const& _location, std::string const& _description); - /// Adds a new error to the list of errors and throws to abort type checking. + /// Adds a new error to the list of errors. + void declarationError(SourceLocation const& _location, std::string const& _description); + + /// Adds a new error to the list of errors and throws to abort reference resolving. void fatalDeclarationError(SourceLocation const& _location, std::string const& _description); ErrorReporter& m_errorReporter; diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 0fb0d212..b1911ef0 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -632,7 +632,8 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) // We run the resolve step again regardless. julia::ExternalIdentifierAccess::Resolver identifierAccess = [&]( assembly::Identifier const& _identifier, - julia::IdentifierContext _context + julia::IdentifierContext _context, + bool ) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 404a3af6..9c4fbcbb 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -269,7 +269,8 @@ void CompilerContext::appendInlineAssembly( julia::ExternalIdentifierAccess identifierAccess; identifierAccess.resolve = [&]( assembly::Identifier const& _identifier, - julia::IdentifierContext + julia::IdentifierContext, + bool ) { auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name); diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 1fc06333..dc090634 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -21,15 +21,20 @@ */ #include <libsolidity/codegen/ContractCompiler.h> -#include <algorithm> -#include <boost/range/adaptor/reversed.hpp> -#include <libevmasm/Instruction.h> -#include <libevmasm/Assembly.h> -#include <libevmasm/GasMeter.h> #include <libsolidity/inlineasm/AsmCodeGen.h> #include <libsolidity/ast/AST.h> +#include <libsolidity/interface/ErrorReporter.h> #include <libsolidity/codegen/ExpressionCompiler.h> #include <libsolidity/codegen/CompilerUtils.h> + +#include <libevmasm/Instruction.h> +#include <libevmasm/Assembly.h> +#include <libevmasm/GasMeter.h> + +#include <boost/range/adaptor/reversed.hpp> + +#include <algorithm> + using namespace std; using namespace dev; using namespace dev::solidity; @@ -519,12 +524,9 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) { - ErrorList errors; - ErrorReporter errorReporter(errors); - assembly::CodeGenerator codeGen(errorReporter); unsigned startStackHeight = m_context.stackHeight(); julia::ExternalIdentifierAccess identifierAccess; - identifierAccess.resolve = [&](assembly::Identifier const& _identifier, julia::IdentifierContext) + identifierAccess.resolve = [&](assembly::Identifier const& _identifier, julia::IdentifierContext, bool) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); if (ref == _inlineAssembly.annotation().externalReferences.end()) @@ -643,13 +645,12 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } }; solAssert(_inlineAssembly.annotation().analysisInfo, ""); - codeGen.assemble( + assembly::CodeGenerator::assemble( _inlineAssembly.operations(), *_inlineAssembly.annotation().analysisInfo, m_context.nonConstAssembly(), identifierAccess ); - solAssert(Error::containsOnlyWarnings(errorReporter.errors()), "Code generation for inline assembly with errors requested."); m_context.setStackOffset(startStackHeight); return false; } diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp index 3edc01ad..13852880 100644 --- a/libsolidity/inlineasm/AsmAnalysis.cpp +++ b/libsolidity/inlineasm/AsmAnalysis.cpp @@ -25,7 +25,7 @@ #include <libsolidity/inlineasm/AsmScope.h> #include <libsolidity/inlineasm/AsmAnalysisInfo.h> -#include <libsolidity/interface/Exceptions.h> +#include <libsolidity/interface/ErrorReporter.h> #include <libsolidity/interface/Utils.h> #include <boost/range/adaptor/reversed.hpp> @@ -120,7 +120,10 @@ bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier) { size_t stackSize(-1); if (m_resolver) - stackSize = m_resolver(_identifier, julia::IdentifierContext::RValue); + { + bool insideFunction = m_currentScope->insideFunction(); + stackSize = m_resolver(_identifier, julia::IdentifierContext::RValue, insideFunction); + } if (stackSize == size_t(-1)) { // Only add an error message if the callback did not do it. @@ -274,8 +277,12 @@ bool AsmAnalyzer::operator()(Switch const& _switch) { if (_case.value) { - if (!expectExpression(*_case.value)) + int const initialStackHeight = m_stackHeight; + // We cannot use "expectExpression" here because *_case.value is not a + // Statement and would be converted to a Statement otherwise. + if (!(*this)(*_case.value)) success = false; + expectDeposit(1, initialStackHeight, _case.value->location); m_stackHeight--; /// Note: the parser ensures there is only one default case @@ -295,6 +302,7 @@ bool AsmAnalyzer::operator()(Switch const& _switch) } m_stackHeight--; + m_info.stackHeightInfo[&_switch] = m_stackHeight; return success; } @@ -341,17 +349,24 @@ bool AsmAnalyzer::expectExpression(Statement const& _statement) int const initialHeight = m_stackHeight; if (!boost::apply_visitor(*this, _statement)) success = false; - if (m_stackHeight - initialHeight != 1) + if (!expectDeposit(1, initialHeight, locationOf(_statement))) + success = false; + return success; +} + +bool AsmAnalyzer::expectDeposit(int _deposit, int _oldHeight, SourceLocation const& _location) +{ + if (m_stackHeight - _oldHeight != _deposit) { m_errorReporter.typeError( - locationOf(_statement), + _location, "Expected expression to return one item to the stack, but did return " + - boost::lexical_cast<string>(m_stackHeight - initialHeight) + + boost::lexical_cast<string>(m_stackHeight - _oldHeight) + " items." ); - success = false; + return false; } - return success; + return true; } bool AsmAnalyzer::checkAssignment(assembly::Identifier const& _variable, size_t _valueSize) @@ -378,7 +393,10 @@ bool AsmAnalyzer::checkAssignment(assembly::Identifier const& _variable, size_t variableSize = 1; } else if (m_resolver) - variableSize = m_resolver(_variable, julia::IdentifierContext::LValue); + { + bool insideFunction = m_currentScope->insideFunction(); + variableSize = m_resolver(_variable, julia::IdentifierContext::LValue, insideFunction); + } 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 e52e6302..e7748bcf 100644 --- a/libsolidity/inlineasm/AsmAnalysis.h +++ b/libsolidity/inlineasm/AsmAnalysis.h @@ -20,7 +20,9 @@ #pragma once -#include <libsolidity/inlineasm/AsmStack.h> +#include <libsolidity/interface/Exceptions.h> + +#include <libjulia/backends/evm/AbstractAssembly.h> #include <boost/variant.hpp> @@ -87,6 +89,7 @@ public: private: /// Visits the statement and expects it to deposit one item onto the stack. bool expectExpression(Statement const& _statement); + bool expectDeposit(int _deposit, int _oldHeight, SourceLocation const& _location); /// Verifies that a variable to be assigned to exists and has the same size /// as the value, @a _valueSize, unless that is equal to -1. @@ -96,7 +99,7 @@ private: void expectValidType(std::string const& type, SourceLocation const& _location); int m_stackHeight = 0; - julia::ExternalIdentifierAccess::Resolver const& m_resolver; + julia::ExternalIdentifierAccess::Resolver m_resolver; Scope* m_currentScope = nullptr; AsmAnalysisInfo& m_info; ErrorReporter& m_errorReporter; diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libsolidity/inlineasm/AsmCodeGen.cpp index 11494c2d..0e4e744f 100644 --- a/libsolidity/inlineasm/AsmCodeGen.cpp +++ b/libsolidity/inlineasm/AsmCodeGen.cpp @@ -87,13 +87,46 @@ public: { m_assembly.appendLibraryAddress(_linkerSymbol); } + virtual void appendJump(int _stackDiffAfter) override + { + appendInstruction(solidity::Instruction::JUMP); + m_assembly.adjustDeposit(_stackDiffAfter); + } + virtual void appendJumpTo(LabelID _labelId, int _stackDiffAfter) override + { + appendLabelReference(_labelId); + appendJump(_stackDiffAfter); + } + virtual void appendJumpToIf(LabelID _labelId) override + { + appendLabelReference(_labelId); + appendInstruction(solidity::Instruction::JUMPI); + } + virtual void appendBeginsub(LabelID, int) override + { + // TODO we could emulate that, though + solAssert(false, "BEGINSUB not implemented for EVM 1.0"); + } + /// Call a subroutine. + virtual void appendJumpsub(LabelID, int, int) override + { + // TODO we could emulate that, though + solAssert(false, "JUMPSUB not implemented for EVM 1.0"); + } + + /// Return from a subroutine. + virtual void appendReturnsub(int, int) override + { + // TODO we could emulate that, though + solAssert(false, "RETURNSUB not implemented for EVM 1.0"); + } private: - size_t assemblyTagToIdentifier(eth::AssemblyItem const& _tag) const + LabelID assemblyTagToIdentifier(eth::AssemblyItem const& _tag) const { u256 id = _tag.data(); - solAssert(id <= std::numeric_limits<size_t>::max(), "Tag id too large."); - return size_t(id); + solAssert(id <= std::numeric_limits<LabelID>::max(), "Tag id too large."); + return LabelID(id); } eth::Assembly& m_assembly; @@ -107,7 +140,7 @@ eth::Assembly assembly::CodeGenerator::assemble( { eth::Assembly assembly; EthAssemblyAdapter assemblyAdapter(assembly); - julia::CodeTransform(m_errorReporter, assemblyAdapter, _parsedData, _analysisInfo, _identifierAccess); + julia::CodeTransform(assemblyAdapter, _analysisInfo, false, _identifierAccess).run(_parsedData); return assembly; } @@ -119,5 +152,5 @@ void assembly::CodeGenerator::assemble( ) { EthAssemblyAdapter assemblyAdapter(_assembly); - julia::CodeTransform(m_errorReporter, assemblyAdapter, _parsedData, _analysisInfo, _identifierAccess); + julia::CodeTransform(assemblyAdapter, _analysisInfo, false, _identifierAccess).run(_parsedData); } diff --git a/libsolidity/inlineasm/AsmCodeGen.h b/libsolidity/inlineasm/AsmCodeGen.h index f075fa93..7a149d74 100644 --- a/libsolidity/inlineasm/AsmCodeGen.h +++ b/libsolidity/inlineasm/AsmCodeGen.h @@ -34,7 +34,6 @@ class Assembly; } namespace solidity { -class ErrorReporter; namespace assembly { struct Block; @@ -42,24 +41,19 @@ struct Block; class CodeGenerator { public: - CodeGenerator(ErrorReporter& _errorReporter): - m_errorReporter(_errorReporter) {} /// Performs code generation and @returns the result. - eth::Assembly assemble( + static eth::Assembly assemble( Block const& _parsedData, AsmAnalysisInfo& _analysisInfo, julia::ExternalIdentifierAccess const& _identifierAccess = julia::ExternalIdentifierAccess() ); /// Performs code generation and appends generated to to _assembly. - void assemble( + static void assemble( Block const& _parsedData, AsmAnalysisInfo& _analysisInfo, eth::Assembly& _assembly, julia::ExternalIdentifierAccess const& _identifierAccess = julia::ExternalIdentifierAccess() ); - -private: - ErrorReporter& m_errorReporter; }; } diff --git a/libsolidity/inlineasm/AsmScope.cpp b/libsolidity/inlineasm/AsmScope.cpp index e3f4615a..7a086846 100644 --- a/libsolidity/inlineasm/AsmScope.cpp +++ b/libsolidity/inlineasm/AsmScope.cpp @@ -79,3 +79,11 @@ bool Scope::exists(string const& _name) else return false; } + +bool Scope::insideFunction() const +{ + for (Scope const* s = this; s; s = s->superScope) + if (s->functionScope) + return true; + return false; +} diff --git a/libsolidity/inlineasm/AsmScope.h b/libsolidity/inlineasm/AsmScope.h index 498218b4..ad321f77 100644 --- a/libsolidity/inlineasm/AsmScope.h +++ b/libsolidity/inlineasm/AsmScope.h @@ -85,6 +85,7 @@ struct Scope Function(std::vector<JuliaType> const& _arguments, std::vector<JuliaType> const& _returns): arguments(_arguments), returns(_returns) {} std::vector<JuliaType> arguments; std::vector<JuliaType> returns; + boost::optional<LabelID> id; }; using Identifier = boost::variant<Variable, Label, Function>; @@ -123,6 +124,9 @@ struct Scope /// across function and assembly boundaries). bool exists(std::string const& _name); + /// @returns true if this scope is inside a function. + bool insideFunction() const; + Scope* superScope = nullptr; /// If true, variables from the super scope are not visible here (other identifiers are), /// but they are still taken into account to prevent shadowing. diff --git a/libsolidity/inlineasm/AsmStack.cpp b/libsolidity/inlineasm/AsmStack.cpp index 73b1604d..92eb8a7a 100644 --- a/libsolidity/inlineasm/AsmStack.cpp +++ b/libsolidity/inlineasm/AsmStack.cpp @@ -66,8 +66,7 @@ eth::Assembly InlineAssemblyStack::assemble() AsmAnalysisInfo analysisInfo; AsmAnalyzer analyzer(analysisInfo, m_errorReporter); solAssert(analyzer.analyze(*m_parserResult), ""); - CodeGenerator codeGen(m_errorReporter); - return codeGen.assemble(*m_parserResult, analysisInfo); + return CodeGenerator::assemble(*m_parserResult, analysisInfo); } bool InlineAssemblyStack::parseAndAssemble( @@ -87,7 +86,8 @@ bool InlineAssemblyStack::parseAndAssemble( AsmAnalysisInfo analysisInfo; AsmAnalyzer analyzer(analysisInfo, errorReporter, false, _identifierAccess.resolve); solAssert(analyzer.analyze(*parserResult), ""); - CodeGenerator(errorReporter).assemble(*parserResult, analysisInfo, _assembly, _identifierAccess); + solAssert(errorReporter.errors().empty(), ""); + CodeGenerator::assemble(*parserResult, analysisInfo, _assembly, _identifierAccess); // At this point, the assembly might be messed up, but we should throw an // internal compiler error anyway. diff --git a/libsolidity/interface/AssemblyStack.cpp b/libsolidity/interface/AssemblyStack.cpp index 347de350..31d9e494 100644 --- a/libsolidity/interface/AssemblyStack.cpp +++ b/libsolidity/interface/AssemblyStack.cpp @@ -30,6 +30,9 @@ #include <libevmasm/Assembly.h> +#include <libjulia/backends/evm/EVMCodeTransform.h> +#include <libjulia/backends/evm/EVMAssembly.h> + using namespace std; using namespace dev; using namespace dev::solidity; @@ -73,7 +76,7 @@ bool AssemblyStack::analyzeParsed() return m_analysisSuccessful; } -eth::LinkerObject AssemblyStack::assemble(Machine _machine) +eth::LinkerObject AssemblyStack::assemble(Machine _machine) const { solAssert(m_analysisSuccessful, ""); solAssert(m_parserResult, ""); @@ -83,11 +86,15 @@ eth::LinkerObject AssemblyStack::assemble(Machine _machine) { case Machine::EVM: { - auto assembly = assembly::CodeGenerator(m_errorReporter).assemble(*m_parserResult, *m_analysisInfo); + auto assembly = assembly::CodeGenerator::assemble(*m_parserResult, *m_analysisInfo); return assembly.assemble(); } case Machine::EVM15: - solUnimplemented("EVM 1.5 backend is not yet implemented."); + { + julia::EVMAssembly assembly(true); + julia::CodeTransform(assembly, *m_analysisInfo, true).run(*m_parserResult); + return assembly.finalize(); + } case Machine::eWasm: solUnimplemented("eWasm backend is not yet implemented."); } @@ -95,7 +102,7 @@ eth::LinkerObject AssemblyStack::assemble(Machine _machine) return eth::LinkerObject(); } -string AssemblyStack::print() +string AssemblyStack::print() const { solAssert(m_parserResult, ""); return assembly::AsmPrinter(m_language == Language::JULIA)(*m_parserResult); diff --git a/libsolidity/interface/AssemblyStack.h b/libsolidity/interface/AssemblyStack.h index abecaae2..17d5f055 100644 --- a/libsolidity/interface/AssemblyStack.h +++ b/libsolidity/interface/AssemblyStack.h @@ -65,13 +65,13 @@ public: bool analyze(assembly::Block const& _block, Scanner const* _scanner = nullptr); /// Run the assembly step (should only be called after parseAndAnalyze). - eth::LinkerObject assemble(Machine _machine); + eth::LinkerObject assemble(Machine _machine) const; /// @returns the errors generated during parsing, analysis (and potentially assembly). ErrorList const& errors() const { return m_errors; } /// Pretty-print the input after having parsed it. - std::string print(); + std::string print() const; private: bool analyzeParsed(); |