mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Refactor to abstract assembly to JULIA.
This commit is contained in:
parent
41ee2cefbb
commit
e2b21e1c96
88
libjulia/backends/AbstractAssembly.h
Normal file
88
libjulia/backends/AbstractAssembly.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @date 2017
|
||||
* Abstract assembly interface, subclasses of which are to be used with the generic
|
||||
* bytecode generator.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libdevcore/CommonData.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
struct SourceLocation;
|
||||
namespace solidity
|
||||
{
|
||||
enum class Instruction: uint8_t;
|
||||
namespace assembly
|
||||
{
|
||||
struct Instruction;
|
||||
struct Identifier;
|
||||
}
|
||||
}
|
||||
namespace julia
|
||||
{
|
||||
|
||||
class AbstractAssembly
|
||||
{
|
||||
public:
|
||||
virtual ~AbstractAssembly() {}
|
||||
|
||||
/// Set a new source location valid starting from the next instruction.
|
||||
virtual void setSourceLocation(SourceLocation const& _location) = 0;
|
||||
/// Retrieve the current height of the stack. This does not have to be zero
|
||||
/// at the beginning.
|
||||
virtual int stackHeight() const = 0;
|
||||
/// Append an EVM instruction.
|
||||
virtual void appendInstruction(solidity::Instruction _instruction) = 0;
|
||||
/// Append a constant.
|
||||
virtual void appendConstant(u256 const& _constant) = 0;
|
||||
/// Append a label.
|
||||
virtual void appendLabel(size_t _labelId) = 0;
|
||||
/// Append a label reference.
|
||||
virtual void appendLabelReference(size_t _labelId) = 0;
|
||||
/// Generate a new unique label.
|
||||
virtual size_t newLabel() = 0;
|
||||
/// Append a reference to a to-be-linked symobl.
|
||||
virtual void appendLinkerSymbol(std::string const& _name) = 0;
|
||||
};
|
||||
|
||||
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<size_t(solidity::assembly::Identifier const&, IdentifierContext)>;
|
||||
/// 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<void(solidity::assembly::Identifier const&, IdentifierContext, julia::AbstractAssembly&)>;
|
||||
/// 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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -264,7 +264,7 @@ void CompilerContext::appendInlineAssembly(
|
||||
assembly = &replacedAssembly;
|
||||
}
|
||||
|
||||
unsigned startStackHeight = stackHeight();
|
||||
int startStackHeight = stackHeight();
|
||||
|
||||
assembly::ExternalIdentifierAccess identifierAccess;
|
||||
identifierAccess.resolve = [&](
|
||||
@ -278,26 +278,26 @@ void CompilerContext::appendInlineAssembly(
|
||||
identifierAccess.generateCode = [&](
|
||||
assembly::Identifier const& _identifier,
|
||||
assembly::IdentifierContext _context,
|
||||
eth::Assembly& _assembly
|
||||
julia::AbstractAssembly& _assembly
|
||||
)
|
||||
{
|
||||
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name);
|
||||
solAssert(it != _localVariables.end(), "");
|
||||
unsigned stackDepth = _localVariables.end() - it;
|
||||
int stackDiff = _assembly.deposit() - startStackHeight + stackDepth;
|
||||
int stackDepth = _localVariables.end() - it;
|
||||
int stackDiff = _assembly.stackHeight() - startStackHeight + stackDepth;
|
||||
if (_context == assembly::IdentifierContext::LValue)
|
||||
stackDiff -= 1;
|
||||
if (stackDiff < 1 || stackDiff > 16)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
CompilerError() <<
|
||||
errinfo_comment("Stack too deep, try removing local variables.")
|
||||
errinfo_comment("Stack too deep (" + to_string(stackDiff) + "), try removing local variables.")
|
||||
);
|
||||
if (_context == assembly::IdentifierContext::RValue)
|
||||
_assembly.append(dupInstruction(stackDiff));
|
||||
_assembly.appendInstruction(dupInstruction(stackDiff));
|
||||
else
|
||||
{
|
||||
_assembly.append(swapInstruction(stackDiff));
|
||||
_assembly.append(Instruction::POP);
|
||||
_assembly.appendInstruction(swapInstruction(stackDiff));
|
||||
_assembly.appendInstruction(Instruction::POP);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -530,7 +530,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
return size_t(-1);
|
||||
return ref->second.valueSize;
|
||||
};
|
||||
identifierAccess.generateCode = [&](assembly::Identifier const& _identifier, assembly::IdentifierContext _context, eth::Assembly& _assembly)
|
||||
identifierAccess.generateCode = [&](assembly::Identifier const& _identifier, assembly::IdentifierContext _context, julia::AbstractAssembly& _assembly)
|
||||
{
|
||||
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
|
||||
solAssert(ref != _inlineAssembly.annotation().externalReferences.end(), "");
|
||||
@ -538,21 +538,25 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
solAssert(!!decl, "");
|
||||
if (_context == assembly::IdentifierContext::RValue)
|
||||
{
|
||||
int const depositBefore = _assembly.deposit();
|
||||
int const depositBefore = _assembly.stackHeight();
|
||||
solAssert(!!decl->type(), "Type of declaration required but not yet determined.");
|
||||
if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(decl))
|
||||
{
|
||||
solAssert(!ref->second.isOffset && !ref->second.isSlot, "");
|
||||
functionDef = &m_context.resolveVirtualFunction(*functionDef);
|
||||
_assembly.append(m_context.functionEntryLabel(*functionDef).pushTag());
|
||||
auto functionEntryLabel = m_context.functionEntryLabel(*functionDef).pushTag();
|
||||
solAssert(functionEntryLabel.data() <= std::numeric_limits<size_t>::max(), "");
|
||||
_assembly.appendLabelReference(size_t(functionEntryLabel.data()));
|
||||
// If there is a runtime context, we have to merge both labels into the same
|
||||
// stack slot in case we store it in storage.
|
||||
if (CompilerContext* rtc = m_context.runtimeContext())
|
||||
{
|
||||
_assembly.append(u256(1) << 32);
|
||||
_assembly.append(Instruction::MUL);
|
||||
_assembly.append(rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub()));
|
||||
_assembly.append(Instruction::OR);
|
||||
_assembly.appendConstant(u256(1) << 32);
|
||||
_assembly.appendInstruction(Instruction::MUL);
|
||||
auto runtimeEntryLabel = rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub());
|
||||
solAssert(runtimeEntryLabel.data() <= std::numeric_limits<size_t>::max(), "");
|
||||
_assembly.appendLabelReference(size_t(runtimeEntryLabel.data()));
|
||||
_assembly.appendInstruction(Instruction::OR);
|
||||
}
|
||||
}
|
||||
else if (auto variable = dynamic_cast<VariableDeclaration const*>(decl))
|
||||
@ -570,7 +574,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
}
|
||||
else if (m_context.isLocalVariable(decl))
|
||||
{
|
||||
int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable);
|
||||
int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable);
|
||||
if (ref->second.isSlot || ref->second.isOffset)
|
||||
{
|
||||
solAssert(variable->type()->dataStoredIn(DataLocation::Storage), "");
|
||||
@ -587,7 +591,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
// only slot, offset is zero
|
||||
if (ref->second.isOffset)
|
||||
{
|
||||
_assembly.append(u256(0));
|
||||
_assembly.appendConstant(u256(0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -601,7 +605,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
errinfo_comment("Stack too deep, try removing local variables.")
|
||||
);
|
||||
solAssert(variable->type()->sizeOnStack() == 1, "");
|
||||
_assembly.append(dupInstruction(stackDiff));
|
||||
_assembly.appendInstruction(dupInstruction(stackDiff));
|
||||
}
|
||||
else
|
||||
solAssert(false, "");
|
||||
@ -610,11 +614,11 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
solAssert(!ref->second.isOffset && !ref->second.isSlot, "");
|
||||
solAssert(contract->isLibrary(), "");
|
||||
_assembly.appendLibraryAddress(contract->fullyQualifiedName());
|
||||
_assembly.appendLinkerSymbol(contract->fullyQualifiedName());
|
||||
}
|
||||
else
|
||||
solAssert(false, "Invalid declaration type.");
|
||||
solAssert(_assembly.deposit() - depositBefore == int(ref->second.valueSize), "");
|
||||
solAssert(_assembly.stackHeight() - depositBefore == int(ref->second.valueSize), "");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -626,15 +630,15 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
"Can only assign to stack variables in inline assembly."
|
||||
);
|
||||
solAssert(variable->type()->sizeOnStack() == 1, "");
|
||||
int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable) - 1;
|
||||
int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable) - 1;
|
||||
if (stackDiff > 16 || stackDiff < 1)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
CompilerError() <<
|
||||
errinfo_sourceLocation(_inlineAssembly.location()) <<
|
||||
errinfo_comment("Stack too deep, try removing local variables.")
|
||||
errinfo_comment("Stack too deep(" + to_string(stackDiff) + "), try removing local variables.")
|
||||
);
|
||||
_assembly.append(swapInstruction(stackDiff));
|
||||
_assembly.append(Instruction::POP);
|
||||
_assembly.appendInstruction(swapInstruction(stackDiff));
|
||||
_assembly.appendInstruction(Instruction::POP);
|
||||
}
|
||||
};
|
||||
solAssert(_inlineAssembly.annotation().analysisInfo, "");
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include <libevmasm/SourceLocation.h>
|
||||
#include <libevmasm/Instruction.h>
|
||||
|
||||
#include <libjulia/backends/AbstractAssembly.h>
|
||||
|
||||
#include <libdevcore/CommonIO.h>
|
||||
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
@ -48,24 +50,61 @@ using namespace dev::solidity::assembly;
|
||||
|
||||
struct GeneratorState
|
||||
{
|
||||
GeneratorState(ErrorList& _errors, AsmAnalysisInfo& _analysisInfo, eth::Assembly& _assembly):
|
||||
errors(_errors), info(_analysisInfo), assembly(_assembly) {}
|
||||
GeneratorState(ErrorList& _errors, AsmAnalysisInfo& _analysisInfo):
|
||||
errors(_errors), info(_analysisInfo) {}
|
||||
|
||||
size_t newLabelId()
|
||||
ErrorList& errors;
|
||||
AsmAnalysisInfo info;
|
||||
};
|
||||
|
||||
class EthAssemblyAdapter: public julia::AbstractAssembly
|
||||
{
|
||||
public:
|
||||
EthAssemblyAdapter(eth::Assembly& _assembly):
|
||||
m_assembly(_assembly)
|
||||
{
|
||||
return assemblyTagToIdentifier(assembly.newTag());
|
||||
}
|
||||
virtual void setSourceLocation(SourceLocation const& _location) override
|
||||
{
|
||||
m_assembly.setSourceLocation(_location);
|
||||
}
|
||||
virtual int stackHeight() const override { return m_assembly.deposit(); }
|
||||
virtual void appendInstruction(solidity::Instruction _instruction) override
|
||||
{
|
||||
m_assembly.append(_instruction);
|
||||
}
|
||||
virtual void appendConstant(u256 const& _constant) override
|
||||
{
|
||||
m_assembly.append(_constant);
|
||||
}
|
||||
/// Append a label.
|
||||
virtual void appendLabel(size_t _labelId) override
|
||||
{
|
||||
m_assembly.append(eth::AssemblyItem(eth::Tag, _labelId));
|
||||
}
|
||||
/// Append a label reference.
|
||||
virtual void appendLabelReference(size_t _labelId) override
|
||||
{
|
||||
m_assembly.append(eth::AssemblyItem(eth::PushTag, _labelId));
|
||||
}
|
||||
virtual size_t newLabel() override
|
||||
{
|
||||
return assemblyTagToIdentifier(m_assembly.newTag());
|
||||
}
|
||||
virtual void appendLinkerSymbol(std::string const& _linkerSymbol) override
|
||||
{
|
||||
m_assembly.appendLibraryAddress(_linkerSymbol);
|
||||
}
|
||||
|
||||
size_t assemblyTagToIdentifier(eth::AssemblyItem const& _tag) const
|
||||
private:
|
||||
size_t assemblyTagToIdentifier(eth::AssemblyItem const& _tag)
|
||||
{
|
||||
u256 id = _tag.data();
|
||||
solAssert(id <= std::numeric_limits<size_t>::max(), "Tag id too large.");
|
||||
return size_t(id);
|
||||
}
|
||||
|
||||
ErrorList& errors;
|
||||
AsmAnalysisInfo info;
|
||||
eth::Assembly& assembly;
|
||||
eth::Assembly& m_assembly;
|
||||
};
|
||||
|
||||
class CodeTransform: public boost::static_visitor<>
|
||||
@ -76,81 +115,84 @@ public:
|
||||
/// @param _identifierAccess used to resolve identifiers external to the inline assembly
|
||||
explicit CodeTransform(
|
||||
GeneratorState& _state,
|
||||
julia::AbstractAssembly& _assembly,
|
||||
assembly::Block const& _block,
|
||||
assembly::ExternalIdentifierAccess const& _identifierAccess = assembly::ExternalIdentifierAccess()
|
||||
): CodeTransform(_state, _block, _identifierAccess, _state.assembly.deposit())
|
||||
): CodeTransform(_state, _assembly, _block, _identifierAccess, _assembly.stackHeight())
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
CodeTransform(
|
||||
GeneratorState& _state,
|
||||
julia::AbstractAssembly& _assembly,
|
||||
assembly::Block const& _block,
|
||||
assembly::ExternalIdentifierAccess const& _identifierAccess,
|
||||
int _initialDeposit
|
||||
int _initialStackHeight
|
||||
):
|
||||
m_state(_state),
|
||||
m_assembly(_assembly),
|
||||
m_scope(*m_state.info.scopes.at(&_block)),
|
||||
m_identifierAccess(_identifierAccess),
|
||||
m_initialDeposit(_initialDeposit)
|
||||
m_initialStackHeight(_initialStackHeight)
|
||||
{
|
||||
int blockStartDeposit = m_state.assembly.deposit();
|
||||
int blockStartStackHeight = m_assembly.stackHeight();
|
||||
std::for_each(_block.statements.begin(), _block.statements.end(), boost::apply_visitor(*this));
|
||||
|
||||
m_state.assembly.setSourceLocation(_block.location);
|
||||
m_assembly.setSourceLocation(_block.location);
|
||||
|
||||
// pop variables
|
||||
for (auto const& identifier: m_scope.identifiers)
|
||||
if (identifier.second.type() == typeid(Scope::Variable))
|
||||
m_state.assembly.append(solidity::Instruction::POP);
|
||||
m_assembly.appendInstruction(solidity::Instruction::POP);
|
||||
|
||||
int deposit = m_state.assembly.deposit() - blockStartDeposit;
|
||||
int deposit = m_assembly.stackHeight() - blockStartStackHeight;
|
||||
solAssert(deposit == 0, "Invalid stack height at end of block.");
|
||||
}
|
||||
|
||||
public:
|
||||
void operator()(assembly::Instruction const& _instruction)
|
||||
{
|
||||
m_state.assembly.setSourceLocation(_instruction.location);
|
||||
m_state.assembly.append(_instruction.instruction);
|
||||
m_assembly.setSourceLocation(_instruction.location);
|
||||
m_assembly.appendInstruction(_instruction.instruction);
|
||||
checkStackHeight(&_instruction);
|
||||
}
|
||||
void operator()(assembly::Literal const& _literal)
|
||||
{
|
||||
m_state.assembly.setSourceLocation(_literal.location);
|
||||
m_assembly.setSourceLocation(_literal.location);
|
||||
if (_literal.kind == assembly::LiteralKind::Number)
|
||||
m_state.assembly.append(u256(_literal.value));
|
||||
m_assembly.appendConstant(u256(_literal.value));
|
||||
else if (_literal.kind == assembly::LiteralKind::Boolean)
|
||||
{
|
||||
if (_literal.value == "true")
|
||||
m_state.assembly.append(u256(1));
|
||||
m_assembly.appendConstant(u256(1));
|
||||
else
|
||||
m_state.assembly.append(u256(0));
|
||||
m_assembly.appendConstant(u256(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
solAssert(_literal.value.size() <= 32, "");
|
||||
m_state.assembly.append(u256(h256(_literal.value, h256::FromBinary, h256::AlignLeft)));
|
||||
m_assembly.appendConstant(u256(h256(_literal.value, h256::FromBinary, h256::AlignLeft)));
|
||||
}
|
||||
checkStackHeight(&_literal);
|
||||
}
|
||||
void operator()(assembly::Identifier const& _identifier)
|
||||
{
|
||||
m_state.assembly.setSourceLocation(_identifier.location);
|
||||
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_state.assembly.append(solidity::dupInstruction(heightDiff));
|
||||
m_assembly.appendInstruction(solidity::dupInstruction(heightDiff));
|
||||
else
|
||||
// Store something to balance the stack
|
||||
m_state.assembly.append(u256(0));
|
||||
m_assembly.appendConstant(u256(0));
|
||||
},
|
||||
[=](Scope::Label& _label)
|
||||
{
|
||||
assignLabelIdIfUnset(_label);
|
||||
m_state.assembly.append(eth::AssemblyItem(eth::PushTag, _label.id));
|
||||
m_assembly.appendLabelReference(*_label.id);
|
||||
},
|
||||
[=](Scope::Function&)
|
||||
{
|
||||
@ -164,14 +206,14 @@ public:
|
||||
m_identifierAccess.generateCode,
|
||||
"Identifier not found and no external access available."
|
||||
);
|
||||
m_identifierAccess.generateCode(_identifier, IdentifierContext::RValue, m_state.assembly);
|
||||
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_state.assembly.deposit();
|
||||
int height = m_assembly.stackHeight();
|
||||
boost::apply_visitor(*this, *it);
|
||||
expectDeposit(1, height);
|
||||
}
|
||||
@ -184,31 +226,31 @@ public:
|
||||
}
|
||||
void operator()(Label const& _label)
|
||||
{
|
||||
m_state.assembly.setSourceLocation(_label.location);
|
||||
m_assembly.setSourceLocation(_label.location);
|
||||
solAssert(m_scope.identifiers.count(_label.name), "");
|
||||
Scope::Label& label = boost::get<Scope::Label>(m_scope.identifiers.at(_label.name));
|
||||
assignLabelIdIfUnset(label);
|
||||
m_state.assembly.append(eth::AssemblyItem(eth::Tag, label.id));
|
||||
m_assembly.appendLabel(*label.id);
|
||||
checkStackHeight(&_label);
|
||||
}
|
||||
void operator()(assembly::Assignment const& _assignment)
|
||||
{
|
||||
m_state.assembly.setSourceLocation(_assignment.location);
|
||||
m_assembly.setSourceLocation(_assignment.location);
|
||||
generateAssignment(_assignment.variableName, _assignment.location);
|
||||
checkStackHeight(&_assignment);
|
||||
}
|
||||
void operator()(FunctionalAssignment const& _assignment)
|
||||
{
|
||||
int height = m_state.assembly.deposit();
|
||||
size_t height = m_assembly.stackHeight();
|
||||
boost::apply_visitor(*this, *_assignment.value);
|
||||
expectDeposit(1, height);
|
||||
m_state.assembly.setSourceLocation(_assignment.location);
|
||||
m_assembly.setSourceLocation(_assignment.location);
|
||||
generateAssignment(_assignment.variableName, _assignment.location);
|
||||
checkStackHeight(&_assignment);
|
||||
}
|
||||
void operator()(assembly::VariableDeclaration const& _varDecl)
|
||||
{
|
||||
int height = m_state.assembly.deposit();
|
||||
size_t height = m_assembly.stackHeight();
|
||||
boost::apply_visitor(*this, *_varDecl.value);
|
||||
expectDeposit(1, height);
|
||||
auto& var = boost::get<Scope::Variable>(m_scope.identifiers.at(_varDecl.variable.name));
|
||||
@ -217,7 +259,7 @@ public:
|
||||
}
|
||||
void operator()(assembly::Block const& _block)
|
||||
{
|
||||
CodeTransform(m_state, _block, m_identifierAccess, m_initialDeposit);
|
||||
CodeTransform(m_state, m_assembly, _block, m_identifierAccess, m_initialStackHeight);
|
||||
checkStackHeight(&_block);
|
||||
}
|
||||
void operator()(assembly::FunctionDefinition const&)
|
||||
@ -233,8 +275,8 @@ private:
|
||||
{
|
||||
Scope::Variable const& _var = boost::get<Scope::Variable>(*var);
|
||||
if (int heightDiff = variableHeightDiff(_var, _location, true))
|
||||
m_state.assembly.append(solidity::swapInstruction(heightDiff - 1));
|
||||
m_state.assembly.append(solidity::Instruction::POP);
|
||||
m_assembly.appendInstruction(solidity::swapInstruction(heightDiff - 1));
|
||||
m_assembly.appendInstruction(solidity::Instruction::POP);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -242,16 +284,16 @@ private:
|
||||
m_identifierAccess.generateCode,
|
||||
"Identifier not found and no external access available."
|
||||
);
|
||||
m_identifierAccess.generateCode(_variableName, IdentifierContext::LValue, m_state.assembly);
|
||||
m_identifierAccess.generateCode(_variableName, IdentifierContext::LValue, m_assembly);
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)
|
||||
size_t variableHeightDiff(Scope::Variable const& _var, SourceLocation const& _location, bool _forSwap)
|
||||
{
|
||||
int heightDiff = m_state.assembly.deposit() - _var.stackHeight;
|
||||
size_t heightDiff = m_assembly.stackHeight() - _var.stackHeight;
|
||||
if (heightDiff <= (_forSwap ? 1 : 0) || heightDiff > (_forSwap ? 17 : 16))
|
||||
{
|
||||
//@TODO move this to analysis phase.
|
||||
@ -268,14 +310,14 @@ private:
|
||||
|
||||
void expectDeposit(int _deposit, int _oldHeight)
|
||||
{
|
||||
solAssert(m_state.assembly.deposit() == _oldHeight + _deposit, "Invalid stack deposit.");
|
||||
solAssert(m_assembly.stackHeight() == _oldHeight + _deposit, "Invalid stack deposit.");
|
||||
}
|
||||
|
||||
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_state.assembly.deposit() - m_initialDeposit,
|
||||
m_state.info.stackHeightInfo.at(_astElement) == m_assembly.stackHeight() - m_initialStackHeight,
|
||||
"Stack height mismatch between analysis and code generation phase."
|
||||
);
|
||||
}
|
||||
@ -283,15 +325,16 @@ private:
|
||||
/// 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 == Scope::Label::unassignedLabelId)
|
||||
_label.id = m_state.newLabelId();
|
||||
if (!_label.id)
|
||||
_label.id.reset(m_assembly.newLabel());
|
||||
}
|
||||
|
||||
|
||||
GeneratorState& m_state;
|
||||
julia::AbstractAssembly& m_assembly;
|
||||
Scope& m_scope;
|
||||
ExternalIdentifierAccess m_identifierAccess;
|
||||
int const m_initialDeposit;
|
||||
int const m_initialStackHeight;
|
||||
};
|
||||
|
||||
eth::Assembly assembly::CodeGenerator::assemble(
|
||||
@ -301,8 +344,9 @@ eth::Assembly assembly::CodeGenerator::assemble(
|
||||
)
|
||||
{
|
||||
eth::Assembly assembly;
|
||||
GeneratorState state(m_errors, _analysisInfo, assembly);
|
||||
CodeTransform(state, _parsedData, _identifierAccess);
|
||||
GeneratorState state(m_errors, _analysisInfo);
|
||||
EthAssemblyAdapter assemblyAdapter(assembly);
|
||||
CodeTransform(state, assemblyAdapter, _parsedData, _identifierAccess);
|
||||
return assembly;
|
||||
}
|
||||
|
||||
@ -313,6 +357,7 @@ void assembly::CodeGenerator::assemble(
|
||||
ExternalIdentifierAccess const& _identifierAccess
|
||||
)
|
||||
{
|
||||
GeneratorState state(m_errors, _analysisInfo, _assembly);
|
||||
CodeTransform(state, _parsedData, _identifierAccess);
|
||||
GeneratorState state(m_errors, _analysisInfo);
|
||||
EthAssemblyAdapter assemblyAdapter(_assembly);
|
||||
CodeTransform(state, assemblyAdapter, _parsedData, _identifierAccess);
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <libsolidity/interface/Exceptions.h>
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
@ -75,8 +76,7 @@ struct Scope
|
||||
|
||||
struct Label
|
||||
{
|
||||
size_t id = unassignedLabelId;
|
||||
static const size_t unassignedLabelId = 0;
|
||||
boost::optional<size_t> id;
|
||||
};
|
||||
|
||||
struct Function
|
||||
|
@ -24,6 +24,8 @@
|
||||
|
||||
#include <libsolidity/interface/Exceptions.h>
|
||||
|
||||
#include <libjulia/backends/AbstractAssembly.h>
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
@ -51,7 +53,7 @@ struct ExternalIdentifierAccess
|
||||
/// 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<void(assembly::Identifier const&, IdentifierContext, eth::Assembly&)>;
|
||||
using CodeGenerator = std::function<void(assembly::Identifier const&, IdentifierContext, julia::AbstractAssembly&)>;
|
||||
/// 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.
|
||||
|
@ -4,6 +4,7 @@ aux_source_directory(. SRC_LIST)
|
||||
aux_source_directory(libdevcore SRC_LIST)
|
||||
aux_source_directory(libevmasm SRC_LIST)
|
||||
aux_source_directory(libsolidity SRC_LIST)
|
||||
aux_source_directory(libjulia SRC_LIST)
|
||||
aux_source_directory(contracts SRC_LIST)
|
||||
aux_source_directory(liblll SRC_LIST)
|
||||
aux_source_directory(libjulia SRC_LIST)
|
||||
|
Loading…
Reference in New Issue
Block a user