aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/inlineasm
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/inlineasm')
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.cpp42
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.h18
-rw-r--r--libsolidity/inlineasm/AsmStack.cpp2
-rw-r--r--libsolidity/inlineasm/AsmStack.h22
4 files changed, 55 insertions, 29 deletions
diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libsolidity/inlineasm/AsmCodeGen.cpp
index 1caaa677..d094aa97 100644
--- a/libsolidity/inlineasm/AsmCodeGen.cpp
+++ b/libsolidity/inlineasm/AsmCodeGen.cpp
@@ -81,7 +81,7 @@ public:
explicit CodeTransform(
GeneratorState& _state,
assembly::Block const& _block,
- assembly::CodeGenerator::IdentifierAccess const& _identifierAccess = assembly::CodeGenerator::IdentifierAccess()
+ assembly::ExternalIdentifierAccess const& _identifierAccess = assembly::ExternalIdentifierAccess()
):
m_state(_state),
m_scope(*m_state.scopes.at(&_block)),
@@ -160,15 +160,23 @@ public:
{
return;
}
- solAssert(m_identifierAccess, "Identifier not found and no external access available.");
- if (!m_identifierAccess(_identifier, m_state.assembly, CodeGenerator::IdentifierContext::RValue))
+ solAssert(
+ m_identifierAccess.resolve && m_identifierAccess.generateCode,
+ "Identifier not found and no external access available."
+ );
+ // @TODO refactor: Store resolved identifier.
+ size_t size = m_identifierAccess.resolve(_identifier, IdentifierContext::RValue);
+ if (size != size_t(-1))
+ m_identifierAccess.generateCode(_identifier, IdentifierContext::RValue, m_state.assembly);
+ else
{
m_state.addError(
Error::Type::DeclarationError,
"Identifier not found or not unique",
_identifier.location
);
- m_state.assembly.append(u256(0));
+ for (size_t i = 0; i < size; ++i)
+ m_state.assembly.append(u256(0));
}
}
void operator()(FunctionalInstruction const& _instr)
@@ -236,12 +244,20 @@ private:
m_state.assembly.append(solidity::Instruction::POP);
return;
}
- solAssert(m_identifierAccess, "Identifier not found and no external access available.");
- if (!m_identifierAccess(_variableName, m_state.assembly, CodeGenerator::IdentifierContext::LValue))
+ solAssert(
+ m_identifierAccess.resolve && m_identifierAccess.generateCode,
+ "Identifier not found and no external access available."
+ );
+ size_t size = m_identifierAccess.resolve(_variableName, IdentifierContext::LValue);
+ if (size != size_t(-1))
+ m_identifierAccess.generateCode(_variableName, IdentifierContext::LValue, m_state.assembly);
+ else
+ {
m_state.addError(
Error::Type::DeclarationError,
"Identifier \"" + string(_variableName.name) + "\" not found, not unique or not lvalue."
);
+ }
}
/// Determines the stack height difference to the given variables. Automatically generates
@@ -289,34 +305,34 @@ private:
GeneratorState& m_state;
Scope& m_scope;
int const m_initialDeposit;
- assembly::CodeGenerator::IdentifierAccess m_identifierAccess;
+ ExternalIdentifierAccess m_identifierAccess;
};
-bool assembly::CodeGenerator::typeCheck(assembly::CodeGenerator::IdentifierAccess const& _identifierAccess)
+bool assembly::CodeGenerator::typeCheck(ExternalIdentifierAccess const& _identifierAccess)
{
size_t initialErrorLen = m_errors.size();
eth::Assembly assembly;
GeneratorState state(m_errors, assembly);
- if (!(AsmAnalyzer(state.scopes, m_errors, !!_identifierAccess)).analyze(m_parsedData))
+ if (!(AsmAnalyzer(state.scopes, m_errors, !!_identifierAccess.resolve)).analyze(m_parsedData))
return false;
CodeTransform(state, m_parsedData, _identifierAccess);
return m_errors.size() == initialErrorLen;
}
-eth::Assembly assembly::CodeGenerator::assemble(assembly::CodeGenerator::IdentifierAccess const& _identifierAccess)
+eth::Assembly assembly::CodeGenerator::assemble(ExternalIdentifierAccess const& _identifierAccess)
{
eth::Assembly assembly;
GeneratorState state(m_errors, assembly);
- if (!(AsmAnalyzer(state.scopes, m_errors, !!_identifierAccess)).analyze(m_parsedData))
+ if (!(AsmAnalyzer(state.scopes, m_errors, !!_identifierAccess.resolve)).analyze(m_parsedData))
solAssert(false, "Assembly error");
CodeTransform(state, m_parsedData, _identifierAccess);
return assembly;
}
-void assembly::CodeGenerator::assemble(eth::Assembly& _assembly, assembly::CodeGenerator::IdentifierAccess const& _identifierAccess)
+void assembly::CodeGenerator::assemble(eth::Assembly& _assembly, ExternalIdentifierAccess const& _identifierAccess)
{
GeneratorState state(m_errors, _assembly);
- if (!(AsmAnalyzer(state.scopes, m_errors, !!_identifierAccess)).analyze(m_parsedData))
+ if (!(AsmAnalyzer(state.scopes, m_errors, !!_identifierAccess.resolve)).analyze(m_parsedData))
solAssert(false, "Assembly error");
CodeTransform(state, m_parsedData, _identifierAccess);
}
diff --git a/libsolidity/inlineasm/AsmCodeGen.h b/libsolidity/inlineasm/AsmCodeGen.h
index bd71812e..f259a36c 100644
--- a/libsolidity/inlineasm/AsmCodeGen.h
+++ b/libsolidity/inlineasm/AsmCodeGen.h
@@ -22,8 +22,10 @@
#pragma once
-#include <functional>
#include <libsolidity/interface/Exceptions.h>
+#include <libsolidity/inlineasm/AsmStack.h>
+
+#include <functional>
namespace dev
{
@@ -36,27 +38,19 @@ namespace solidity
namespace assembly
{
struct Block;
-struct Identifier;
class CodeGenerator
{
public:
- enum class IdentifierContext { LValue, RValue };
- /// Function type that is called for external identifiers. Such a function should search for
- /// the identifier and append appropriate assembly items to the assembly. If in lvalue context,
- /// the value to assign is assumed to be on the stack and an assignment is to be performed.
- /// If in rvalue context, the function is assumed to append instructions to
- /// push the value of the identifier onto the stack. On error, the function should return false.
- using IdentifierAccess = std::function<bool(assembly::Identifier const&, eth::Assembly&, IdentifierContext)>;
CodeGenerator(Block const& _parsedData, ErrorList& _errors):
m_parsedData(_parsedData), m_errors(_errors) {}
/// Performs type checks and @returns false on error.
/// Actually runs the full code generation but discards the result.
- bool typeCheck(IdentifierAccess const& _identifierAccess = IdentifierAccess());
+ bool typeCheck(ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess());
/// Performs code generation and @returns the result.
- eth::Assembly assemble(IdentifierAccess const& _identifierAccess = IdentifierAccess());
+ eth::Assembly assemble(ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess());
/// Performs code generation and appends generated to to _assembly.
- void assemble(eth::Assembly& _assembly, IdentifierAccess const& _identifierAccess = IdentifierAccess());
+ void assemble(eth::Assembly& _assembly, ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess());
private:
Block const& m_parsedData;
diff --git a/libsolidity/inlineasm/AsmStack.cpp b/libsolidity/inlineasm/AsmStack.cpp
index 8d011cf8..09084642 100644
--- a/libsolidity/inlineasm/AsmStack.cpp
+++ b/libsolidity/inlineasm/AsmStack.cpp
@@ -66,7 +66,7 @@ eth::Assembly InlineAssemblyStack::assemble()
bool InlineAssemblyStack::parseAndAssemble(
string const& _input,
eth::Assembly& _assembly,
- CodeGenerator::IdentifierAccess const& _identifierAccess
+ ExternalIdentifierAccess const& _identifierAccess
)
{
ErrorList errors;
diff --git a/libsolidity/inlineasm/AsmStack.h b/libsolidity/inlineasm/AsmStack.h
index 4d5a99a4..b6e4952a 100644
--- a/libsolidity/inlineasm/AsmStack.h
+++ b/libsolidity/inlineasm/AsmStack.h
@@ -22,10 +22,10 @@
#pragma once
+#include <libsolidity/interface/Exceptions.h>
+
#include <string>
#include <functional>
-#include <libsolidity/interface/Exceptions.h>
-#include <libsolidity/inlineasm/AsmCodeGen.h>
namespace dev
{
@@ -39,6 +39,22 @@ class Scanner;
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
+{
+ /// 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.
+ std::function<size_t(assembly::Identifier const&, IdentifierContext)> resolve;
+ /// 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.
+ std::function<void(assembly::Identifier const&, IdentifierContext, eth::Assembly&)> generateCode;
+};
class InlineAssemblyStack
{
@@ -56,7 +72,7 @@ public:
bool parseAndAssemble(
std::string const& _input,
eth::Assembly& _assembly,
- CodeGenerator::IdentifierAccess const& _identifierAccess = CodeGenerator::IdentifierAccess()
+ ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess()
);
ErrorList const& errors() const { return m_errors; }