mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Initial EVM1.5 assembly implementation.
This commit is contained in:
@@ -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)
|
||||
{
|
||||
m_errorReporter.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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -21,15 +21,20 @@
|
||||
*/
|
||||
|
||||
#include <libsolidity/codegen/ContractCompiler.h>
|
||||
#include <algorithm>
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
#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 <libsolidity/inlineasm/AsmCodeGen.h>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/codegen/ExpressionCompiler.h>
|
||||
#include <libsolidity/codegen/CompilerUtils.h>
|
||||
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace dev::solidity;
|
||||
@@ -524,7 +529,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
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())
|
||||
|
||||
@@ -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.
|
||||
@@ -200,7 +203,8 @@ bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef)
|
||||
}
|
||||
|
||||
int const stackHeight = m_stackHeight;
|
||||
m_stackHeight = _funDef.arguments.size() + _funDef.returns.size();
|
||||
// 1 for return label, depends on VM version
|
||||
m_stackHeight = 1 + _funDef.arguments.size() + _funDef.returns.size();
|
||||
|
||||
bool success = (*this)(_funDef.body);
|
||||
|
||||
@@ -254,10 +258,11 @@ bool AsmAnalyzer::operator()(assembly::FunctionCall const& _funCall)
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
m_stackHeight += 1; // Return label, but depends on backend
|
||||
for (auto const& arg: _funCall.arguments | boost::adaptors::reversed)
|
||||
if (!expectExpression(arg))
|
||||
success = false;
|
||||
m_stackHeight += int(returns) - int(arguments);
|
||||
m_stackHeight += int(returns) - int(arguments) - 1; // Return label, but depends on backend
|
||||
m_info.stackHeightInfo[&_funCall] = m_stackHeight;
|
||||
return success;
|
||||
}
|
||||
@@ -295,6 +300,7 @@ bool AsmAnalyzer::operator()(Switch const& _switch)
|
||||
}
|
||||
|
||||
m_stackHeight--;
|
||||
m_info.stackHeightInfo[&_switch] = m_stackHeight;
|
||||
|
||||
return success;
|
||||
}
|
||||
@@ -378,7 +384,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.
|
||||
|
||||
@@ -20,7 +20,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/inlineasm/AsmStack.h>
|
||||
#include <libsolidity/interface/Exceptions.h>
|
||||
|
||||
#include <libsolidity/interface/Exceptions.h>
|
||||
|
||||
#include <libjulia/backends/evm/AbstractAssembly.h>
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
|
||||
@@ -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 _label, int _stackDiffAfter) override
|
||||
{
|
||||
appendLabelReference(_label);
|
||||
appendJump(_stackDiffAfter);
|
||||
}
|
||||
virtual void appendJumpToIf(LabelID _label) override
|
||||
{
|
||||
appendLabelReference(_label);
|
||||
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) 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(m_errorReporter, 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(m_errorReporter, assemblyAdapter, _analysisInfo, false, _identifierAccess).run(_parsedData);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
@@ -87,7 +90,11 @@ eth::LinkerObject AssemblyStack::assemble(Machine _machine)
|
||||
return assembly.assemble();
|
||||
}
|
||||
case Machine::EVM15:
|
||||
solUnimplemented("EVM 1.5 backend is not yet implemented.");
|
||||
{
|
||||
julia::EVMAssembly assembly(true);
|
||||
julia::CodeTransform(m_errorReporter, assembly, *m_analysisInfo, true).run(*m_parserResult);
|
||||
return assembly.finalize();
|
||||
}
|
||||
case Machine::eWasm:
|
||||
solUnimplemented("eWasm backend is not yet implemented.");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user