aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/codegen
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2016-03-02 05:56:39 +0800
committerchriseth <c@ethdev.com>2016-03-30 08:37:00 +0800
commitf0494307232e52dcc268f5f32d26cc89d7e98e3a (patch)
tree5a03eae3515eb50d67388e7d7d1193d016baaddf /libsolidity/codegen
parent949b00ed591303c531ed8fa73087b710b7a554de (diff)
downloaddexon-solidity-f0494307232e52dcc268f5f32d26cc89d7e98e3a.tar.gz
dexon-solidity-f0494307232e52dcc268f5f32d26cc89d7e98e3a.tar.zst
dexon-solidity-f0494307232e52dcc268f5f32d26cc89d7e98e3a.zip
Code generation (missing external access and source locations).
Diffstat (limited to 'libsolidity/codegen')
-rw-r--r--libsolidity/codegen/Compiler.cpp86
-rw-r--r--libsolidity/codegen/Compiler.h1
-rw-r--r--libsolidity/codegen/CompilerContext.h2
3 files changed, 89 insertions, 0 deletions
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 <libevmcore/Instruction.h>
#include <libethcore/ChainOperationParams.h>
#include <libevmasm/Assembly.h>
+#include <libsolidity/inlineasm/AsmCodeGen.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/codegen/ExpressionCompiler.h>
#include <libsolidity/codegen/CompilerUtils.h>
@@ -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<FunctionDefinition const*>(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<VariableDeclaration const*>(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<ContractDefinition const*>(decl))
+ {
+ solAssert(contract->isLibrary(), "");
+ _assembly.appendLibraryAddress(contract->name());
+ }
+ 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() + 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