Converted sub assembly to smart pointer.

This commit is contained in:
chriseth
2016-11-16 14:37:18 +01:00
parent e543bd34c0
commit e51f852504
11 changed files with 133 additions and 87 deletions
+7 -7
View File
@@ -60,8 +60,8 @@ void CompilerContext::startFunction(Declaration const& _function)
void CompilerContext::addVariable(VariableDeclaration const& _declaration,
unsigned _offsetToCurrent)
{
solAssert(m_asm.deposit() >= 0 && unsigned(m_asm.deposit()) >= _offsetToCurrent, "");
m_localVariables[&_declaration] = unsigned(m_asm.deposit()) - _offsetToCurrent;
solAssert(m_asm->deposit() >= 0 && unsigned(m_asm->deposit()) >= _offsetToCurrent, "");
m_localVariables[&_declaration] = unsigned(m_asm->deposit()) - _offsetToCurrent;
}
void CompilerContext::removeVariable(VariableDeclaration const& _declaration)
@@ -145,12 +145,12 @@ unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declarat
unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const
{
return m_asm.deposit() - _baseOffset - 1;
return m_asm->deposit() - _baseOffset - 1;
}
unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const
{
return m_asm.deposit() - _offset - 1;
return m_asm->deposit() - _offset - 1;
}
pair<u256, unsigned> CompilerContext::storageLocationOfVariable(const Declaration& _declaration) const
@@ -217,12 +217,12 @@ void CompilerContext::appendInlineAssembly(
return true;
};
solAssert(assembly::InlineAssemblyStack().parseAndAssemble(*assembly, m_asm, identifierAccess), "");
solAssert(assembly::InlineAssemblyStack().parseAndAssemble(*assembly, *m_asm, identifierAccess), "");
}
void CompilerContext::injectVersionStampIntoSub(size_t _subIndex)
{
eth::Assembly& sub = m_asm.sub(_subIndex);
eth::Assembly& sub = m_asm->sub(_subIndex);
sub.injectStart(Instruction::POP);
sub.injectStart(fromBigEndian<u256>(binaryVersion()));
}
@@ -257,7 +257,7 @@ vector<ContractDefinition const*>::const_iterator CompilerContext::superContract
void CompilerContext::updateSourceLocation()
{
m_asm.setSourceLocation(m_visitedNodes.empty() ? SourceLocation() : m_visitedNodes.top()->location());
m_asm->setSourceLocation(m_visitedNodes.empty() ? SourceLocation() : m_visitedNodes.top()->location());
}
eth::AssemblyItem CompilerContext::FunctionCompilationQueue::entryLabel(
+31 -31
View File
@@ -44,11 +44,12 @@ namespace solidity {
class CompilerContext
{
public:
CompilerContext(CompilerContext* _runtimeContext = nullptr) :
CompilerContext(CompilerContext* _runtimeContext = nullptr):
m_asm(std::make_shared<eth::Assembly>()),
m_runtimeContext(_runtimeContext)
{
if (m_runtimeContext)
m_runtimeSub = registerSubroutine(m_runtimeContext->assembly());
m_runtimeSub = size_t(m_asm->newSub(m_runtimeContext->m_asm).data());
}
void addMagicGlobal(MagicVariableDeclaration const& _declaration);
@@ -59,9 +60,9 @@ public:
void setCompiledContracts(std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts) { m_compiledContracts = _contracts; }
eth::Assembly const& compiledContract(ContractDefinition const& _contract) const;
void setStackOffset(int _offset) { m_asm.setDeposit(_offset); }
void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); }
unsigned stackHeight() const { solAssert(m_asm.deposit() >= 0, ""); return unsigned(m_asm.deposit()); }
void setStackOffset(int _offset) { m_asm->setDeposit(_offset); }
void adjustStackOffset(int _adjustment) { m_asm->adjustDeposit(_adjustment); }
unsigned stackHeight() const { solAssert(m_asm->deposit() >= 0, ""); return unsigned(m_asm->deposit()); }
bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration) != 0; }
bool isLocalVariable(Declaration const* _declaration) const;
@@ -102,34 +103,33 @@ public:
std::pair<u256, unsigned> storageLocationOfVariable(Declaration const& _declaration) const;
/// Appends a JUMPI instruction to a new tag and @returns the tag
eth::AssemblyItem appendConditionalJump() { return m_asm.appendJumpI().tag(); }
eth::AssemblyItem appendConditionalJump() { return m_asm->appendJumpI().tag(); }
/// Appends a JUMPI instruction to @a _tag
CompilerContext& appendConditionalJumpTo(eth::AssemblyItem const& _tag) { m_asm.appendJumpI(_tag); return *this; }
CompilerContext& appendConditionalJumpTo(eth::AssemblyItem const& _tag) { m_asm->appendJumpI(_tag); return *this; }
/// Appends a JUMP to a new tag and @returns the tag
eth::AssemblyItem appendJumpToNew() { return m_asm.appendJump().tag(); }
eth::AssemblyItem appendJumpToNew() { return m_asm->appendJump().tag(); }
/// Appends a JUMP to a tag already on the stack
CompilerContext& appendJump(eth::AssemblyItem::JumpType _jumpType = eth::AssemblyItem::JumpType::Ordinary);
/// Returns an "ErrorTag"
eth::AssemblyItem errorTag() { return m_asm.errorTag(); }
eth::AssemblyItem errorTag() { return m_asm->errorTag(); }
/// Appends a JUMP to a specific tag
CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm.appendJump(_tag); return *this; }
CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm->appendJump(_tag); return *this; }
/// Appends pushing of a new tag and @returns the new tag.
eth::AssemblyItem pushNewTag() { return m_asm.append(m_asm.newPushTag()).tag(); }
eth::AssemblyItem pushNewTag() { return m_asm->append(m_asm->newPushTag()).tag(); }
/// @returns a new tag without pushing any opcodes or data
eth::AssemblyItem newTag() { return m_asm.newTag(); }
/// Adds a subroutine to the code (in the data section)
/// @returns the assembly item corresponding to the pushed subroutine, i.e. its offset in the list.
size_t registerSubroutine(eth::Assembly const& _assembly) { return size_t(m_asm.newSub(_assembly).data()); }
eth::AssemblyItem newTag() { return m_asm->newTag(); }
/// Adds a subroutine to the code (in the data section) and pushes its size (via a tag)
/// on the stack. @returns the pushsub assembly item.
eth::AssemblyItem addSubroutine(eth::Assembly const& _assembly) { auto sub = m_asm.newSub(_assembly); m_asm.append(m_asm.newPushSubSize(size_t(sub.data()))); return sub; }
void appendSubroutineSize(size_t const& _subRoutine) { m_asm.append(m_asm.newPushSubSize(_subRoutine)); }
eth::AssemblyItem addSubroutine(eth::AssemblyPointer const& _assembly) { auto sub = m_asm->newSub(_assembly); m_asm->append(m_asm->newPushSubSize(size_t(sub.data()))); return sub; }
void pushSubroutineSize(size_t _subRoutine) { m_asm->append(m_asm->newPushSubSize(_subRoutine)); }
/// Pushes the offset of the subroutine.
void pushSubroutineOffset(size_t _subRoutine) { m_asm->append(eth::AssemblyItem(eth::PushSub, _subRoutine)); }
/// Pushes the size of the final program
void appendProgramSize() { m_asm.appendProgramSize(); }
void appendProgramSize() { m_asm->appendProgramSize(); }
/// Adds data to the data section, pushes a reference to the stack
eth::AssemblyItem appendData(bytes const& _data) { return m_asm.append(_data); }
eth::AssemblyItem appendData(bytes const& _data) { return m_asm->append(_data); }
/// Appends the address (virtual, will be filled in by linker) of a library.
void appendLibraryAddress(std::string const& _identifier) { m_asm.appendLibraryAddress(_identifier); }
void appendLibraryAddress(std::string const& _identifier) { m_asm->appendLibraryAddress(_identifier); }
/// Resets the stack of visited nodes with a new stack having only @c _node
void resetVisitedNodes(ASTNode const* _node);
/// Pops the stack of visited nodes
@@ -138,10 +138,10 @@ public:
void pushVisitedNodes(ASTNode const* _node) { m_visitedNodes.push(_node); updateSourceLocation(); }
/// Append elements to the current instruction list and adjust @a m_stackOffset.
CompilerContext& operator<<(eth::AssemblyItem const& _item) { m_asm.append(_item); return *this; }
CompilerContext& operator<<(Instruction _instruction) { m_asm.append(_instruction); return *this; }
CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; }
CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); return *this; }
CompilerContext& operator<<(eth::AssemblyItem const& _item) { m_asm->append(_item); return *this; }
CompilerContext& operator<<(Instruction _instruction) { m_asm->append(_instruction); return *this; }
CompilerContext& operator<<(u256 const& _value) { m_asm->append(_value); return *this; }
CompilerContext& operator<<(bytes const& _data) { m_asm->append(_data); return *this; }
/// Appends inline assembly. @a _replacements are string-matching replacements that are performed
/// prior to parsing the inline assembly.
@@ -155,27 +155,27 @@ public:
/// Prepends "PUSH <compiler version number> POP"
void injectVersionStampIntoSub(size_t _subIndex);
void optimise(unsigned _runs = 200) { m_asm.optimise(true, true, _runs); }
void optimise(unsigned _runs = 200) { m_asm->optimise(true, true, _runs); }
/// @returns the runtime context if in creation mode and runtime context is set, nullptr otherwise.
CompilerContext* runtimeContext() { return m_runtimeContext; }
/// @returns the identifier of the runtime subroutine.
size_t runtimeSub() const { return m_runtimeSub; }
eth::Assembly const& assembly() const { return m_asm; }
eth::Assembly const& assembly() const { return *m_asm; }
/// @returns non-const reference to the underlying assembly. Should be avoided in favour of
/// wrappers in this class.
eth::Assembly& nonConstAssembly() { return m_asm; }
eth::Assembly& nonConstAssembly() { return *m_asm; }
/// @arg _sourceCodes is the map of input files to source code strings
/// @arg _inJsonFormat shows whether the out should be in Json format
Json::Value streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const
{
return m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat);
return m_asm->stream(_stream, "", _sourceCodes, _inJsonFormat);
}
eth::LinkerObject const& assembledObject() { return m_asm.assemble(); }
eth::LinkerObject const& assembledRuntimeObject(size_t _subIndex) { return m_asm.sub(_subIndex).assemble(); }
eth::LinkerObject const& assembledObject() { return m_asm->assemble(); }
eth::LinkerObject const& assembledRuntimeObject(size_t _subIndex) { return m_asm->sub(_subIndex).assemble(); }
/**
* Helper class to pop the visited nodes stack when a scope closes
@@ -231,7 +231,7 @@ private:
mutable std::queue<Declaration const*> m_functionsToCompile;
} m_functionCompilationQueue;
eth::Assembly m_asm;
eth::AssemblyPointer m_asm;
/// Magic global variables like msg, tx or this, distinguished by type.
std::set<Declaration const*> m_magicGlobals;
/// Other already compiled contracts to be used in contract creation calls.
+7 -8
View File
@@ -79,7 +79,7 @@ size_t ContractCompiler::compileClone(
appendInitAndConstructorCode(_contract);
//@todo determine largest return size of all runtime functions
eth::AssemblyItem runtimeSub = m_context.addSubroutine(cloneRuntime());
auto runtimeSub = m_context.addSubroutine(cloneRuntime());
// stack contains sub size
m_context << Instruction::DUP1 << runtimeSub << u256(0) << Instruction::CODECOPY;
@@ -87,7 +87,6 @@ size_t ContractCompiler::compileClone(
appendMissingFunctions();
solAssert(runtimeSub.data() < numeric_limits<size_t>::max(), "");
return size_t(runtimeSub.data());
}
@@ -158,10 +157,10 @@ size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _cont
m_context << deployRoutine;
solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered");
m_context.appendSubroutineSize(m_context.runtimeSub());
// stack contains sub size
m_context << Instruction::DUP1 << m_context.runtimeSub() << u256(0) << Instruction::CODECOPY;
m_context.pushSubroutineSize(m_context.runtimeSub());
m_context << Instruction::DUP1;
m_context.pushSubroutineOffset(m_context.runtimeSub());
m_context << u256(0) << Instruction::CODECOPY;
m_context << u256(0) << Instruction::RETURN;
return m_context.runtimeSub();
@@ -893,7 +892,7 @@ void ContractCompiler::compileExpression(Expression const& _expression, TypePoin
CompilerUtils(m_context).convertType(*_expression.annotation().type, *_targetType);
}
eth::Assembly ContractCompiler::cloneRuntime()
eth::AssemblyPointer ContractCompiler::cloneRuntime()
{
eth::Assembly a;
a << Instruction::CALLDATASIZE;
@@ -911,5 +910,5 @@ eth::Assembly ContractCompiler::cloneRuntime()
a.appendJumpI(a.errorTag());
//@todo adjust for larger return values, make this dynamic.
a << u256(0x20) << u256(0) << Instruction::RETURN;
return a;
return make_shared<eth::Assembly>(a);
}
+1 -1
View File
@@ -114,7 +114,7 @@ private:
void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer());
/// @returns the runtime assembly for clone contracts.
static eth::Assembly cloneRuntime();
static eth::AssemblyPointer cloneRuntime();
bool const m_optimise;
/// Pointer to the runtime compiler in case this is a creation compiler.
+4 -1
View File
@@ -528,8 +528,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
// copy the contract's code into memory
eth::Assembly const& assembly = m_context.compiledContract(contract);
utils().fetchFreeMemoryPointer();
// TODO we create a copy here, which is actually what we want.
// This should be revisited at the point where we fix
// https://github.com/ethereum/solidity/issues/1092
// pushes size
eth::AssemblyItem subroutine = m_context.addSubroutine(assembly);
auto subroutine = m_context.addSubroutine(make_shared<eth::Assembly>(assembly));
m_context << Instruction::DUP1 << subroutine;
m_context << Instruction::DUP4 << Instruction::CODECOPY;