diff --git a/Changelog.md b/Changelog.md index 3e423c838b67..a9fa4c76e7cd 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ Compiler Features: Bugfixes: +* Commandline Interface: Fix possible inconsistency in subassembly IDs between target architectures in `--asm-json` output. * SMTChecker: Fix incorrect analysis when only a subset of contracts is selected with `--model-checker-contracts`. diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index a0711cd41756..65c038ebd525 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -39,6 +39,7 @@ #include #include +#include #include #include #include @@ -667,17 +668,17 @@ std::pair, std::vector> Assembly::fromJSO return std::make_pair(result, _level == 0 ? parsedSourceList : std::vector{}); } -void Assembly::encodeAllPossibleSubPathsInAssemblyTree(std::vector _pathFromRoot, std::vector _assembliesOnPath) +void Assembly::encodeAllPossibleSubPathsInAssemblyTree(std::vector _pathFromRoot, std::vector _assembliesOnPath) { _assembliesOnPath.push_back(this); - for (_pathFromRoot.push_back(0); _pathFromRoot.back() < m_subs.size(); ++_pathFromRoot.back()) + for (_pathFromRoot.push_back(SubAssemblyID{0}); _pathFromRoot.back().value < m_subs.size(); ++_pathFromRoot.back().value) { for (size_t distanceFromRoot = 0; distanceFromRoot < _assembliesOnPath.size(); ++distanceFromRoot) _assembliesOnPath[distanceFromRoot]->encodeSubPath( _pathFromRoot | ranges::views::drop_exactly(distanceFromRoot) | ranges::to ); - m_subs[_pathFromRoot.back()]->encodeAllPossibleSubPathsInAssemblyTree(_pathFromRoot, _assembliesOnPath); + m_subs[_pathFromRoot.back().asIndex()]->encodeAllPossibleSubPathsInAssemblyTree(_pathFromRoot, _assembliesOnPath); } } @@ -798,20 +799,20 @@ std::map const& Assembly::optimiseInternal( // Run optimisation for sub-assemblies. // TODO: verify and double-check this for EOF. - for (size_t subId = 0; subId < m_subs.size(); ++subId) + for (SubAssemblyID subID {0}; subID.value < m_subs.size(); ++subID.value) { OptimiserSettings settings = _settings; - Assembly& sub = *m_subs[subId]; + Assembly& sub = *m_subs[subID.asIndex()]; std::set referencedTags; for (auto& codeSection: m_codeSections) - referencedTags += JumpdestRemover::referencedTags(codeSection.items, subId); + referencedTags += JumpdestRemover::referencedTags(codeSection.items, subID); std::map const& subTagReplacements = sub.optimiseInternal( settings, referencedTags ); // Apply the replacements (can be empty). for (auto& codeSection: m_codeSections) - BlockDeduplicator::applyTagReplacement(codeSection.items, subTagReplacements, subId); + BlockDeduplicator::applyTagReplacement(codeSection.items, subTagReplacements, subID); } std::map tagReplacements; @@ -1188,7 +1189,7 @@ LinkerObject const& Assembly::assemble() const [[nodiscard]] bytes Assembly::assembleTag(AssemblyItem const& _item, size_t _pos, bool _addJumpDest) const { solRequire(_item.data() != 0, AssemblyException, "Invalid tag position."); - solRequire(_item.splitForeignPushTag().first == std::numeric_limits::max(), AssemblyException, "Foreign tag."); + solRequire(_item.splitForeignPushTag().first.empty(), AssemblyException, "Foreign tag."); solRequire(_pos < 0xffffffffL, AssemblyException, "Tag too large."); size_t tagId = static_cast(_item.data()); solRequire(m_tagPositionsInBytecode[tagId] == std::numeric_limits::max(), AssemblyException, "Duplicate tag position."); @@ -1259,10 +1260,10 @@ LinkerObject const& Assembly::assembleLegacy() const if (item.type() == PushTag) { auto [subId, tagId] = item.splitForeignPushTag(); - if (subId == std::numeric_limits::max()) + if (subId.empty()) continue; - assertThrow(subId < m_subs.size(), AssemblyException, "Invalid sub id"); - auto subTagPosition = m_subs[subId]->m_tagPositionsInBytecode.at(tagId); + solRequire(subId.value < m_subs.size(), AssemblyException, "Invalid sub id"); + auto subTagPosition = m_subs[subId.asIndex()]->m_tagPositionsInBytecode.at(tagId); assertThrow(subTagPosition != std::numeric_limits::max(), AssemblyException, "Reference to tag without position."); bytesPerTag = std::max(bytesPerTag, numberEncodingSize(subTagPosition)); } @@ -1332,17 +1333,18 @@ LinkerObject const& Assembly::assembleLegacy() const break; case PushSub: assembleInstruction([&]() { - assertThrow(item.data() <= std::numeric_limits::max(), AssemblyException, ""); ret.bytecode.push_back(dataRefPush); - subRefs.insert(std::make_pair(static_cast(item.data()), ret.bytecode.size())); + subRefs.emplace( + SubAssemblyID{item.data()}, + ret.bytecode.size() + ); ret.bytecode.resize(ret.bytecode.size() + bytesPerDataRef); }); break; case PushSubSize: { assembleInstruction([&](){ - assertThrow(item.data() <= std::numeric_limits::max(), AssemblyException, ""); - auto s = subAssemblyById(static_cast(item.data()))->assemble().bytecode.size(); + auto s = subAssemblyById(SubAssemblyID{item.data()})->assemble().bytecode.size(); item.setPushedValue(u256(s)); unsigned b = std::max(1, numberEncodingSize(s)); ret.bytecode.push_back(static_cast(pushInstruction(b))); @@ -1478,14 +1480,12 @@ LinkerObject const& Assembly::assembleLegacy() const } for (auto const& i: tagRefs) { - size_t subId; - size_t tagId; - std::tie(subId, tagId) = i.second; - assertThrow(subId == std::numeric_limits::max() || subId < m_subs.size(), AssemblyException, "Invalid sub id"); + auto [subId, tagId] = i.second; + solRequire(subId.empty() || subId.value < m_subs.size(), AssemblyException, "Invalid sub id"); std::vector const& tagPositions = - subId == std::numeric_limits::max() ? + subId.empty() ? m_tagPositionsInBytecode : - m_subs[subId]->m_tagPositionsInBytecode; + m_subs[subId.asIndex()]->m_tagPositionsInBytecode; assertThrow(tagId < tagPositions.size(), AssemblyException, "Reference to non-existing tag."); size_t pos = tagPositions[tagId]; assertThrow(pos != std::numeric_limits::max(), AssemblyException, "Reference to tag without position."); @@ -1796,14 +1796,13 @@ LinkerObject const& Assembly::assembleEOF() const return ret; } -std::vector Assembly::decodeSubPath(size_t _subObjectId) const +std::vector Assembly::decodeSubPath(SubAssemblyID _subObjectId) const { - if (_subObjectId < m_subs.size()) + if (_subObjectId.value < m_subs.size()) return {_subObjectId}; - auto subIdPathIt = find_if( - m_subPaths.begin(), - m_subPaths.end(), + auto subIdPathIt = ranges::find_if( + m_subPaths, [_subObjectId](auto const& subId) { return subId.second == _subObjectId; } ); @@ -1811,32 +1810,32 @@ std::vector Assembly::decodeSubPath(size_t _subObjectId) const return subIdPathIt->first; } -size_t Assembly::encodeSubPath(std::vector const& _subPath) +SubAssemblyID Assembly::encodeSubPath(std::vector const& _subPath) { assertThrow(!_subPath.empty(), AssemblyException, ""); if (_subPath.size() == 1) { - assertThrow(_subPath[0] < m_subs.size(), AssemblyException, ""); + solAssert(_subPath[0].value < m_subs.size()); return _subPath[0]; } - if (m_subPaths.find(_subPath) == m_subPaths.end()) + if (!m_subPaths.contains(_subPath)) { - size_t objectId = std::numeric_limits::max() - m_subPaths.size(); - assertThrow(objectId >= m_subs.size(), AssemblyException, ""); + SubAssemblyID const objectId{std::numeric_limits::max() - m_subPaths.size()}; + solAssert(objectId.value >= m_subs.size()); m_subPaths[_subPath] = objectId; } return m_subPaths[_subPath]; } -Assembly const* Assembly::subAssemblyById(size_t _subId) const +Assembly const* Assembly::subAssemblyById(SubAssemblyID const _subId) const { - std::vector subIds = decodeSubPath(_subId); + std::vector subIDs = decodeSubPath(_subId); Assembly const* currentAssembly = this; - for (size_t currentSubId: subIds) + for (auto const& subID: subIDs) { - currentAssembly = currentAssembly->m_subs.at(currentSubId).get(); + currentAssembly = currentAssembly->m_subs.at(subID.asIndex()).get(); assertThrow(currentAssembly, AssemblyException, ""); } diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index 30b06dd367fb..e58222a8282a 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -47,9 +48,9 @@ using AssemblyPointer = std::shared_ptr; class Assembly { - using TagRefs = std::map>; + using TagRefs = std::map>; using DataRefs = std::multimap; - using SubAssemblyRefs = std::multimap; + using SubAssemblyRefs = std::multimap; using ProgramSizeRefs = std::vector; using LinkRef = std::pair; @@ -81,8 +82,8 @@ class Assembly AssemblyItem newData(bytes const& _data) { util::h256 h(util::keccak256(util::asString(_data))); m_data[h] = _data; return AssemblyItem(PushData, h); } bytes const& data(util::h256 const& _i) const { return m_data.at(_i); } 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); } + Assembly const& sub(SubAssemblyID const _sub) const { return *m_subs.at(_sub.asIndex()); } + Assembly& sub(SubAssemblyID const _sub) { return *m_subs.at(_sub.asIndex()); } size_t numSubs() const { return m_subs.size(); } AssemblyItem newPushSubSize(u256 const& _subId) { return AssemblyItem(PushSubSize, _subId); } AssemblyItem newPushLibraryAddress(std::string const& _identifier); @@ -142,9 +143,9 @@ class Assembly /// 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. AssemblyItem appendSubroutine(AssemblyPointer const& _assembly) { auto sub = newSub(_assembly); append(newPushSubSize(size_t(sub.data()))); return sub; } - void pushSubroutineSize(size_t _subRoutine) { append(newPushSubSize(_subRoutine)); } + void pushSubroutineSize(SubAssemblyID _subRoutine) { append(newPushSubSize(_subRoutine.value)); } /// Pushes the offset of the subroutine. - void pushSubroutineOffset(size_t _subRoutine) { append(AssemblyItem(PushSub, _subRoutine)); } + void pushSubroutineOffset(SubAssemblyID _subRoutine) { append(AssemblyItem(PushSub, _subRoutine.value)); } /// Appends @a _data literally to the very end of the bytecode. void appendToAuxiliaryData(bytes const& _data) { m_auxiliaryData += _data; } @@ -216,8 +217,8 @@ class Assembly /// Mark this assembly as invalid. Calling ``assemble`` on it will throw. void markAsInvalid() { m_invalid = true; } - std::vector decodeSubPath(size_t _subObjectId) const; - size_t encodeSubPath(std::vector const& _subPath); + std::vector decodeSubPath(SubAssemblyID _subObjectId) const; + SubAssemblyID encodeSubPath(std::vector const& _subPath); bool isCreation() const { return m_creation; } @@ -265,9 +266,9 @@ class Assembly private: bool m_invalid = false; - Assembly const* subAssemblyById(size_t _subId) const; + Assembly const* subAssemblyById(SubAssemblyID _subId) const; - void encodeAllPossibleSubPathsInAssemblyTree(std::vector _pathFromRoot = {}, std::vector _assembliesOnPath = {}); + void encodeAllPossibleSubPathsInAssemblyTree(std::vector _pathFromRoot = {}, std::vector _assembliesOnPath = {}); std::shared_ptr sharedSourceName(std::string const& _name) const; @@ -315,7 +316,7 @@ class Assembly /// Map from a vector representing a path to a particular sub assembly to sub assembly id. /// This map is used only for sub-assemblies which are not direct sub-assemblies (where path is having more than one value). - std::map, size_t> m_subPaths; + std::map, SubAssemblyID> m_subPaths; /// Contains the tag replacements relevant for super-assemblies. /// If set, it means the optimizer has run and we will not run it again. diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index 8a917986f915..1b4d50bc386b 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -50,7 +50,7 @@ std::string toStringInHex(u256 _value) } -AssemblyItem AssemblyItem::toSubAssemblyTag(size_t _subId) const +AssemblyItem AssemblyItem::toSubAssemblyTag(SubAssemblyID _subId) const { assertThrow(data() < (u256(1) << 64), util::Exception, "Tag already has subassembly set."); assertThrow(m_type == PushTag || m_type == Tag, util::Exception, ""); @@ -61,20 +61,21 @@ AssemblyItem AssemblyItem::toSubAssemblyTag(size_t _subId) const return r; } -std::pair AssemblyItem::splitForeignPushTag() const +std::pair AssemblyItem::splitForeignPushTag() const { solAssert(m_type == PushTag || m_type == Tag || m_type == RelativeJump || m_type == ConditionalRelativeJump); u256 combined = u256(data()); - size_t subId = static_cast((combined >> 64) - 1); + // the combined u256 is 'dirty', so we can't use the conversion constructor of SubAssemblyID here + SubAssemblyID subID {static_cast((combined >> 64) - 1)}; size_t tag = static_cast(combined & 0xffffffffffffffffULL); - return std::make_pair(subId, tag); + return std::make_pair(subID, tag); } size_t AssemblyItem::relativeJumpTagID() const { solAssert(m_type == RelativeJump || m_type == ConditionalRelativeJump); auto const [subId, tagId] = splitForeignPushTag(); - solAssert(subId == std::numeric_limits::max(), "Relative jump to sub"); + solAssert(subId.empty(), "Relative jump to sub"); return tagId; } @@ -130,13 +131,13 @@ std::pair AssemblyItem::nameAndData(langutil::EVMVersi util::unreachable(); } -void AssemblyItem::setPushTagSubIdAndTag(size_t _subId, size_t _tag) +void AssemblyItem::setPushTagSubIdAndTag(SubAssemblyID _subId, size_t _tag) { solAssert(m_type == PushTag || m_type == Tag || m_type == RelativeJump || m_type == ConditionalRelativeJump); - solAssert(!(m_type == RelativeJump || m_type == ConditionalRelativeJump) || _subId == std::numeric_limits::max()); + solAssert(!(m_type == RelativeJump || m_type == ConditionalRelativeJump) || _subId.empty()); u256 data = _tag; - if (_subId != std::numeric_limits::max()) - data |= (u256(_subId) + 1) << 64; + if (!_subId.empty()) + data |= (u256(_subId.value) + 1) << 64; setData(data); } @@ -352,13 +353,11 @@ std::string AssemblyItem::toAssemblyText(Assembly const& _assembly) const break; case PushTag: { - size_t sub{0}; - size_t tag{0}; - std::tie(sub, tag) = splitForeignPushTag(); - if (sub == std::numeric_limits::max()) + auto [sub, tag] = splitForeignPushTag(); + if (sub.empty()) text = std::string("tag_") + std::to_string(tag); else - text = std::string("tag_") + std::to_string(sub) + "_" + std::to_string(tag); + text = std::string("tag_") + std::to_string(sub.value) + "_" + std::to_string(tag); break; } case Tag: @@ -372,8 +371,8 @@ std::string AssemblyItem::toAssemblyText(Assembly const& _assembly) const case PushSubSize: { std::vector subPathComponents; - for (size_t subPathComponentId: _assembly.decodeSubPath(static_cast(data()))) - subPathComponents.emplace_back("sub_" + std::to_string(subPathComponentId)); + for (SubAssemblyID subPathComponentId: _assembly.decodeSubPath(SubAssemblyID{data()})) + subPathComponents.emplace_back("sub_" + std::to_string(subPathComponentId.value)); text = (type() == PushSub ? "dataOffset"s : "dataSize"s) + "(" + @@ -469,11 +468,11 @@ std::ostream& solidity::evmasm::operator<<(std::ostream& _out, AssemblyItem cons break; case PushTag: { - size_t subId = _item.splitForeignPushTag().first; - if (subId == std::numeric_limits::max()) + SubAssemblyID subId = _item.splitForeignPushTag().first; + if (subId.empty()) _out << " PushTag " << _item.splitForeignPushTag().second; else - _out << " PushTag " << subId << ":" << _item.splitForeignPushTag().second; + _out << " PushTag " << subId.value << ":" << _item.splitForeignPushTag().second; break; } case Tag: diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index b053c5b27598..19553837446f 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -169,14 +170,14 @@ class AssemblyItem AssemblyItem pushTag() const { solAssert(m_type == PushTag || m_type == Tag || m_type == RelativeJump || m_type == ConditionalRelativeJump); return AssemblyItem(PushTag, 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; + AssemblyItem toSubAssemblyTag(SubAssemblyID _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; + std::pair splitForeignPushTag() const; /// @returns relative jump target tag ID. Asserts that it is not foreign tag. size_t relativeJumpTagID() const; /// Sets sub-assembly part and tag for a push tag. - void setPushTagSubIdAndTag(size_t _subId, size_t _tag); + void setPushTagSubIdAndTag(SubAssemblyID _subId, size_t _tag); AssemblyItemType type() const { return m_type; } u256 const& data() const { solAssert(m_type != Operation && m_data != nullptr); return *m_data; } diff --git a/libevmasm/BlockDeduplicator.cpp b/libevmasm/BlockDeduplicator.cpp index 3ba8cfcd3523..5c9c5a840f6e 100644 --- a/libevmasm/BlockDeduplicator.cpp +++ b/libevmasm/BlockDeduplicator.cpp @@ -101,14 +101,14 @@ bool BlockDeduplicator::deduplicate() bool BlockDeduplicator::applyTagReplacement( AssemblyItems& _items, std::map const& _replacements, - size_t _subId + SubAssemblyID _subId ) { bool changed = false; for (AssemblyItem& item: _items) if (item.type() == PushTag || item.type() == RelativeJump || item.type() == ConditionalRelativeJump) { - size_t subId; + SubAssemblyID subId; size_t tagId; std::tie(subId, tagId) = item.splitForeignPushTag(); if (subId != _subId) diff --git a/libevmasm/BlockDeduplicator.h b/libevmasm/BlockDeduplicator.h index fb83b317e0a1..3b97d6ede796 100644 --- a/libevmasm/BlockDeduplicator.h +++ b/libevmasm/BlockDeduplicator.h @@ -24,10 +24,11 @@ #pragma once +#include + #include #include - #include #include #include @@ -59,7 +60,7 @@ class BlockDeduplicator static bool applyTagReplacement( AssemblyItems& _items, std::map const& _replacements, - size_t _subID = size_t(-1) + SubAssemblyID _subID = {} ); private: diff --git a/libevmasm/CMakeLists.txt b/libevmasm/CMakeLists.txt index a7441b85e264..75796531ebe6 100644 --- a/libevmasm/CMakeLists.txt +++ b/libevmasm/CMakeLists.txt @@ -42,6 +42,7 @@ set(sources SimplificationRule.h SimplificationRules.cpp SimplificationRules.h + SubAssemblyID.h ) add_library(evmasm ${sources}) diff --git a/libevmasm/EVMAssemblyStack.cpp b/libevmasm/EVMAssemblyStack.cpp index 7cb05bf8bf00..de5e459ba8ea 100644 --- a/libevmasm/EVMAssemblyStack.cpp +++ b/libevmasm/EVMAssemblyStack.cpp @@ -62,7 +62,7 @@ void EVMAssemblyStack::assemble() m_sourceMapping = AssemblyItem::computeSourceMapping(m_evmAssembly->codeSections().front().items, sourceIndices()); if (m_evmAssembly->numSubs() > 0) { - m_evmRuntimeAssembly = std::make_shared(m_evmAssembly->sub(0)); + m_evmRuntimeAssembly = std::make_shared(m_evmAssembly->sub(SubAssemblyID{0})); solAssert(m_evmRuntimeAssembly && !m_evmRuntimeAssembly->isCreation()); // TODO: Check for EOF solAssert(m_evmRuntimeAssembly->codeSections().size() == 1); diff --git a/libevmasm/Inliner.cpp b/libevmasm/Inliner.cpp index f3358128c655..f32a03ab59f5 100644 --- a/libevmasm/Inliner.cpp +++ b/libevmasm/Inliner.cpp @@ -71,7 +71,7 @@ std::optional getLocalTag(AssemblyItem const& _item) if (_item.type() != PushTag && _item.type() != Tag) return std::nullopt; auto [subId, tag] = _item.splitForeignPushTag(); - if (subId != std::numeric_limits::max()) + if (!subId.empty()) return std::nullopt; return tag; } diff --git a/libevmasm/JumpdestRemover.cpp b/libevmasm/JumpdestRemover.cpp index 7ded5ae90889..300f24b57bd6 100644 --- a/libevmasm/JumpdestRemover.cpp +++ b/libevmasm/JumpdestRemover.cpp @@ -32,7 +32,7 @@ using namespace solidity::evmasm; bool JumpdestRemover::optimise(std::set const& _tagsReferencedFromOutside) { - std::set references{referencedTags(m_items, std::numeric_limits::max())}; + std::set references{referencedTags(m_items, SubAssemblyID{})}; references.insert(_tagsReferencedFromOutside.begin(), _tagsReferencedFromOutside.end()); size_t initialSize = m_items.size(); @@ -45,7 +45,7 @@ bool JumpdestRemover::optimise(std::set const& _tagsReferencedFromOutsid if (_item.type() != Tag) return false; auto asmIdAndTag = _item.splitForeignPushTag(); - assertThrow(asmIdAndTag.first == std::numeric_limits::max(), OptimizerException, "Sub-assembly tag used as label."); + solRequire(asmIdAndTag.first.empty(), OptimizerException, "Sub-assembly tag used as label."); size_t tag = asmIdAndTag.second; return !references.count(tag); } @@ -54,7 +54,7 @@ bool JumpdestRemover::optimise(std::set const& _tagsReferencedFromOutsid return m_items.size() != initialSize; } -std::set JumpdestRemover::referencedTags(AssemblyItems const& _items, size_t _subId) +std::set JumpdestRemover::referencedTags(AssemblyItems const& _items, SubAssemblyID _subId) { std::set ret; for (auto const& item: _items) diff --git a/libevmasm/JumpdestRemover.h b/libevmasm/JumpdestRemover.h index e07550e2dd40..f344e543c573 100644 --- a/libevmasm/JumpdestRemover.h +++ b/libevmasm/JumpdestRemover.h @@ -21,6 +21,8 @@ */ #pragma once +#include + #include #include #include @@ -39,7 +41,7 @@ class JumpdestRemover /// @returns a set of all tags from the given sub-assembly that are referenced /// from the given list of items. - static std::set referencedTags(AssemblyItems const& _items, size_t _subId); + static std::set referencedTags(AssemblyItems const& _items, SubAssemblyID _subId); private: AssemblyItems& m_items; diff --git a/libevmasm/SubAssemblyID.h b/libevmasm/SubAssemblyID.h new file mode 100644 index 000000000000..bd64a71d2c25 --- /dev/null +++ b/libevmasm/SubAssemblyID.h @@ -0,0 +1,62 @@ +/* + This file is part of solidity. + + solidity 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. + + solidity 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 solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include + +#include + +#include +#include +#include +#include + +namespace solidity::evmasm +{ + +/// Sub assembly ID representing class. Based on fixed-size 64-bit unsigned int. +/// An empty / root state is reflected by a value that is set to max and can be queried via the `empty()` member +/// function. +struct SubAssemblyID +{ + using value_type = uint64_t; + SubAssemblyID() = default; + SubAssemblyID(value_type const _value): value(_value) {} + explicit SubAssemblyID(u256 const& _data) + { + solAssert(_data <= std::numeric_limits::max()); + value = static_cast(_data); + } + + value_type value = std::numeric_limits::max(); + + size_t asIndex() const + { + if constexpr(sizeof(value_type) > sizeof(size_t)) + { + solAssert(value < std::numeric_limits::max()); + return static_cast(value); + } + return value; + } + bool empty() const { return value == std::numeric_limits::max(); } + auto operator<=>(SubAssemblyID const&) const = default; +}; + +} diff --git a/libsolidity/codegen/Compiler.h b/libsolidity/codegen/Compiler.h index bc801ff5782b..1df3e3cb4219 100644 --- a/libsolidity/codegen/Compiler.h +++ b/libsolidity/codegen/Compiler.h @@ -70,7 +70,7 @@ class Compiler private: OptimiserSettings const m_optimiserSettings; CompilerContext m_runtimeContext; - size_t m_runtimeSub = size_t(-1); ///< Identifier of the runtime sub-assembly, if present. + evmasm::SubAssemblyID m_runtimeSub{}; ///< Identifier of the runtime sub-assembly, if present. CompilerContext m_context; }; diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index e8c4e9bc77f7..638ee6939ca8 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -75,7 +75,7 @@ class CompilerContext m_yulUtilFunctions(m_evmVersion, _eofVersion, m_revertStrings, m_yulFunctionCollector) { if (m_runtimeContext) - m_runtimeSub = size_t(m_asm->newSub(m_runtimeContext->m_asm).data()); + m_runtimeSub = evmasm::SubAssemblyID{m_asm->newSub(m_runtimeContext->m_asm).data()}; } langutil::EVMVersion const& evmVersion() const { return m_evmVersion; } @@ -227,9 +227,9 @@ class CompilerContext /// on the stack. @returns the pushsub assembly item. evmasm::AssemblyItem addSubroutine(evmasm::AssemblyPointer const& _assembly) { return m_asm->appendSubroutine(_assembly); } /// Pushes the size of the subroutine. - void pushSubroutineSize(size_t _subRoutine) { m_asm->pushSubroutineSize(_subRoutine); } + void pushSubroutineSize(evmasm::SubAssemblyID _subRoutine) { m_asm->pushSubroutineSize(_subRoutine); } /// Pushes the offset of the subroutine. - void pushSubroutineOffset(size_t _subRoutine) { m_asm->pushSubroutineOffset(_subRoutine); } + void pushSubroutineOffset(evmasm::SubAssemblyID _subRoutine) { m_asm->pushSubroutineOffset(_subRoutine); } /// Pushes the size of the final program void appendProgramSize() { m_asm->appendProgramSize(); } /// Adds data to the data section, pushes a reference to the stack @@ -289,7 +289,7 @@ class CompilerContext /// @returns the runtime context if in creation mode and runtime context is set, nullptr otherwise. CompilerContext* runtimeContext() const { return m_runtimeContext; } /// @returns the identifier of the runtime subroutine. - size_t runtimeSub() const { return m_runtimeSub; } + evmasm::SubAssemblyID runtimeSub() const { return m_runtimeSub; } /// @returns a const reference to the underlying assembly. evmasm::Assembly const& assembly() const { return *m_asm; } @@ -376,7 +376,7 @@ class CompilerContext /// The runtime context if in Creation mode, this is used for generating tags that would be stored into the storage and then used at runtime. CompilerContext *m_runtimeContext; /// The index of the runtime subroutine. - size_t m_runtimeSub = std::numeric_limits::max(); + evmasm::SubAssemblyID m_runtimeSub{}; /// An index of low-level function labels by name. std::map m_lowLevelFunctions; /// Collector for yul functions. diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 3a4dca0439ca..fc5ec2917f33 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -108,7 +108,7 @@ void ContractCompiler::compileContract( appendFunctionSelector(_contract); } -size_t ContractCompiler::compileConstructor( +SubAssemblyID ContractCompiler::compileConstructor( ContractDefinition const& _contract, std::map> const& _otherCompilers ) @@ -167,7 +167,7 @@ void ContractCompiler::appendInitAndConstructorCode(ContractDefinition const& _c } } -size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _contract) +SubAssemblyID ContractCompiler::packIntoContractCreator(ContractDefinition const& _contract) { solAssert(!!m_runtimeCompiler, ""); solAssert(!_contract.isLibrary(), "Tried to use contract creator or library."); @@ -186,7 +186,7 @@ size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _cont CompilerContext::LocationSetter locationSetter(m_context, _contract); m_context << deployRoutine; - solAssert(m_context.runtimeSub() != std::numeric_limits::max(), "Runtime sub not registered"); + solAssert(!m_context.runtimeSub().empty(), "Runtime sub not registered"); ContractType contractType(_contract); auto const& immutables = contractType.immutableVariables(); @@ -220,7 +220,7 @@ size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _cont return m_context.runtimeSub(); } -size_t ContractCompiler::deployLibrary(ContractDefinition const& _contract) +SubAssemblyID ContractCompiler::deployLibrary(ContractDefinition const& _contract) { solAssert(!!m_runtimeCompiler, ""); solAssert(_contract.isLibrary(), "Tried to deploy contract as library."); @@ -230,7 +230,7 @@ size_t ContractCompiler::deployLibrary(ContractDefinition const& _contract) CompilerContext::LocationSetter locationSetter(m_context, _contract); - solAssert(m_context.runtimeSub() != std::numeric_limits::max(), "Runtime sub not registered"); + solAssert(!m_context.runtimeSub().empty(), "Runtime sub not registered"); m_context.pushSubroutineSize(m_context.runtimeSub()); m_context.pushSubroutineOffset(m_context.runtimeSub()); // This code replaces the address added by appendDeployTimeAddress(). diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h index 592b6703997b..e342bbc5fb1b 100644 --- a/libsolidity/codegen/ContractCompiler.h +++ b/libsolidity/codegen/ContractCompiler.h @@ -58,7 +58,7 @@ class ContractCompiler: private ASTConstVisitor ); /// Compiles the constructor part of the contract. /// @returns the identifier of the runtime sub-assembly. - size_t compileConstructor( + evmasm::SubAssemblyID compileConstructor( ContractDefinition const& _contract, std::map> const& _otherCompilers ); @@ -73,11 +73,11 @@ class ContractCompiler: private ASTConstVisitor /// Adds the code that is run at creation time. Should be run after exchanging the run-time context /// with a new and initialized context. Adds the constructor code. /// @returns the identifier of the runtime sub assembly - size_t packIntoContractCreator(ContractDefinition const& _contract); + evmasm::SubAssemblyID packIntoContractCreator(ContractDefinition const& _contract); /// Appends code that deploys the given contract as a library. /// Will also add code that modifies the contract in memory by injecting the current address /// for the call protector. - size_t deployLibrary(ContractDefinition const& _contract); + evmasm::SubAssemblyID deployLibrary(ContractDefinition const& _contract); /// Appends state variable initialisation and constructor code. void appendInitAndConstructorCode(ContractDefinition const& _contract); void appendBaseConstructor(FunctionDefinition const& _constructor); diff --git a/libyul/CompilabilityChecker.cpp b/libyul/CompilabilityChecker.cpp index cc46ecb77000..d65c741f202c 100644 --- a/libyul/CompilabilityChecker.cpp +++ b/libyul/CompilabilityChecker.cpp @@ -49,9 +49,9 @@ CompilabilityChecker::CompilabilityChecker( BuiltinContext builtinContext; builtinContext.currentObject = &_object; if (!_object.name.empty()) - builtinContext.subIDs[_object.name] = 1; + builtinContext.subIDs[_object.name] = {1}; for (auto const& subNode: _object.subObjects) - builtinContext.subIDs[subNode->name] = 1; + builtinContext.subIDs[subNode->name] = {1}; NoOutputAssembly assembly{evmDialect->evmVersion()}; CodeTransform transform( assembly, diff --git a/libyul/Object.cpp b/libyul/Object.cpp index 54ec6a3cfd7a..bb044128766a 100644 --- a/libyul/Object.cpp +++ b/libyul/Object.cpp @@ -169,7 +169,7 @@ Object::Structure Object::summarizeStructure() const return structure; } -std::vector Object::pathToSubObject(std::string_view _qualifiedName) const +std::vector Object::pathToSubObject(std::string_view _qualifiedName) const { yulAssert(_qualifiedName != name, ""); yulAssert(subIndexByName.count(name) == 0, ""); @@ -181,7 +181,7 @@ std::vector Object::pathToSubObject(std::string_view _qualifiedName) con std::vector subObjectPathComponents; boost::algorithm::split(subObjectPathComponents, _qualifiedName, boost::is_any_of(".")); - std::vector path; + std::vector path; Object const* object = this; for (std::string const& currentSubObjectName: subObjectPathComponents) { @@ -193,8 +193,8 @@ std::vector Object::pathToSubObject(std::string_view _qualifiedName) con ); object = dynamic_cast(object->subObjects[subIndexIt->second].get()); yulAssert(object, "Assembly object <" + std::string(_qualifiedName) + "> not found or does not contain code."); - yulAssert(object->subId != std::numeric_limits::max(), ""); - path.push_back({object->subId}); + yulAssert(!object->subId.empty()); + path.emplace_back(object->subId); } return path; diff --git a/libyul/Object.h b/libyul/Object.h index c865b906ed37..a816db11b820 100644 --- a/libyul/Object.h +++ b/libyul/Object.h @@ -24,6 +24,8 @@ #include #include +#include + #include #include @@ -135,14 +137,14 @@ class Object: public ObjectNode /// pathToSubObject("E2.F3.H4") == {1, 0, 2} /// pathToSubObject("A1.E2") == {1} /// The path must not lead to a @a Data object (will throw in that case). - std::vector pathToSubObject(std::string_view _qualifiedName) const; + std::vector pathToSubObject(std::string_view _qualifiedName) const; std::shared_ptr code() const; void setCode(std::shared_ptr const& _ast, std::shared_ptr = nullptr); bool hasCode() const; - /// sub id for object if it is subobject of another object, max value if it is not subobject - size_t subId = std::numeric_limits::max(); + /// sub id for object if it is subobject of another object, max value / empty if it is not subobject + evmasm::SubAssemblyID subId{}; std::vector> subObjects; std::map> subIndexByName; diff --git a/libyul/ObjectOptimizer.cpp b/libyul/ObjectOptimizer.cpp index a09e88791577..63f372bf6448 100644 --- a/libyul/ObjectOptimizer.cpp +++ b/libyul/ObjectOptimizer.cpp @@ -56,7 +56,7 @@ Dialect const& yul::languageToDialect(Language _language, EVMVersion _version, s void ObjectOptimizer::optimize(Object& _object, Settings const& _settings) { - yulAssert(_object.subId == std::numeric_limits::max(), "Not a top-level object."); + yulAssert(_object.subId.empty(), "Not a top-level object."); optimize(_object, _settings, true /* _isCreation */); } diff --git a/libyul/YulStack.cpp b/libyul/YulStack.cpp index 5adb8d6d5c9a..38c7c0b72ea9 100644 --- a/libyul/YulStack.cpp +++ b/libyul/YulStack.cpp @@ -330,15 +330,15 @@ YulStack::assembleEVMWithDeployed(std::optional _deployName) assembly.optimise(evmasm::Assembly::OptimiserSettings::translateSettings(m_optimiserSettings)); - std::optional subIndex; + std::optional subIndex; // Pick matching assembly if name was given if (_deployName.has_value()) { for (size_t i = 0; i < assembly.numSubs(); i++) - if (assembly.sub(i).name() == _deployName) + if (assembly.sub({i}).name() == _deployName) { - subIndex = i; + subIndex = {i}; break; } @@ -346,7 +346,7 @@ YulStack::assembleEVMWithDeployed(std::optional _deployName) } // Otherwise use heuristic: If there is a single sub-assembly, this is likely the object to be deployed. else if (assembly.numSubs() == 1) - subIndex = 0; + subIndex = {0}; if (subIndex.has_value()) { diff --git a/libyul/backends/evm/AbstractAssembly.h b/libyul/backends/evm/AbstractAssembly.h index 41f480f442a0..3108729b9fa9 100644 --- a/libyul/backends/evm/AbstractAssembly.h +++ b/libyul/backends/evm/AbstractAssembly.h @@ -25,6 +25,8 @@ #include +#include + #include #include #include @@ -55,7 +57,7 @@ class AbstractAssembly { public: using LabelID = size_t; - using SubID = size_t; + using SubID = evmasm::SubAssemblyID; using ContainerID = uint8_t; using FunctionID = uint16_t; enum class JumpType { Ordinary, IntoFunction, OutOfFunction }; diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index d68ef16348b1..71e2faf7b20a 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -292,10 +292,10 @@ std::vector> createBuiltins(langutil::EVMVe _assembly.appendAssemblySize(); else { - std::vector subIdPath = + std::vector subIdPath = _context.subIDs.count(dataName.str()) == 0 ? _context.currentObject->pathToSubObject(dataName.str()) : - std::vector{_context.subIDs.at(dataName.str())}; + std::vector{_context.subIDs.at(dataName.str())}; yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">."); _assembly.appendDataSize(subIdPath); } @@ -313,10 +313,10 @@ std::vector> createBuiltins(langutil::EVMVe _assembly.appendConstant(0); else { - std::vector subIdPath = + std::vector subIdPath = _context.subIDs.count(dataName.str()) == 0 ? _context.currentObject->pathToSubObject(dataName.str()) : - std::vector{_context.subIDs.at(dataName.str())}; + std::vector{_context.subIDs.at(dataName.str())}; yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">."); _assembly.appendDataOffset(subIdPath); } @@ -422,8 +422,8 @@ std::vector> createBuiltins(langutil::EVMVe yulAssert(!util::contains(formattedLiteral, '.')); auto const* containerID = valueOrNullptr(context.subIDs, formattedLiteral); yulAssert(containerID != nullptr); - yulAssert(*containerID <= std::numeric_limits::max()); - _assembly.appendEOFCreate(static_cast(*containerID)); + yulAssert(containerID->value <= std::numeric_limits::max()); + _assembly.appendEOFCreate(static_cast(containerID->value)); } )); @@ -446,8 +446,8 @@ std::vector> createBuiltins(langutil::EVMVe yulAssert(!util::contains(formattedLiteral, '.')); auto const* containerID = valueOrNullptr(context.subIDs, formattedLiteral); yulAssert(containerID != nullptr); - yulAssert(*containerID <= std::numeric_limits::max()); - _assembly.appendReturnContract(static_cast(*containerID)); + yulAssert(containerID->value <= std::numeric_limits::max()); + _assembly.appendReturnContract(static_cast(containerID->value)); } )); } diff --git a/libyul/backends/evm/EthAssemblyAdapter.cpp b/libyul/backends/evm/EthAssemblyAdapter.cpp index 960e663dfa7a..47bd3ffb6644 100644 --- a/libyul/backends/evm/EthAssemblyAdapter.cpp +++ b/libyul/backends/evm/EthAssemblyAdapter.cpp @@ -142,7 +142,7 @@ std::pair, AbstractAssembly::SubID> EthAssembl { std::shared_ptr assembly{std::make_shared(m_assembly.evmVersion(), _creation, m_assembly.eofVersion(), std::move(_name))}; auto sub = m_assembly.newSub(assembly); - return {std::make_shared(*assembly), static_cast(sub.data())}; + return {std::make_shared(*assembly), SubID{sub.data()}}; } AbstractAssembly::FunctionID EthAssemblyAdapter::registerFunction(uint8_t _args, uint8_t _rets, bool _nonReturning) @@ -207,7 +207,7 @@ void EthAssemblyAdapter::appendDataSize(std::vector con AbstractAssembly::SubID EthAssemblyAdapter::appendData(bytes const& _data) { evmasm::AssemblyItem pushData = m_assembly.newData(_data); - SubID subID = m_nextDataCounter++; + SubID const subID{m_nextDataCounter++}; m_dataHashBySubId[subID] = pushData.data(); return subID; } diff --git a/libyul/backends/evm/EthAssemblyAdapter.h b/libyul/backends/evm/EthAssemblyAdapter.h index dd708b8b33de..67dcf6af4fe5 100644 --- a/libyul/backends/evm/EthAssemblyAdapter.h +++ b/libyul/backends/evm/EthAssemblyAdapter.h @@ -88,6 +88,6 @@ class EthAssemblyAdapter: public AbstractAssembly evmasm::Assembly& m_assembly; std::map m_dataHashBySubId; - size_t m_nextDataCounter = std::numeric_limits::max() / 2; + SubID::value_type m_nextDataCounter = std::numeric_limits::max() / 2; }; } diff --git a/libyul/backends/evm/NoOutputAssembly.cpp b/libyul/backends/evm/NoOutputAssembly.cpp index 78025265f342..ba4ae4025c9c 100644 --- a/libyul/backends/evm/NoOutputAssembly.cpp +++ b/libyul/backends/evm/NoOutputAssembly.cpp @@ -175,7 +175,7 @@ void NoOutputAssembly::appendDataSize(std::vector const AbstractAssembly::SubID NoOutputAssembly::appendData(bytes const&) { - return 1; + return {1}; } diff --git a/test/cmdlineTests/asm_json_nested_structure/args b/test/cmdlineTests/asm_json_nested_structure/args new file mode 100644 index 000000000000..0602b0457a91 --- /dev/null +++ b/test/cmdlineTests/asm_json_nested_structure/args @@ -0,0 +1 @@ +--asm-json --pretty-json --strict-assembly \ No newline at end of file diff --git a/test/cmdlineTests/asm_json_nested_structure/input.yul b/test/cmdlineTests/asm_json_nested_structure/input.yul new file mode 100644 index 000000000000..b6db74e7e356 --- /dev/null +++ b/test/cmdlineTests/asm_json_nested_structure/input.yul @@ -0,0 +1,19 @@ +object "root" { + code { + // this produces non-zero PUSH #[$] assembly item values + mstore(42, datasize("sub1.sub1_2")) + mstore(42, datasize("sub2.sub2_2")) + } + object "sub1" { + code {} + object "sub1_2" { + code {} + } + } + object "sub2" { + code {} + object "sub2_2" { + code {} + } + } +} diff --git a/test/cmdlineTests/asm_json_nested_structure/output b/test/cmdlineTests/asm_json_nested_structure/output new file mode 100644 index 000000000000..e422d95ff0fe --- /dev/null +++ b/test/cmdlineTests/asm_json_nested_structure/output @@ -0,0 +1,101 @@ + +======= asm_json_nested_structure/input.yul (EVM) ======= + +EVM assembly: +{ + ".code": [ + { + "begin": 60, + "end": 83, + "name": "PUSH #[$]", + "source": -1, + "value": "000000000000000000000000000000000000000000000000ffffffffffffffff" + }, + { + "begin": 56, + "end": 58, + "name": "PUSH", + "source": -1, + "value": "2A" + }, + { + "begin": 49, + "end": 84, + "name": "MSTORE", + "source": -1 + }, + { + "begin": 108, + "end": 131, + "name": "PUSH #[$]", + "source": -1, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffe" + }, + { + "begin": 104, + "end": 106, + "name": "PUSH", + "source": -1, + "value": "2A" + }, + { + "begin": 97, + "end": 132, + "name": "MSTORE", + "source": -1 + }, + { + "begin": 25, + "end": 148, + "name": "STOP", + "source": -1 + } + ], + ".data": { + "0": { + ".code": [ + { + "begin": 182, + "end": 189, + "name": "STOP", + "source": -1 + } + ], + ".data": { + "0": { + ".code": [ + { + "begin": 233, + "end": 240, + "name": "STOP", + "source": -1 + } + ] + } + } + }, + "1": { + ".code": [ + { + "begin": 290, + "end": 297, + "name": "STOP", + "source": -1 + } + ], + ".data": { + "0": { + ".code": [ + { + "begin": 341, + "end": 348, + "name": "STOP", + "source": -1 + } + ] + } + } + } + }, + "sourceList": [] +} diff --git a/test/externalTests/solc-js/asm-json.js b/test/externalTests/solc-js/asm-json.js new file mode 100644 index 000000000000..3f3781d0b0b7 --- /dev/null +++ b/test/externalTests/solc-js/asm-json.js @@ -0,0 +1,45 @@ +const tape = require('tape'); +const fs = require('fs'); +const solc = require('../index.js'); + +tape('ASM Json output consistency', function (t) { + t.test('Nested structure', function(st) { + const testdir = 'test/'; + const output = JSON.parse(solc.compile(JSON.stringify({ + language: 'Solidity', + settings: { + viaIR: true, + outputSelection: { + '*': { + '*': ['evm.legacyAssembly'] + } + } + }, + sources: { + C: { + content: fs.readFileSync(testdir + 'code_access_runtime.sol', 'utf8') + } + } + }))); + st.ok(output); + + function containsTarget(obj, target) { + if (Array.isArray(obj)) + return obj.some(item => containsTarget(item, target)); + else if (typeof obj === 'object' && obj !== null) { + if (obj.name === target.name && obj.value === target.value) + return true; + return Object.values(obj).some(value => containsTarget(value, target)); + } + return false; + } + + // regression test that there is indeed a negative subassembly index in there + // and it is based on a 64 bit uint + const targetObject = { + "name": "PUSH #[$]", + "value": "000000000000000000000000000000000000000000000000ffffffffffffffff" + }; + st.equal(containsTarget(output, targetObject), true) + }); +}); diff --git a/test/externalTests/solc-js/solc-js.sh b/test/externalTests/solc-js/solc-js.sh index af325326c2db..f4e62b6da8ea 100755 --- a/test/externalTests/solc-js/solc-js.sh +++ b/test/externalTests/solc-js/solc-js.sh @@ -48,6 +48,9 @@ function solcjs_test printLog "Copying contracts..." cp -Rf "$SOLCJS_INPUT_DIR/DAO" test/ + printLog "Copying test with non-zero subassembly access" + cp -f "$TEST_DIR"/test/libsolidity/semanticTests/various/code_access_runtime.sol test/ + printLog "Copying SMTChecker tests..." # We do not copy all tests because that takes too long. cp -Rf "$TEST_DIR"/test/libsolidity/smtCheckerTests/external_calls test/smtCheckerTests/ diff --git a/test/libevmasm/Assembler.cpp b/test/libevmasm/Assembler.cpp index 6a41f7a7394c..c67527766b5d 100644 --- a/test/libevmasm/Assembler.cpp +++ b/test/libevmasm/Assembler.cpp @@ -109,11 +109,11 @@ BOOST_AUTO_TEST_CASE(all_assembly_items, *boost::unit_test::precondition(nonEOF( // PushSubSize auto sub = _assembly.appendSubroutine(_subAsmPtr); // PushSub - _assembly.pushSubroutineOffset(static_cast(sub.data())); + _assembly.pushSubroutineOffset(SubAssemblyID(sub.data())); // PushSubSize auto verbatim_sub = _assembly.appendSubroutine(_verbatimAsmPtr); // PushSub - _assembly.pushSubroutineOffset(static_cast(verbatim_sub.data())); + _assembly.pushSubroutineOffset(SubAssemblyID(verbatim_sub.data())); // PushDeployTimeAddress _assembly.append(PushDeployTimeAddress); // AssignImmutable. @@ -332,7 +332,7 @@ BOOST_AUTO_TEST_CASE(immutable, *boost::unit_test::precondition(nonEOF())) _assembly.appendImmutableAssignment("someOtherImmutable"); auto sub = _assembly.appendSubroutine(_subAsmPtr); - _assembly.pushSubroutineOffset(static_cast(sub.data())); + _assembly.pushSubroutineOffset(SubAssemblyID(sub.data())); checkCompilation(_assembly); @@ -418,11 +418,11 @@ BOOST_AUTO_TEST_CASE(subobject_encode_decode) assembly.appendSubroutine(subAsmPtr); subAsmPtr->appendSubroutine(subSubAsmPtr); - BOOST_CHECK(assembly.encodeSubPath({0}) == 0); - BOOST_REQUIRE_THROW(assembly.encodeSubPath({1}), solidity::evmasm::AssemblyException); - BOOST_REQUIRE_THROW(assembly.decodeSubPath(1), solidity::evmasm::AssemblyException); + BOOST_CHECK(assembly.encodeSubPath({SubAssemblyID{0}}).value == 0); + BOOST_REQUIRE_THROW(assembly.encodeSubPath({SubAssemblyID{1}}), solidity::langutil::InternalCompilerError); + BOOST_REQUIRE_THROW(assembly.decodeSubPath(SubAssemblyID{1}), solidity::evmasm::AssemblyException); - std::vector subPath{0, 0}; + std::vector subPath{{0}, {0}}; BOOST_CHECK(assembly.decodeSubPath(assembly.encodeSubPath(subPath)) == subPath); } diff --git a/test/libevmasm/Optimiser.cpp b/test/libevmasm/Optimiser.cpp index f4b7034de544..b530a638e899 100644 --- a/test/libevmasm/Optimiser.cpp +++ b/test/libevmasm/Optimiser.cpp @@ -1370,7 +1370,7 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies, *boost::unit_test::precondi sub->append(t4.pushTag()); sub->append(Instruction::JUMP); - size_t subId = static_cast(main.appendSubroutine(sub).data()); + SubAssemblyID subId{main.appendSubroutine(sub).data()}; main.append(t1.toSubAssemblyTag(subId)); main.append(t1.toSubAssemblyTag(subId)); main.append(u256(8));