diff options
author | chriseth <c@ethdev.com> | 2017-03-14 22:41:23 +0800 |
---|---|---|
committer | chriseth <chris@ethereum.org> | 2017-04-25 22:49:03 +0800 |
commit | e0849f2f3bbb23ebddb37cd770f46266967e789d (patch) | |
tree | 53c454ea354e032963ef246e11210de44731155c | |
parent | 5d6747eb32f56f6b8b818eff5635888d250d62e1 (diff) | |
download | dexon-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.cpp | 19 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 43 | ||||
-rw-r--r-- | libsolidity/ast/ASTAnnotations.h | 10 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.cpp | 23 | ||||
-rw-r--r-- | libsolidity/codegen/ContractCompiler.cpp | 152 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmCodeGen.cpp | 42 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmCodeGen.h | 18 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmStack.cpp | 2 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmStack.h | 22 |
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; } |