From 4bde0a2d36297c4b3fa17c7dac2bb1681e1e7f75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 20 Oct 2016 11:58:25 +0200 Subject: Build jsoncpp from source using jsoncpp.cmake script --- libevmasm/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'libevmasm') diff --git a/libevmasm/CMakeLists.txt b/libevmasm/CMakeLists.txt index 14800f41..9cc3e93e 100644 --- a/libevmasm/CMakeLists.txt +++ b/libevmasm/CMakeLists.txt @@ -8,6 +8,7 @@ file(GLOB HEADERS "*.h") include_directories(BEFORE ..) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) -eth_use(${EXECUTABLE} REQUIRED Jsoncpp Dev::soldevcore) +eth_use(${EXECUTABLE} REQUIRED Dev::soldevcore) +target_link_libraries(${EXECUTABLE} jsoncpp) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) -- cgit v1.2.3 From 2e929666845300217f3725f67e48cd04a567a6f2 Mon Sep 17 00:00:00 2001 From: Yoichi Hirai Date: Mon, 7 Nov 2016 14:12:30 +0100 Subject: libevmasm: fix comparison of SourceLocations --- libevmasm/SourceLocation.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'libevmasm') diff --git a/libevmasm/SourceLocation.h b/libevmasm/SourceLocation.h index 05304d14..b8f073bb 100644 --- a/libevmasm/SourceLocation.h +++ b/libevmasm/SourceLocation.h @@ -55,7 +55,11 @@ struct SourceLocation return *this; } - bool operator==(SourceLocation const& _other) const { return start == _other.start && end == _other.end;} + bool operator==(SourceLocation const& _other) const + { + return start == _other.start && end == _other.end && + ((!sourceName && !_other.sourceName) || (sourceName && _other.sourceName && *sourceName == *_other.sourceName)); + } bool operator!=(SourceLocation const& _other) const { return !operator==(_other); } inline bool operator<(SourceLocation const& _other) const; inline bool contains(SourceLocation const& _other) const; @@ -79,20 +83,21 @@ inline std::ostream& operator<<(std::ostream& _out, SourceLocation const& _locat bool SourceLocation::operator<(SourceLocation const& _other) const { if (!sourceName || !_other.sourceName) - return int(!!sourceName) < int(!!_other.sourceName); - return make_tuple(*sourceName, start, end) < make_tuple(*_other.sourceName, _other.start, _other.end); + return std::make_tuple(int(!!sourceName), start, end) < std::make_tuple(int(!!_other.sourceName), _other.start, _other.end); + else + return std::make_tuple(*sourceName, start, end) < std::make_tuple(*_other.sourceName, _other.start, _other.end); } bool SourceLocation::contains(SourceLocation const& _other) const { - if (isEmpty() || _other.isEmpty() || !sourceName || !_other.sourceName || *sourceName != *_other.sourceName) + if (isEmpty() || _other.isEmpty() || ((!sourceName || !_other.sourceName || *sourceName != *_other.sourceName) && (sourceName || _other.sourceName))) return false; return start <= _other.start && _other.end <= end; } bool SourceLocation::intersects(SourceLocation const& _other) const { - if (isEmpty() || _other.isEmpty() || !sourceName || !_other.sourceName || *sourceName != *_other.sourceName) + if (isEmpty() || _other.isEmpty() || ((!sourceName || !_other.sourceName || *sourceName != *_other.sourceName) && (sourceName || _other.sourceName))) return false; return _other.start < end && start < _other.end; } -- cgit v1.2.3 From c2c39239d6f1d51addad97c0c5128983ef58011f Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 14 Nov 2016 16:02:57 +0100 Subject: Report infinite gas for calls. --- libevmasm/GasMeter.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'libevmasm') diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp index 51f3cf1d..51dc34f4 100644 --- a/libevmasm/GasMeter.cpp +++ b/libevmasm/GasMeter.cpp @@ -128,24 +128,28 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item) case Instruction::CALLCODE: case Instruction::DELEGATECALL: { - gas = GasCosts::callGas; - if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(0))) - gas += (*value); - else - gas = GasConsumption::infinite(); - if (_item.instruction() == Instruction::CALL) - gas += GasCosts::callNewAccountGas; // We very rarely know whether the address exists. - int valueSize = _item.instruction() == Instruction::DELEGATECALL ? 0 : 1; - if (!classes.knownZero(m_state->relativeStackElement(-1 - valueSize))) - gas += GasCosts::callValueTransferGas; - gas += memoryGas(-2 - valueSize, -3 - valueSize); - gas += memoryGas(-4 - valueSize, -5 - valueSize); +// We assume that we do not know the target contract and thus, the consumption is infinite. + gas = GasConsumption::infinite(); +// gas = GasCosts::callGas; +// if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(0))) +// gas += (*value); +// else +// gas = GasConsumption::infinite(); +// if (_item.instruction() == Instruction::CALL) +// gas += GasCosts::callNewAccountGas; // We very rarely know whether the address exists. +// int valueSize = _item.instruction() == Instruction::DELEGATECALL ? 0 : 1; +// if (!classes.knownZero(m_state->relativeStackElement(-1 - valueSize))) +// gas += GasCosts::callValueTransferGas; +// gas += memoryGas(-2 - valueSize, -3 - valueSize); +// gas += memoryGas(-4 - valueSize, -5 - valueSize); break; } case Instruction::CREATE: - gas = GasCosts::createGas; - gas += memoryGas(-1, -2); - break; +// We assume that we do not know the target contract and thus, the consumption is infinite. +// gas = GasConsumption::infinite(); +// gas = GasCosts::createGas; +// gas += memoryGas(-1, -2); +// break; case Instruction::EXP: gas = GasCosts::expGas; if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1))) -- cgit v1.2.3 From bf5b0dc2d27a3c4139894daf627cf63b8cfb1864 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 14 Nov 2016 23:28:26 +0100 Subject: Keep old code. --- libevmasm/GasMeter.cpp | 48 ++++++++++++++++++++++++++++-------------------- libevmasm/GasMeter.h | 3 ++- 2 files changed, 30 insertions(+), 21 deletions(-) (limited to 'libevmasm') diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp index 51dc34f4..da8b41e3 100644 --- a/libevmasm/GasMeter.cpp +++ b/libevmasm/GasMeter.cpp @@ -39,7 +39,7 @@ GasMeter::GasConsumption& GasMeter::GasConsumption::operator+=(GasConsumption co return *this; } -GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item) +GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _includeExternalCosts) { GasConsumption gas; switch (_item.type()) @@ -128,28 +128,36 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item) case Instruction::CALLCODE: case Instruction::DELEGATECALL: { -// We assume that we do not know the target contract and thus, the consumption is infinite. - gas = GasConsumption::infinite(); -// gas = GasCosts::callGas; -// if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(0))) -// gas += (*value); -// else -// gas = GasConsumption::infinite(); -// if (_item.instruction() == Instruction::CALL) -// gas += GasCosts::callNewAccountGas; // We very rarely know whether the address exists. -// int valueSize = _item.instruction() == Instruction::DELEGATECALL ? 0 : 1; -// if (!classes.knownZero(m_state->relativeStackElement(-1 - valueSize))) -// gas += GasCosts::callValueTransferGas; -// gas += memoryGas(-2 - valueSize, -3 - valueSize); -// gas += memoryGas(-4 - valueSize, -5 - valueSize); + if (_includeExternalCosts) + // We assume that we do not know the target contract and thus, the consumption is infinite. + gas = GasConsumption::infinite(); + else + { + gas = GasCosts::callGas; + if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(0))) + gas += (*value); + else + gas = GasConsumption::infinite(); + if (_item.instruction() == Instruction::CALL) + gas += GasCosts::callNewAccountGas; // We very rarely know whether the address exists. + int valueSize = _item.instruction() == Instruction::DELEGATECALL ? 0 : 1; + if (!classes.knownZero(m_state->relativeStackElement(-1 - valueSize))) + gas += GasCosts::callValueTransferGas; + gas += memoryGas(-2 - valueSize, -3 - valueSize); + gas += memoryGas(-4 - valueSize, -5 - valueSize); + } break; } case Instruction::CREATE: -// We assume that we do not know the target contract and thus, the consumption is infinite. -// gas = GasConsumption::infinite(); -// gas = GasCosts::createGas; -// gas += memoryGas(-1, -2); -// break; + if (_includeExternalCosts) + // We assume that we do not know the target contract and thus, the consumption is infinite. + gas = GasConsumption::infinite(); + else + { + gas = GasCosts::createGas; + gas += memoryGas(-1, -2); + } + break; case Instruction::EXP: gas = GasCosts::expGas; if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1))) diff --git a/libevmasm/GasMeter.h b/libevmasm/GasMeter.h index 1a607a9f..ff127909 100644 --- a/libevmasm/GasMeter.h +++ b/libevmasm/GasMeter.h @@ -102,7 +102,8 @@ public: /// @returns an upper bound on the gas consumed by the given instruction and updates /// the state. - GasConsumption estimateMax(AssemblyItem const& _item); + /// @param _inculdeExternalCosts if true, include costs caused by other contracts in calls. + GasConsumption estimateMax(AssemblyItem const& _item, bool _includeExternalCosts = true); u256 const& largestMemoryAccess() const { return m_largestMemoryAccess; } -- cgit v1.2.3 From 47794c1da406a28f0e8a10e3e57cd935f5cc7f3d Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 7 Nov 2016 20:08:05 +0100 Subject: Implement uninitialized storage functions. --- libevmasm/Assembly.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'libevmasm') diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index e881c1e2..e19b6b0d 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -485,6 +485,7 @@ LinkerObject const& Assembly::assemble() const break; case Tag: tagPos[(unsigned)i.data()] = ret.bytecode.size(); + assertThrow(ret.bytecode.size() < 0xffffffffL, AssemblyException, "Tag too large."); assertThrow(i.data() != 0, AssemblyException, ""); ret.bytecode.push_back((byte)Instruction::JUMPDEST); break; -- cgit v1.2.3 From e543bd34c0b4884b5a27555f698f50af6a1c0b81 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 10 Nov 2016 18:16:21 +0100 Subject: Stored combined creation and runtime tags. Includes a change to Assembly to allow tags from sub-assemblies to be used. Sorry, this get a bit bigger than I thought. --- libevmasm/Assembly.cpp | 102 ++++++++++++++++++++++++---------------- libevmasm/Assembly.h | 6 ++- libevmasm/AssemblyItem.cpp | 23 +++++++++ libevmasm/AssemblyItem.h | 8 ++++ libevmasm/BlockDeduplicator.cpp | 37 +++++++++++---- libevmasm/BlockDeduplicator.h | 16 +++++++ libevmasm/ControlFlowGraph.h | 5 ++ 7 files changed, 145 insertions(+), 52 deletions(-) (limited to 'libevmasm') diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index e19b6b0d..23a8180b 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -308,9 +308,20 @@ void Assembly::injectStart(AssemblyItem const& _i) Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs) { - if (!_enable) - return *this; + if (_enable) + optimiseInternal(_isCreation, _runs); + return *this; +} +map Assembly::optimiseInternal(bool _isCreation, size_t _runs) +{ + for (size_t subId = 0; subId < m_subs.size(); ++subId) + { + map subTagReplacements = m_subs[subId].optimiseInternal(false, _runs); + BlockDeduplicator::applyTagReplacement(m_items, subTagReplacements, subId); + } + + map tagReplacements; unsigned total = 0; for (unsigned count = 1; count > 0; total += count) { @@ -319,30 +330,39 @@ Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs) // This only modifies PushTags, we have to run again to actually remove code. BlockDeduplicator dedup(m_items); if (dedup.deduplicate()) + { + tagReplacements.insert(dedup.replacedTags().begin(), dedup.replacedTags().end()); count++; + } { - // Control flow graph that resets knowledge at path joins. - ControlFlowGraph cfg(m_items, false); + // Control flow graph optimization has been here before but is disabled because it + // assumes we only jump to tags that are pushed. This is not the case anymore with + // function types that can be stored in storage. AssemblyItems optimisedItems; - for (BasicBlock const& block: cfg.optimisedBlocks()) + + auto iter = m_items.begin(); + while (iter != m_items.end()) { - // We used to start with the block's initial state but it caused - // too many inconsistencies. + auto end = iter; + while (end != m_items.end()) + if (SemanticInformation::altersControlFlow(*end++)) + break; + KnownState emptyState; CommonSubexpressionEliminator eliminator(emptyState); - auto iter = m_items.begin() + block.begin; - auto const end = m_items.begin() + block.end; - while (iter < end) + auto blockIter = iter; + auto const blockEnd = end; + while (blockIter < blockEnd) { - auto orig = iter; - iter = eliminator.feedItems(iter, end); + auto orig = blockIter; + blockIter = eliminator.feedItems(blockIter, blockEnd); bool shouldReplace = false; AssemblyItems optimisedChunk; try { optimisedChunk = eliminator.getOptimizedItems(); - shouldReplace = (optimisedChunk.size() < size_t(iter - orig)); + shouldReplace = (optimisedChunk.size() < size_t(blockIter - orig)); } catch (StackTooDeepException const&) { @@ -361,15 +381,11 @@ Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs) optimisedItems += optimisedChunk; } else - copy(orig, iter, back_inserter(optimisedItems)); + copy(orig, blockIter, back_inserter(optimisedItems)); } + iter = end; } - if (optimisedItems.size() < m_items.size()) - { - m_items = move(optimisedItems); - count++; - } } } @@ -380,10 +396,7 @@ Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs) m_items ); - for (auto& sub: m_subs) - sub.optimise(true, false, _runs); - - return *this; + return tagReplacements; } LinkerObject const& Assembly::assemble() const @@ -394,8 +407,8 @@ LinkerObject const& Assembly::assemble() const LinkerObject& ret = m_assembledObject; unsigned totalBytes = bytesRequired(); - vector tagPos(m_usedTags); - map tagRef; + m_tagPositionsInBytecode = vector(m_usedTags, -1); + map> tagRef; multimap dataRef; multimap subRef; vector sizeRef; ///< Pointers to code locations where the size of the program is inserted @@ -413,8 +426,8 @@ LinkerObject const& Assembly::assemble() const for (AssemblyItem const& i: m_items) { // store position of the invalid jump destination - if (i.type() != Tag && tagPos[0] == 0) - tagPos[0] = ret.bytecode.size(); + if (i.type() != Tag && m_tagPositionsInBytecode[0] == size_t(-1)) + m_tagPositionsInBytecode[0] = ret.bytecode.size(); switch (i.type()) { @@ -446,7 +459,7 @@ LinkerObject const& Assembly::assemble() const case PushTag: { ret.bytecode.push_back(tagPush); - tagRef[ret.bytecode.size()] = (unsigned)i.data(); + tagRef[ret.bytecode.size()] = i.splitForeignPushTag(); ret.bytecode.resize(ret.bytecode.size() + bytesPerTag); break; } @@ -484,26 +497,16 @@ LinkerObject const& Assembly::assemble() const ret.bytecode.resize(ret.bytecode.size() + 20); break; case Tag: - tagPos[(unsigned)i.data()] = ret.bytecode.size(); - assertThrow(ret.bytecode.size() < 0xffffffffL, AssemblyException, "Tag too large."); assertThrow(i.data() != 0, AssemblyException, ""); + assertThrow(i.splitForeignPushTag().first == size_t(-1), AssemblyException, "Foreign tag."); + assertThrow(ret.bytecode.size() < 0xffffffffL, AssemblyException, "Tag too large."); + m_tagPositionsInBytecode[size_t(i.data())] = ret.bytecode.size(); ret.bytecode.push_back((byte)Instruction::JUMPDEST); break; default: BOOST_THROW_EXCEPTION(InvalidOpcode()); } } - for (auto const& i: tagRef) - { - bytesRef r(ret.bytecode.data() + i.first, bytesPerTag); - auto tag = i.second; - if (tag >= tagPos.size()) - tag = 0; - if (tag == 0) - assertThrow(tagPos[tag] != 0, AssemblyException, ""); - - toBigEndian(tagPos[tag], r); - } if (!dataRef.empty() && !subRef.empty()) ret.bytecode.push_back(0); @@ -519,6 +522,23 @@ LinkerObject const& Assembly::assemble() const } ret.append(m_subs[i].assemble()); } + for (auto const& i: tagRef) + { + size_t subId; + size_t tagId; + tie(subId, tagId) = i.second; + assertThrow(subId == size_t(-1) || subId < m_subs.size(), AssemblyException, "Invalid sub id"); + std::vector const& tagPositions = + subId == size_t(-1) ? + 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."); + assertThrow(dev::bytesRequired(pos) <= bytesPerTag, AssemblyException, "Tag too large for reserved space."); + bytesRef r(ret.bytecode.data() + i.first, bytesPerTag); + toBigEndian(pos, r); + } for (auto const& dataItem: m_data) { auto references = dataRef.equal_range(dataItem.first); diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index dae1e1da..0ae81e1d 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -53,7 +53,6 @@ public: AssemblyItem newPushSubSize(u256 const& _subId) { return AssemblyItem(PushSubSize, _subId); } AssemblyItem newPushLibraryAddress(std::string const& _identifier); - AssemblyItem append() { return append(newTag()); } void append(Assembly const& _a); void append(Assembly const& _a, int _deposit); AssemblyItem const& append(AssemblyItem const& _i); @@ -110,6 +109,10 @@ public: ) const; protected: + /// Does the same operations as @a optimise, but should only be applied to a sub and + /// returns the replaced tags. + std::map optimiseInternal(bool _isCreation, size_t _runs); + 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; @@ -129,6 +132,7 @@ protected: std::map m_libraries; ///< Identifiers of libraries to be linked. mutable LinkerObject m_assembledObject; + mutable std::vector m_tagPositionsInBytecode; int m_deposit = 0; int m_baseDeposit = 0; diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index 599ded85..2eae20af 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -26,6 +26,29 @@ using namespace std; using namespace dev; using namespace dev::eth; +AssemblyItem AssemblyItem::toSubAssemblyTag(size_t _subId) const +{ + assertThrow(m_data < (u256(1) << 64), Exception, "Tag already has subassembly set."); + + assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); + AssemblyItem r = *this; + r.m_type = PushTag; + r.setPushTagSubIdAndTag(_subId, size_t(m_data)); + return r; +} + +pair AssemblyItem::splitForeignPushTag() const +{ + assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); + return make_pair(size_t(m_data / (u256(1) << 64)) - 1, size_t(m_data)); +} + +void AssemblyItem::setPushTagSubIdAndTag(size_t _subId, size_t _tag) +{ + assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); + setData(_tag + ((u256(_subId) + 1) << 64)); +} + unsigned AssemblyItem::bytesRequired(unsigned _addressLength) const { switch (m_type) diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index 1c3d9789..1a2fb1e6 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -69,6 +69,14 @@ public: AssemblyItem tag() const { assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); return AssemblyItem(Tag, m_data); } AssemblyItem pushTag() const { assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); return AssemblyItem(PushTag, m_data); } + /// Converts the tag to a subassembly tag. This has to be called in order to move a tag across assemblies. + /// @param _subId the identifier of the subassembly the tag is taken from. + AssemblyItem toSubAssemblyTag(size_t _subId) const; + /// @returns splits the data of the push tag into sub assembly id and actual tag id. + /// The sub assembly id of non-foreign push tags is -1. + std::pair splitForeignPushTag() const; + /// Sets sub-assembly part and tag for a push tag. + void setPushTagSubIdAndTag(size_t _subId, size_t _tag); AssemblyItemType type() const { return m_type; } u256 const& data() const { return m_data; } diff --git a/libevmasm/BlockDeduplicator.cpp b/libevmasm/BlockDeduplicator.cpp index 3bb7a797..18b595cd 100644 --- a/libevmasm/BlockDeduplicator.cpp +++ b/libevmasm/BlockDeduplicator.cpp @@ -77,7 +77,6 @@ bool BlockDeduplicator::deduplicate() { //@todo this should probably be optimized. set> blocksSeen(comparator); - map tagReplacement; for (size_t i = 0; i < m_items.size(); ++i) { if (m_items.at(i).type() != Tag) @@ -86,22 +85,40 @@ bool BlockDeduplicator::deduplicate() if (it == blocksSeen.end()) blocksSeen.insert(i); else - tagReplacement[m_items.at(i).data()] = m_items.at(*it).data(); + m_replacedTags[m_items.at(i).data()] = m_items.at(*it).data(); } - bool changed = false; - for (AssemblyItem& item: m_items) - if (item.type() == PushTag && tagReplacement.count(item.data())) - { - changed = true; - item.setData(tagReplacement.at(item.data())); - } - if (!changed) + if (!applyTagReplacement(m_items, m_replacedTags)) break; } return iterations > 0; } +bool BlockDeduplicator::applyTagReplacement( + AssemblyItems& _items, + map const& _replacements, + size_t _subId +) +{ + bool changed = false; + for (AssemblyItem& item: _items) + if (item.type() == PushTag) + { + size_t subId; + size_t tagId; + tie(subId, tagId) = item.splitForeignPushTag(); + if (subId != _subId) + continue; + auto it = _replacements.find(tagId); + if (it != _replacements.end()) + { + changed = true; + item.setPushTagSubIdAndTag(subId, size_t(it->second)); + } + } + return changed; +} + BlockDeduplicator::BlockIterator& BlockDeduplicator::BlockIterator::operator++() { if (it == end) diff --git a/libevmasm/BlockDeduplicator.h b/libevmasm/BlockDeduplicator.h index c48835fd..5ecab7f3 100644 --- a/libevmasm/BlockDeduplicator.h +++ b/libevmasm/BlockDeduplicator.h @@ -23,9 +23,12 @@ #pragma once +#include + #include #include #include +#include namespace dev { @@ -45,6 +48,18 @@ public: BlockDeduplicator(AssemblyItems& _items): m_items(_items) {} /// @returns true if something was changed bool deduplicate(); + /// @returns the tags that were replaced. + std::map const& replacedTags() const { return m_replacedTags; } + + /// Replaces all PushTag operations insied @a _items that match a key in + /// @a _replacements by the respective value. If @a _subID is not -1, only + /// apply the replacement for foreign tags from this sub id. + /// @returns true iff a replacement was performed. + static bool applyTagReplacement( + AssemblyItems& _items, + std::map const& _replacements, + size_t _subID = size_t(-1) + ); private: /// Iterator that skips tags and skips to the end if (all branches of) the control @@ -70,6 +85,7 @@ private: AssemblyItem const* replaceWith; }; + std::map m_replacedTags; AssemblyItems& m_items; }; diff --git a/libevmasm/ControlFlowGraph.h b/libevmasm/ControlFlowGraph.h index 03a1f717..78998262 100644 --- a/libevmasm/ControlFlowGraph.h +++ b/libevmasm/ControlFlowGraph.h @@ -89,6 +89,11 @@ struct BasicBlock using BasicBlocks = std::vector; +/** + * Control flow graph optimizer. + * ASSUMES THAT WE ONLY JUMP TO TAGS THAT WERE PREVIOUSLY PUSHED. THIS IS NOT TRUE ANYMORE + * NOW THAT FUNCTION TAGS CAN BE STORED IN STORAGE. + */ class ControlFlowGraph { public: -- cgit v1.2.3 From e51f852504556f952ae1350c070409e3c4981cc0 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 11 Nov 2016 11:41:50 +0100 Subject: Converted sub assembly to smart pointer. --- libevmasm/Assembly.cpp | 54 ++++++++++++++++++++++++++++++---------------- libevmasm/Assembly.h | 33 ++++++++++++++-------------- libevmasm/AssemblyItem.cpp | 12 ++++++++--- 3 files changed, 62 insertions(+), 37 deletions(-) (limited to 'libevmasm') diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 23a8180b..0ee3f421 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -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 Assembly::optimiseInternal(bool _isCreation, size_t _runs) { for (size_t subId = 0; subId < m_subs.size(); ++subId) { - map subTagReplacements = m_subs[subId].optimiseInternal(false, _runs); + map subTagReplacements = m_subs[subId]->optimiseInternal(false, _runs); BlockDeduplicator::applyTagReplacement(m_items, subTagReplacements, subId); } @@ -385,7 +391,11 @@ map 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(m_usedTags, -1); map> tagRef; multimap dataRef; multimap subRef; vector 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(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 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."); diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index 0ae81e1d..3ce82cce 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -14,30 +14,32 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file Assembly.h - * @author Gav Wood - * @date 2014 - */ #pragma once -#include -#include -#include -#include -#include #include #include #include #include -#include "Exceptions.h" +#include + +#include +#include +#include + #include +#include +#include +#include + namespace dev { namespace eth { +using AssemblyPointer = std::shared_ptr; + 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 m_data; - std::vector m_subs; + std::vector> m_subs; std::map m_strings; std::map m_libraries; ///< Identifiers of libraries to be linked. diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index 2eae20af..bc8c87aa 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -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"; -- cgit v1.2.3 From 0335ed4cb476ece63224a96c8ab660116ff08c3a Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 11 Nov 2016 14:11:07 +0100 Subject: Simple peephole optimizer that is activated even if not requested. --- libevmasm/Assembly.cpp | 33 ++++++--- libevmasm/Assembly.h | 3 +- libevmasm/PeepholeOptimiser.cpp | 146 ++++++++++++++++++++++++++++++++++++++++ libevmasm/PeepholeOptimiser.h | 53 +++++++++++++++ 4 files changed, 223 insertions(+), 12 deletions(-) create mode 100644 libevmasm/PeepholeOptimiser.cpp create mode 100644 libevmasm/PeepholeOptimiser.h (limited to 'libevmasm') diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 0ee3f421..a813a3a7 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -20,13 +20,17 @@ */ #include "Assembly.h" -#include + #include #include +#include #include #include #include + +#include #include + using namespace std; using namespace dev; using namespace dev::eth; @@ -314,16 +318,15 @@ void Assembly::injectStart(AssemblyItem const& _i) Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs) { - if (_enable) - optimiseInternal(_isCreation, _runs); + optimiseInternal(_enable, _isCreation, _runs); return *this; } -map Assembly::optimiseInternal(bool _isCreation, size_t _runs) +map Assembly::optimiseInternal(bool _enable, bool _isCreation, size_t _runs) { for (size_t subId = 0; subId < m_subs.size(); ++subId) { - map subTagReplacements = m_subs[subId]->optimiseInternal(false, _runs); + map subTagReplacements = m_subs[subId]->optimiseInternal(_enable, false, _runs); BlockDeduplicator::applyTagReplacement(m_items, subTagReplacements, subId); } @@ -333,6 +336,13 @@ map Assembly::optimiseInternal(bool _isCreation, size_t _runs) { count = 0; + PeepholeOptimiser peepOpt(m_items); + if (peepOpt.optimise()) + count++; + + if (!_enable) + continue; + // This only modifies PushTags, we have to run again to actually remove code. BlockDeduplicator dedup(m_items); if (dedup.deduplicate()) @@ -399,12 +409,13 @@ map Assembly::optimiseInternal(bool _isCreation, size_t _runs) } } - total += ConstantOptimisationMethod::optimiseConstants( - _isCreation, - _isCreation ? 1 : _runs, - *this, - m_items - ); + if (_enable) + total += ConstantOptimisationMethod::optimiseConstants( + _isCreation, + _isCreation ? 1 : _runs, + *this, + m_items + ); return tagReplacements; } diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index 3ce82cce..f3c56610 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -101,6 +101,7 @@ public: /// execution gas usage is optimised. @a _isCreation should be true for the top-level assembly. /// @a _runs specifes an estimate on how often each opcode in this assembly will be executed, /// i.e. use a small value to optimise for size and a large value to optimise for runtime. + /// If @a _enable is not set, will perform some simple peephole optimizations. Assembly& optimise(bool _enable, bool _isCreation = true, size_t _runs = 200); Json::Value stream( std::ostream& _out, @@ -112,7 +113,7 @@ public: protected: /// Does the same operations as @a optimise, but should only be applied to a sub and /// returns the replaced tags. - std::map optimiseInternal(bool _isCreation, size_t _runs); + std::map optimiseInternal(bool _enable, bool _isCreation, size_t _runs); 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()); } diff --git a/libevmasm/PeepholeOptimiser.cpp b/libevmasm/PeepholeOptimiser.cpp new file mode 100644 index 00000000..91b0ece1 --- /dev/null +++ b/libevmasm/PeepholeOptimiser.cpp @@ -0,0 +1,146 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** + * @file PeepholeOptimiser.h + * Performs local optimising code changes to assembly. + */ + +#include "PeepholeOptimiser.h" + +#include +#include + +using namespace std; +using namespace dev::eth; +using namespace dev; + +// TODO: Extend this to use the tools from ExpressionClasses.cpp + +struct Identity +{ + static size_t windowSize() { return 1; } + static bool apply(AssemblyItems::const_iterator _in, std::back_insert_iterator _out) + { + *_out = *_in; + return true; + } +}; + +struct PushPop +{ + static size_t windowSize() { return 2; } + static bool apply(AssemblyItems::const_iterator _in, std::back_insert_iterator) + { + auto t = _in[0].type(); + if (_in[1] == Instruction::POP && ( + SemanticInformation::isDupInstruction(_in[0]) || + t == Push || t == PushString || t == PushTag || t == PushSub || + t == PushSubSize || t == PushProgramSize || t == PushData || t == PushLibraryAddress + )) + return true; + else + return false; + } +}; + +struct DoubleSwap +{ + static size_t windowSize() { return 2; } + static bool apply(AssemblyItems::const_iterator _in, std::back_insert_iterator) + { + if (_in[0] == _in[1] && SemanticInformation::isSwapInstruction(_in[0])) + return true; + else + return false; + } +}; + +struct JumpToNext +{ + static size_t windowSize() { return 3; } + static bool apply(AssemblyItems::const_iterator _in, std::back_insert_iterator _out) + { + if ( + _in[0].type() == PushTag && + (_in[1] == Instruction::JUMP || _in[1] == Instruction::JUMPI) && + _in[2].type() == Tag && + _in[0].data() == _in[2].data() + ) + { + *_out = _in[2]; + return true; + } + else + return false; + } +}; + +struct TagConjunctions +{ + static size_t windowSize() { return 3; } + static bool apply(AssemblyItems::const_iterator _in, std::back_insert_iterator _out) + { + if ( + _in[0].type() == PushTag && + _in[2] == Instruction::AND && + _in[1].type() == Push && + (_in[1].data() & u256(0xFFFFFFFF)) == u256(0xFFFFFFFF) + ) + { + *_out = _in[0]; + return true; + } + else + return false; + } +}; + +struct OptimiserState +{ + AssemblyItems const& items; + size_t i; + std::back_insert_iterator out; +}; + +void applyMethods(OptimiserState&) +{ + assertThrow(false, OptimizerException, "Peephole optimizer failed to apply identity."); +} + +template +void applyMethods(OptimiserState& _state, Method, OtherMethods... _other) +{ + if (_state.i + Method::windowSize() <= _state.items.size() && Method::apply(_state.items.begin() + _state.i, _state.out)) + _state.i += Method::windowSize(); + else + applyMethods(_state, _other...); +} + +bool PeepholeOptimiser::optimise() +{ + OptimiserState state {m_items, 0, std::back_inserter(m_optimisedItems)}; + while (state.i < m_items.size()) + applyMethods(state, PushPop(), DoubleSwap(), JumpToNext(), TagConjunctions(), Identity()); + if (m_optimisedItems.size() < m_items.size()) + { + m_items = std::move(m_optimisedItems); + return true; + } + else + return false; + +} diff --git a/libevmasm/PeepholeOptimiser.h b/libevmasm/PeepholeOptimiser.h new file mode 100644 index 00000000..dfc9a03b --- /dev/null +++ b/libevmasm/PeepholeOptimiser.h @@ -0,0 +1,53 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** + * @file PeepholeOptimiser.h + * Performs local optimising code changes to assembly. + */ +#pragma once + +#include +#include + +namespace dev +{ +namespace eth +{ +class AssemblyItem; +using AssemblyItems = std::vector; + +class PeepholeOptimisationMethod +{ +public: + virtual size_t windowSize() const; + virtual bool apply(AssemblyItems::const_iterator _in, std::back_insert_iterator _out); +}; + +class PeepholeOptimiser +{ +public: + explicit PeepholeOptimiser(AssemblyItems& _items): m_items(_items) {} + + bool optimise(); + +private: + AssemblyItems& m_items; + AssemblyItems m_optimisedItems; +}; + +} +} -- cgit v1.2.3 From 390ba085b63e3968b555eeab0ddf8ef429e7c0ee Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 11 Nov 2016 15:38:56 +0100 Subject: fixup! Simple peephole optimizer that is activated even if not requested. --- libevmasm/PeepholeOptimiser.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'libevmasm') diff --git a/libevmasm/PeepholeOptimiser.cpp b/libevmasm/PeepholeOptimiser.cpp index 91b0ece1..f42dba48 100644 --- a/libevmasm/PeepholeOptimiser.cpp +++ b/libevmasm/PeepholeOptimiser.cpp @@ -81,6 +81,8 @@ struct JumpToNext _in[0].data() == _in[2].data() ) { + if (_in[1] == Instruction::JUMPI) + *_out = AssemblyItem(Instruction::POP, _in[1].location()); *_out = _in[2]; return true; } -- cgit v1.2.3 From cb000a55328d0d1980f2a645e06d4f125ef89e47 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 11 Nov 2016 16:35:13 +0100 Subject: Fix setting the tag. --- libevmasm/AssemblyItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libevmasm') diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index bc8c87aa..7bd93eaf 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -46,7 +46,7 @@ pair AssemblyItem::splitForeignPushTag() const void AssemblyItem::setPushTagSubIdAndTag(size_t _subId, size_t _tag) { assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); - setData(_tag + ((u256(_subId) + 1) << 64)); + setData(_tag + (u256(_subId + 1) << 64)); } unsigned AssemblyItem::bytesRequired(unsigned _addressLength) const -- cgit v1.2.3 From ec31d08775021de0f3279dbeb115b3e688c5997e Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 14 Nov 2016 13:13:37 +0100 Subject: Change encoding to address-funid and add "function" as ABI type. --- libevmasm/PeepholeOptimiser.h | 1 + 1 file changed, 1 insertion(+) (limited to 'libevmasm') diff --git a/libevmasm/PeepholeOptimiser.h b/libevmasm/PeepholeOptimiser.h index dfc9a03b..372e49c5 100644 --- a/libevmasm/PeepholeOptimiser.h +++ b/libevmasm/PeepholeOptimiser.h @@ -22,6 +22,7 @@ #include #include +#include namespace dev { -- cgit v1.2.3 From 2c14a96820233809db4360b39f5f02039be5730a Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 16 Nov 2016 15:09:01 +0100 Subject: Some more assertions and style changes. --- libevmasm/Assembly.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libevmasm') diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index a813a3a7..a3037456 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -81,7 +81,7 @@ string Assembly::out() const unsigned Assembly::bytesRequired(unsigned subTagSize) const { - for (unsigned tagSize = subTagSize;; ++tagSize) + for (unsigned tagSize = subTagSize; true; ++tagSize) { unsigned ret = 1; for (auto const& i: m_data) -- cgit v1.2.3