aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2017-03-14 22:41:23 +0800
committerchriseth <chris@ethereum.org>2017-04-25 22:49:03 +0800
commite0849f2f3bbb23ebddb37cd770f46266967e789d (patch)
tree53c454ea354e032963ef246e11210de44731155c
parent5d6747eb32f56f6b8b818eff5635888d250d62e1 (diff)
downloaddexon-solidity-e0849f2f3bbb23ebddb37cd770f46266967e789d.tar.gz
dexon-solidity-e0849f2f3bbb23ebddb37cd770f46266967e789d.tar.zst
dexon-solidity-e0849f2f3bbb23ebddb37cd770f46266967e789d.zip
Split external identifier access into resolving and code generation.
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp19
-rw-r--r--libsolidity/analysis/TypeChecker.cpp43
-rw-r--r--libsolidity/ast/ASTAnnotations.h10
-rw-r--r--libsolidity/codegen/CompilerContext.cpp23
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp152
-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
9 files changed, 188 insertions, 143 deletions
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index 37bcb2d9..5ff4ee2d 100644
--- a/libsolidity/analysis/ReferencesResolver.cpp
+++ b/libsolidity/analysis/ReferencesResolver.cpp
@@ -158,21 +158,22 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
{
- // We need to perform a full code generation pass here as inline assembly does not distinguish
- // reference resolution and code generation.
// Errors created in this stage are completely ignored because we do not yet know
// the type and size of external identifiers, which would result in false errors.
+ // The only purpose of this step is to fill the inline assembly annotation with
+ // external references.
ErrorList errorsIgnored;
assembly::CodeGenerator codeGen(_inlineAssembly.operations(), errorsIgnored);
- codeGen.typeCheck([&](assembly::Identifier const& _identifier, eth::Assembly&, assembly::CodeGenerator::IdentifierContext) {
+ assembly::ExternalIdentifierAccess identifierAccess;
+ identifierAccess.resolve = [&](assembly::Identifier const& _identifier, assembly::IdentifierContext) {
auto declarations = m_resolver.nameFromCurrentScope(_identifier.name);
if (declarations.size() != 1)
- return false;
- _inlineAssembly.annotation().externalReferences[&_identifier] = declarations.front();
- // At this stage we neither know the code to generate nor the stack size of the identifier,
- // so we do not modify assembly.
- return true;
- });
+ return size_t(-1);
+ _inlineAssembly.annotation().externalReferences[&_identifier].declaration = declarations.front();
+ // At this stage we do not yet know the stack size of the identifier, so we just return 1.
+ return size_t(1);
+ };
+ codeGen.typeCheck(identifierAccess);
return false;
}
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index b37db7b7..808914ae 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -628,47 +628,44 @@ void TypeChecker::endVisit(FunctionTypeName const& _funType)
bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
{
- // Inline assembly does not have its own type-checking phase, so we just run the
- // code-generator and see whether it produces any errors.
// External references have already been resolved in a prior stage and stored in the annotation.
- auto identifierAccess = [&](
+ // We run the resolve step again regardless.
+ assembly::ExternalIdentifierAccess identifierAccess;
+ identifierAccess.resolve = [&](
assembly::Identifier const& _identifier,
- eth::Assembly& _assembly,
- assembly::CodeGenerator::IdentifierContext _context
+ assembly::IdentifierContext _context
)
{
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
if (ref == _inlineAssembly.annotation().externalReferences.end())
- return false;
- Declaration const* declaration = ref->second;
+ return size_t(-1);
+ size_t valueSize = size_t(-1);
+ Declaration const* declaration = ref->second.declaration;
solAssert(!!declaration, "");
- if (_context == assembly::CodeGenerator::IdentifierContext::RValue)
+ if (_context == assembly::IdentifierContext::RValue)
{
solAssert(!!declaration->type(), "Type of declaration required but not yet determined.");
- unsigned pushes = 0;
if (dynamic_cast<FunctionDefinition const*>(declaration))
- pushes = 1;
+ valueSize = 1;
else if (auto var = dynamic_cast<VariableDeclaration const*>(declaration))
{
if (var->isConstant())
fatalTypeError(SourceLocation(), "Constant variables not yet implemented for inline assembly.");
if (var->isLocalVariable())
- pushes = var->type()->sizeOnStack();
+ valueSize = var->type()->sizeOnStack();
else if (!var->type()->isValueType())
- pushes = 1;
+ valueSize = 1;
else
- pushes = 2; // slot number, intra slot offset
+ valueSize = 2; // slot number, intra slot offset
}
else if (auto contract = dynamic_cast<ContractDefinition const*>(declaration))
{
if (!contract->isLibrary())
- return false;
- pushes = 1;
+ return size_t(-1);
+ valueSize = 1;
}
else
- return false;
- for (unsigned i = 0; i < pushes; ++i)
- _assembly.append(u256(0)); // just to verify the stack height
+ return size_t(-1);
}
else
{
@@ -676,14 +673,14 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
if (auto varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
{
if (!varDecl->isLocalVariable())
- return false; // only local variables are inline-assemlby lvalues
- for (unsigned i = 0; i < declaration->type()->sizeOnStack(); ++i)
- _assembly.append(Instruction::POP); // remove value just to verify the stack height
+ return size_t(-1); // only local variables are inline-assembly lvalues
+ valueSize = size_t(declaration->type()->sizeOnStack());
}
else
- return false;
+ return size_t(-1);
}
- return true;
+ ref->second.valueSize = valueSize;
+ return valueSize;
};
assembly::CodeGenerator codeGen(_inlineAssembly.operations(), m_errors);
if (!codeGen.typeCheck(identifierAccess))
diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h
index bd297f9e..9ca7f66c 100644
--- a/libsolidity/ast/ASTAnnotations.h
+++ b/libsolidity/ast/ASTAnnotations.h
@@ -117,8 +117,14 @@ struct Identifier; // forward
struct InlineAssemblyAnnotation: StatementAnnotation
{
- /// Mapping containing resolved references to external identifiers.
- std::map<assembly::Identifier const*, Declaration const*> externalReferences;
+ struct ExternalIdentifierInfo
+ {
+ Declaration const* declaration = nullptr;
+ size_t valueSize = size_t(-1);
+ };
+
+ /// Mapping containing resolved references to external identifiers and their value size
+ std::map<assembly::Identifier const*, ExternalIdentifierInfo> externalReferences;
};
struct ReturnAnnotation: StatementAnnotation
diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp
index a8316109..977e6c81 100644
--- a/libsolidity/codegen/CompilerContext.cpp
+++ b/libsolidity/codegen/CompilerContext.cpp
@@ -265,31 +265,38 @@ void CompilerContext::appendInlineAssembly(
}
unsigned startStackHeight = stackHeight();
- auto identifierAccess = [&](
+
+ assembly::ExternalIdentifierAccess identifierAccess;
+ identifierAccess.resolve = [&](
+ assembly::Identifier const& _identifier,
+ assembly::IdentifierContext
+ ) {
+ auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name);
+ return it == _localVariables.end() ? size_t(-1) : 1;
+ };
+ identifierAccess.generateCode = [&](
assembly::Identifier const& _identifier,
- eth::Assembly& _assembly,
- assembly::CodeGenerator::IdentifierContext _context
+ assembly::IdentifierContext _context,
+ eth::Assembly& _assembly
) {
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name);
- if (it == _localVariables.end())
- return false;
+ solAssert(it != _localVariables.end(), "");
unsigned stackDepth = _localVariables.end() - it;
int stackDiff = _assembly.deposit() - startStackHeight + stackDepth;
- if (_context == assembly::CodeGenerator::IdentifierContext::LValue)
+ 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.")
);
- if (_context == assembly::CodeGenerator::IdentifierContext::RValue)
+ if (_context == assembly::IdentifierContext::RValue)
_assembly.append(dupInstruction(stackDiff));
else
{
_assembly.append(swapInstruction(stackDiff));
_assembly.append(Instruction::POP);
}
- return true;
};
solAssert(assembly::InlineAssemblyStack().parseAndAssemble(*assembly, *m_asm, identifierAccess), "Failed to assemble inline assembly block.");
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp
index 6524bd03..a583f8b4 100644
--- a/libsolidity/codegen/ContractCompiler.cpp
+++ b/libsolidity/codegen/ContractCompiler.cpp
@@ -522,91 +522,99 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
ErrorList errors;
assembly::CodeGenerator codeGen(_inlineAssembly.operations(), errors);
unsigned startStackHeight = m_context.stackHeight();
- codeGen.assemble(
- m_context.nonConstAssembly(),
- [&](assembly::Identifier const& _identifier, eth::Assembly& _assembly, assembly::CodeGenerator::IdentifierContext _context) {
- auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
- if (ref == _inlineAssembly.annotation().externalReferences.end())
- return false;
- Declaration const* decl = ref->second;
- solAssert(!!decl, "");
- if (_context == assembly::CodeGenerator::IdentifierContext::RValue)
+ assembly::ExternalIdentifierAccess identifierAccess;
+ identifierAccess.resolve = [&](assembly::Identifier const& _identifier, assembly::IdentifierContext)
+ {
+ auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
+ if (ref == _inlineAssembly.annotation().externalReferences.end())
+ return size_t(-1);
+ return ref->second.valueSize;
+ };
+ identifierAccess.generateCode = [&](assembly::Identifier const& _identifier, assembly::IdentifierContext _context, eth::Assembly& _assembly)
+ {
+ auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
+ solAssert(ref != _inlineAssembly.annotation().externalReferences.end(), "");
+ Declaration const* decl = ref->second.declaration;
+ solAssert(!!decl, "");
+ if (_context == assembly::IdentifierContext::RValue)
+ {
+ solAssert(!!decl->type(), "Type of declaration required but not yet determined.");
+ if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(decl))
{
- solAssert(!!decl->type(), "Type of declaration required but not yet determined.");
- if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(decl))
+ functionDef = &m_context.resolveVirtualFunction(*functionDef);
+ _assembly.append(m_context.functionEntryLabel(*functionDef).pushTag());
+ // 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())
{
- functionDef = &m_context.resolveVirtualFunction(*functionDef);
- _assembly.append(m_context.functionEntryLabel(*functionDef).pushTag());
- // 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.append(u256(1) << 32);
+ _assembly.append(Instruction::MUL);
+ _assembly.append(rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub()));
+ _assembly.append(Instruction::OR);
+ }
+ }
+ else if (auto variable = dynamic_cast<VariableDeclaration const*>(decl))
+ {
+ solAssert(!variable->isConstant(), "");
+ if (m_context.isLocalVariable(variable))
+ {
+ int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable);
+ if (stackDiff < 1 || stackDiff > 16)
+ BOOST_THROW_EXCEPTION(
+ CompilerError() <<
+ errinfo_sourceLocation(_inlineAssembly.location()) <<
+ errinfo_comment("Stack too deep, try removing local variables.")
+ );
+ for (unsigned i = 0; i < variable->type()->sizeOnStack(); ++i)
+ _assembly.append(dupInstruction(stackDiff));
}
- else if (auto variable = dynamic_cast<VariableDeclaration const*>(decl))
+ else
{
- solAssert(!variable->isConstant(), "");
- if (m_context.isLocalVariable(variable))
+ solAssert(m_context.isStateVariable(variable), "Invalid variable type.");
+ auto const& location = m_context.storageLocationOfVariable(*variable);
+ if (!variable->type()->isValueType())
{
- int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable);
- if (stackDiff < 1 || stackDiff > 16)
- BOOST_THROW_EXCEPTION(
- CompilerError() <<
- errinfo_sourceLocation(_inlineAssembly.location()) <<
- errinfo_comment("Stack too deep, try removing local variables.")
- );
- for (unsigned i = 0; i < variable->type()->sizeOnStack(); ++i)
- _assembly.append(dupInstruction(stackDiff));
+ solAssert(location.second == 0, "Intra-slot offest assumed to be zero.");
+ _assembly.append(location.first);
}
else
{
- solAssert(m_context.isStateVariable(variable), "Invalid variable type.");
- auto const& location = m_context.storageLocationOfVariable(*variable);
- if (!variable->type()->isValueType())
- {
- solAssert(location.second == 0, "Intra-slot offest assumed to be zero.");
- _assembly.append(location.first);
- }
- else
- {
- _assembly.append(location.first);
- _assembly.append(u256(location.second));
- }
+ _assembly.append(location.first);
+ _assembly.append(u256(location.second));
}
}
- else if (auto contract = dynamic_cast<ContractDefinition const*>(decl))
- {
- solAssert(contract->isLibrary(), "");
- _assembly.appendLibraryAddress(contract->fullyQualifiedName());
- }
- else
- solAssert(false, "Invalid declaration type.");
- } else {
- // lvalue context
- auto variable = dynamic_cast<VariableDeclaration const*>(decl);
- solAssert(
- !!variable && m_context.isLocalVariable(variable),
- "Can only assign to stack variables in inline assembly."
+ }
+ else if (auto contract = dynamic_cast<ContractDefinition const*>(decl))
+ {
+ solAssert(contract->isLibrary(), "");
+ _assembly.appendLibraryAddress(contract->fullyQualifiedName());
+ }
+ else
+ solAssert(false, "Invalid declaration type.");
+ } else {
+ // lvalue context
+ auto variable = dynamic_cast<VariableDeclaration const*>(decl);
+ solAssert(
+ !!variable && m_context.isLocalVariable(variable),
+ "Can only assign to stack variables in inline assembly."
+ );
+ unsigned size = variable->type()->sizeOnStack();
+ int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable) - size;
+ if (stackDiff > 16 || stackDiff < 1)
+ BOOST_THROW_EXCEPTION(
+ CompilerError() <<
+ errinfo_sourceLocation(_inlineAssembly.location()) <<
+ errinfo_comment("Stack too deep, try removing local variables.")
);
- unsigned size = variable->type()->sizeOnStack();
- int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable) - size;
- if (stackDiff > 16 || stackDiff < 1)
- BOOST_THROW_EXCEPTION(
- CompilerError() <<
- errinfo_sourceLocation(_inlineAssembly.location()) <<
- errinfo_comment("Stack too deep, try removing local variables.")
- );
- for (unsigned i = 0; i < size; ++i) {
- _assembly.append(swapInstruction(stackDiff));
- _assembly.append(Instruction::POP);
- }
+ for (unsigned i = 0; i < size; ++i) {
+ _assembly.append(swapInstruction(stackDiff));
+ _assembly.append(Instruction::POP);
}
- return true;
}
+ };
+ codeGen.assemble(
+ m_context.nonConstAssembly(),
+ identifierAccess
);
solAssert(Error::containsOnlyWarnings(errors), "Code generation for inline assembly with errors requested.");
m_context.setStackOffset(startStackHeight);
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; }