mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Converted sub assembly to smart pointer.
This commit is contained in:
parent
e543bd34c0
commit
e51f852504
@ -75,17 +75,17 @@ string Assembly::out() const
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
unsigned Assembly::bytesRequired() const
|
||||
unsigned Assembly::bytesRequired(unsigned subTagSize) const
|
||||
{
|
||||
for (unsigned br = 1;; ++br)
|
||||
for (unsigned tagSize = subTagSize;; ++tagSize)
|
||||
{
|
||||
unsigned ret = 1;
|
||||
for (auto const& i: m_data)
|
||||
ret += i.second.size();
|
||||
|
||||
for (AssemblyItem const& i: m_items)
|
||||
ret += i.bytesRequired(br);
|
||||
if (dev::bytesRequired(ret) <= br)
|
||||
ret += i.bytesRequired(tagSize);
|
||||
if (dev::bytesRequired(ret) <= tagSize)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -132,13 +132,19 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con
|
||||
if (i.data() == 0)
|
||||
_out << " PUSH [ErrorTag]";
|
||||
else
|
||||
_out << " PUSH [tag" << dec << i.data() << "]";
|
||||
{
|
||||
size_t subId = i.splitForeignPushTag().first;
|
||||
if (subId == size_t(-1))
|
||||
_out << " PUSH [tag" << dec << i.splitForeignPushTag().second << "]";
|
||||
else
|
||||
_out << " PUSH [tag" << dec << subId << ":" << i.splitForeignPushTag().second << "]";
|
||||
}
|
||||
break;
|
||||
case PushSub:
|
||||
_out << " PUSH [$" << h256(i.data()).abridgedMiddle() << "]";
|
||||
_out << " PUSH [$" << size_t(i.data()) << "]";
|
||||
break;
|
||||
case PushSubSize:
|
||||
_out << " PUSH #[$" << h256(i.data()).abridgedMiddle() << "]";
|
||||
_out << " PUSH #[$" << size_t(i.data()) << "]";
|
||||
break;
|
||||
case PushProgramSize:
|
||||
_out << " PUSHSIZE";
|
||||
@ -167,7 +173,7 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con
|
||||
for (size_t i = 0; i < m_subs.size(); ++i)
|
||||
{
|
||||
_out << _prefix << " " << hex << i << ": " << endl;
|
||||
m_subs[i].stream(_out, _prefix + " ", _sourceCodes);
|
||||
m_subs[i]->stream(_out, _prefix + " ", _sourceCodes);
|
||||
}
|
||||
}
|
||||
return _out;
|
||||
@ -266,7 +272,7 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes
|
||||
{
|
||||
std::stringstream hexStr;
|
||||
hexStr << hex << i;
|
||||
data[hexStr.str()] = m_subs[i].stream(_out, "", _sourceCodes, true);
|
||||
data[hexStr.str()] = m_subs[i]->stream(_out, "", _sourceCodes, true);
|
||||
}
|
||||
root[".data"] = data;
|
||||
_out << root;
|
||||
@ -317,7 +323,7 @@ map<u256, u256> Assembly::optimiseInternal(bool _isCreation, size_t _runs)
|
||||
{
|
||||
for (size_t subId = 0; subId < m_subs.size(); ++subId)
|
||||
{
|
||||
map<u256, u256> subTagReplacements = m_subs[subId].optimiseInternal(false, _runs);
|
||||
map<u256, u256> subTagReplacements = m_subs[subId]->optimiseInternal(false, _runs);
|
||||
BlockDeduplicator::applyTagReplacement(m_items, subTagReplacements, subId);
|
||||
}
|
||||
|
||||
@ -385,7 +391,11 @@ map<u256, u256> Assembly::optimiseInternal(bool _isCreation, size_t _runs)
|
||||
}
|
||||
iter = end;
|
||||
}
|
||||
|
||||
if (optimisedItems.size() < m_items.size())
|
||||
{
|
||||
m_items = move(optimisedItems);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,20 +414,28 @@ LinkerObject const& Assembly::assemble() const
|
||||
if (!m_assembledObject.bytecode.empty())
|
||||
return m_assembledObject;
|
||||
|
||||
size_t subTagSize = 1;
|
||||
for (auto const& sub: m_subs)
|
||||
{
|
||||
sub->assemble();
|
||||
if (!sub->m_tagPositionsInBytecode.empty())
|
||||
subTagSize = max(subTagSize, *max_element(sub->m_tagPositionsInBytecode.begin(), sub->m_tagPositionsInBytecode.end()));
|
||||
}
|
||||
|
||||
LinkerObject& ret = m_assembledObject;
|
||||
|
||||
unsigned totalBytes = bytesRequired();
|
||||
size_t bytesRequiredForCode = bytesRequired(subTagSize);
|
||||
m_tagPositionsInBytecode = vector<size_t>(m_usedTags, -1);
|
||||
map<size_t, pair<size_t, size_t>> tagRef;
|
||||
multimap<h256, unsigned> dataRef;
|
||||
multimap<size_t, size_t> subRef;
|
||||
vector<unsigned> sizeRef; ///< Pointers to code locations where the size of the program is inserted
|
||||
unsigned bytesPerTag = dev::bytesRequired(totalBytes);
|
||||
unsigned bytesPerTag = dev::bytesRequired(bytesRequiredForCode);
|
||||
byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag;
|
||||
|
||||
unsigned bytesRequiredIncludingData = bytesRequired();
|
||||
unsigned bytesRequiredIncludingData = bytesRequiredForCode + 1;
|
||||
for (auto const& sub: m_subs)
|
||||
bytesRequiredIncludingData += sub.assemble().bytecode.size();
|
||||
bytesRequiredIncludingData += sub->assemble().bytecode.size();
|
||||
|
||||
unsigned bytesPerDataRef = dev::bytesRequired(bytesRequiredIncludingData);
|
||||
byte dataRefPush = (byte)Instruction::PUSH1 - 1 + bytesPerDataRef;
|
||||
@ -475,7 +493,7 @@ LinkerObject const& Assembly::assemble() const
|
||||
break;
|
||||
case PushSubSize:
|
||||
{
|
||||
auto s = m_subs.at(size_t(i.data())).assemble().bytecode.size();
|
||||
auto s = m_subs.at(size_t(i.data()))->assemble().bytecode.size();
|
||||
i.setPushedValue(u256(s));
|
||||
byte b = max<unsigned>(1, dev::bytesRequired(s));
|
||||
ret.bytecode.push_back((byte)Instruction::PUSH1 - 1 + b);
|
||||
@ -520,7 +538,7 @@ LinkerObject const& Assembly::assemble() const
|
||||
bytesRef r(ret.bytecode.data() + ref->second, bytesPerDataRef);
|
||||
toBigEndian(ret.bytecode.size(), r);
|
||||
}
|
||||
ret.append(m_subs[i].assemble());
|
||||
ret.append(m_subs[i]->assemble());
|
||||
}
|
||||
for (auto const& i: tagRef)
|
||||
{
|
||||
@ -531,7 +549,7 @@ LinkerObject const& Assembly::assemble() const
|
||||
std::vector<size_t> const& tagPositions =
|
||||
subId == size_t(-1) ?
|
||||
m_tagPositionsInBytecode :
|
||||
m_subs[subId].m_tagPositionsInBytecode;
|
||||
m_subs[subId]->m_tagPositionsInBytecode;
|
||||
assertThrow(tagId < tagPositions.size(), AssemblyException, "Reference to non-existing tag.");
|
||||
size_t pos = tagPositions[tagId];
|
||||
assertThrow(pos != size_t(-1), AssemblyException, "Reference to tag without position.");
|
||||
|
@ -14,30 +14,32 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file Assembly.h
|
||||
* @author Gav Wood <i@gavwood.com>
|
||||
* @date 2014
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <libdevcore/Common.h>
|
||||
#include <libdevcore/Assertions.h>
|
||||
#include <libdevcore/SHA3.h>
|
||||
#include <libevmasm/Instruction.h>
|
||||
#include <libevmasm/SourceLocation.h>
|
||||
#include <libevmasm/AssemblyItem.h>
|
||||
#include <libevmasm/LinkerObject.h>
|
||||
#include "Exceptions.h"
|
||||
#include <libevmasm/Exceptions.h>
|
||||
|
||||
#include <libdevcore/Common.h>
|
||||
#include <libdevcore/Assertions.h>
|
||||
#include <libdevcore/SHA3.h>
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace eth
|
||||
{
|
||||
|
||||
using AssemblyPointer = std::shared_ptr<Assembly>;
|
||||
|
||||
class Assembly
|
||||
{
|
||||
public:
|
||||
@ -46,9 +48,9 @@ public:
|
||||
AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); }
|
||||
AssemblyItem newPushTag() { return AssemblyItem(PushTag, m_usedTags++); }
|
||||
AssemblyItem newData(bytes const& _data) { h256 h(dev::keccak256(asString(_data))); m_data[h] = _data; return AssemblyItem(PushData, h); }
|
||||
AssemblyItem newSub(Assembly const& _sub) { m_subs.push_back(_sub); return AssemblyItem(PushSub, m_subs.size() - 1); }
|
||||
Assembly const& sub(size_t _sub) const { return m_subs.at(_sub); }
|
||||
Assembly& sub(size_t _sub) { return m_subs.at(_sub); }
|
||||
AssemblyItem newSub(AssemblyPointer const& _sub) { m_subs.push_back(_sub); return AssemblyItem(PushSub, m_subs.size() - 1); }
|
||||
Assembly const& sub(size_t _sub) const { return *m_subs.at(_sub); }
|
||||
Assembly& sub(size_t _sub) { return *m_subs.at(_sub); }
|
||||
AssemblyItem newPushString(std::string const& _data) { h256 h(dev::keccak256(_data)); m_strings[h] = _data; return AssemblyItem(PushString, h); }
|
||||
AssemblyItem newPushSubSize(u256 const& _subId) { return AssemblyItem(PushSubSize, _subId); }
|
||||
AssemblyItem newPushLibraryAddress(std::string const& _identifier);
|
||||
@ -58,7 +60,6 @@ public:
|
||||
AssemblyItem const& append(AssemblyItem const& _i);
|
||||
AssemblyItem const& append(std::string const& _data) { return append(newPushString(_data)); }
|
||||
AssemblyItem const& append(bytes const& _data) { return append(newData(_data)); }
|
||||
AssemblyItem appendSubSize(Assembly const& _a) { auto ret = newSub(_a); append(newPushSubSize(ret.data())); return ret; }
|
||||
/// Pushes the final size of the current assembly itself. Use this when the code is modified
|
||||
/// after compilation and CODESIZE is not an option.
|
||||
void appendProgramSize() { append(AssemblyItem(PushProgramSize)); }
|
||||
@ -115,7 +116,7 @@ protected:
|
||||
|
||||
std::string locationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) const;
|
||||
void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) BOOST_THROW_EXCEPTION(InvalidDeposit()); }
|
||||
unsigned bytesRequired() const;
|
||||
unsigned bytesRequired(unsigned subTagSize) const;
|
||||
|
||||
private:
|
||||
Json::Value streamAsmJson(std::ostream& _out, StringMap const& _sourceCodes) const;
|
||||
@ -127,7 +128,7 @@ protected:
|
||||
unsigned m_usedTags = 1;
|
||||
AssemblyItems m_items;
|
||||
std::map<h256, bytes> m_data;
|
||||
std::vector<Assembly> m_subs;
|
||||
std::vector<std::shared_ptr<Assembly>> m_subs;
|
||||
std::map<h256, std::string> m_strings;
|
||||
std::map<h256, std::string> m_libraries; ///< Identifiers of libraries to be linked.
|
||||
|
||||
|
@ -127,8 +127,14 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItem const& _item)
|
||||
_out << " PushString" << hex << (unsigned)_item.data();
|
||||
break;
|
||||
case PushTag:
|
||||
_out << " PushTag " << _item.data();
|
||||
{
|
||||
size_t subId = _item.splitForeignPushTag().first;
|
||||
if (subId == size_t(-1))
|
||||
_out << " PushTag " << _item.splitForeignPushTag().second;
|
||||
else
|
||||
_out << " PushTag " << subId << ":" << _item.splitForeignPushTag().second;
|
||||
break;
|
||||
}
|
||||
case Tag:
|
||||
_out << " Tag " << _item.data();
|
||||
break;
|
||||
@ -136,10 +142,10 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItem const& _item)
|
||||
_out << " PushData " << hex << (unsigned)_item.data();
|
||||
break;
|
||||
case PushSub:
|
||||
_out << " PushSub " << hex << h256(_item.data()).abridgedMiddle();
|
||||
_out << " PushSub " << hex << size_t(_item.data());
|
||||
break;
|
||||
case PushSubSize:
|
||||
_out << " PushSubSize " << hex << h256(_item.data()).abridgedMiddle();
|
||||
_out << " PushSubSize " << hex << size_t(_item.data());
|
||||
break;
|
||||
case PushProgramSize:
|
||||
_out << " PushProgramSize";
|
||||
|
@ -520,7 +520,8 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
|
||||
requireMaxSize(3);
|
||||
requireDeposit(1, 1);
|
||||
|
||||
auto subPush = m_asm.appendSubSize(code[0].assembly(ns));
|
||||
auto subPush = m_asm.newSub(make_shared<Assembly>(code[0].assembly(ns)));
|
||||
m_asm.append(m_asm.newPushSubSize(subPush.data()));
|
||||
m_asm.append(Instruction::DUP1);
|
||||
if (code.size() == 3)
|
||||
{
|
||||
|
@ -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(
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -7757,7 +7757,7 @@ BOOST_AUTO_TEST_CASE(store_function_in_constructor)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract C {
|
||||
uint result_in_constructor;
|
||||
uint public result_in_constructor;
|
||||
function (uint) internal returns (uint) x;
|
||||
function C () {
|
||||
x = double;
|
||||
|
@ -1238,6 +1238,24 @@ BOOST_AUTO_TEST_CASE(inconsistency)
|
||||
compareVersions("trigger()");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dead_code_elimination_across_assemblies)
|
||||
{
|
||||
// This tests that a runtime-function that is stored in storage in the constructor
|
||||
// is not removed as part of dead code elimination.
|
||||
char const* sourceCode = R"(
|
||||
contract DCE {
|
||||
function () internal returns (uint) stored;
|
||||
function DCE() {
|
||||
stored = f;
|
||||
}
|
||||
function f() internal returns (uint) { return 7; }
|
||||
function test() returns (uint) { return stored(); }
|
||||
}
|
||||
)";
|
||||
compileBothVersions(sourceCode);
|
||||
compareVersions("test()");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user