From f0494307232e52dcc268f5f32d26cc89d7e98e3a Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 1 Mar 2016 22:56:39 +0100 Subject: Code generation (missing external access and source locations). --- libsolidity/codegen/Compiler.cpp | 86 +++++++++++++++++++++++++++++++++++ libsolidity/codegen/Compiler.h | 1 + libsolidity/codegen/CompilerContext.h | 2 + 3 files changed, 89 insertions(+) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp index c7eb71a8..69e23359 100644 --- a/libsolidity/codegen/Compiler.cpp +++ b/libsolidity/codegen/Compiler.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -497,6 +498,91 @@ bool Compiler::visit(FunctionDefinition const& _function) return false; } +bool Compiler::visit(InlineAssembly const& _inlineAssembly) +{ + ErrorList errors; + assembly::CodeGenerator codeGen(_inlineAssembly.operations(), errors); + int startStackHeight = m_context.stackHeight(); + m_context.appendInlineAssembly(codeGen.assemble( + [&](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) + { + solAssert(!!decl->type(), "Type of declaration required but not yet determined."); + if (/*FunctionDefinition const* functionDef = */dynamic_cast(decl)) + { + solAssert(false, "Referencing local functions in inline assembly not yet implemented."); + // This does not work directly, because the label does not exist in _assembly + // (it is a fresh assembly object). + // _assembly.append(m_context.virtualFunctionEntryLabel(*functionDef).pushTag()); + } + else if (auto variable = dynamic_cast(decl)) + { + solAssert(!variable->isConstant(), ""); + if (m_context.isLocalVariable(variable)) + { + int stackDiff = _assembly.deposit() + startStackHeight - m_context.baseStackOffsetOfVariable(*variable); + if (stackDiff < 1 || stackDiff > 16) + BOOST_THROW_EXCEPTION( + CompilerError() << + errinfo_comment("Stack too deep, try removing local variables.") + ); + for (unsigned i = 0; i < variable->type()->sizeOnStack(); ++i) + _assembly.append(eth::dupInstruction(stackDiff)); + } + 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)); + } + } + } + else if (auto contract = dynamic_cast(decl)) + { + solAssert(contract->isLibrary(), ""); + _assembly.appendLibraryAddress(contract->name()); + } + else + solAssert(false, "Invalid declaration type."); + } else { + // lvalue context + auto variable = dynamic_cast(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() + startStackHeight - m_context.baseStackOffsetOfVariable(*variable) - size; + if (stackDiff > 16 || stackDiff < 1) + BOOST_THROW_EXCEPTION( + CompilerError() << + errinfo_comment("Stack too deep, try removing local variables.") + ); + for (unsigned i = 0; i < size; ++i) { + _assembly.append(eth::swapInstruction(stackDiff)); + _assembly.append(eth::Instruction::POP); + } + } + return true; + } + )); + solAssert(errors.empty(), "Code generation for inline assembly with errors requested."); + return false; +} + bool Compiler::visit(IfStatement const& _ifStatement) { StackHeightChecker checker(m_context); diff --git a/libsolidity/codegen/Compiler.h b/libsolidity/codegen/Compiler.h index fa33bd30..68ad904a 100644 --- a/libsolidity/codegen/Compiler.h +++ b/libsolidity/codegen/Compiler.h @@ -94,6 +94,7 @@ private: virtual bool visit(VariableDeclaration const& _variableDeclaration) override; virtual bool visit(FunctionDefinition const& _function) override; + virtual bool visit(InlineAssembly const& _inlineAssembly) override; virtual bool visit(IfStatement const& _ifStatement) override; virtual bool visit(WhileStatement const& _whileStatement) override; virtual bool visit(ForStatement const& _forStatement) override; diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 5287088a..bd8fc295 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -109,6 +109,8 @@ public: /// Adds a subroutine to the code (in the data section) and pushes its size (via a tag) /// on the stack. @returns the assembly item corresponding to the pushed subroutine, i.e. its offset. eth::AssemblyItem addSubroutine(eth::Assembly const& _assembly) { return m_asm.appendSubSize(_assembly); } + /// Appends the given code (used by inline assembly) ignoring any stack height changes. + void appendInlineAssembly(eth::Assembly const& _assembly) { int deposit = m_asm.deposit(); m_asm.append(_assembly); m_asm.setDeposit(deposit); } /// Pushes the size of the final program void appendProgramSize() { return m_asm.appendProgramSize(); } /// Adds data to the data section, pushes a reference to the stack -- cgit