aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
authorAlex Beregszaszi <alex@rtfs.hu>2017-06-09 18:23:40 +0800
committerGitHub <noreply@github.com>2017-06-09 18:23:40 +0800
commit76667fed4f9865c4a3a5a267c469446f8bce1bef (patch)
tree4f8d0d9eee83e30912e78685d6c0fbdc916521a9 /libsolidity
parent21e0b69dcb189fb52ac4e38959801582e02ca8fd (diff)
parent80227af08a72e37e35a0a8bfacadc1c201f1d114 (diff)
downloaddexon-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.cpp14
-rw-r--r--libsolidity/analysis/ReferencesResolver.h7
-rw-r--r--libsolidity/analysis/TypeChecker.cpp3
-rw-r--r--libsolidity/codegen/CompilerContext.cpp3
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp23
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.cpp36
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.h7
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.cpp43
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.h10
-rw-r--r--libsolidity/inlineasm/AsmScope.cpp8
-rw-r--r--libsolidity/inlineasm/AsmScope.h4
-rw-r--r--libsolidity/inlineasm/AsmStack.cpp6
-rw-r--r--libsolidity/interface/AssemblyStack.cpp15
-rw-r--r--libsolidity/interface/AssemblyStack.h4
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();