diff options
author | chriseth <c@ethdev.com> | 2015-05-13 03:27:04 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2015-05-13 23:15:32 +0800 |
commit | cebc959ff3d7dab6a41833013ffe22728def3221 (patch) | |
tree | c997849fb951a132c06ffaf3af45b3f3958f3f12 /KnownState.cpp | |
parent | 2654daab2628181597bb4c35ae69ca378248f8ba (diff) | |
download | dexon-solidity-cebc959ff3d7dab6a41833013ffe22728def3221.tar.gz dexon-solidity-cebc959ff3d7dab6a41833013ffe22728def3221.tar.zst dexon-solidity-cebc959ff3d7dab6a41833013ffe22728def3221.zip |
Known state: store tags on stack as unions.
Diffstat (limited to 'KnownState.cpp')
-rw-r--r-- | KnownState.cpp | 92 |
1 files changed, 66 insertions, 26 deletions
diff --git a/KnownState.cpp b/KnownState.cpp index 5a70a74f..b84e656a 100644 --- a/KnownState.cpp +++ b/KnownState.cpp @@ -162,29 +162,41 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool /// Helper function for KnownState::reduceToCommonKnowledge, removes everything from /// _this which is not in or not equal to the value in _other. -template <class _Mapping, class _KeyType> void intersect( - _Mapping& _this, - _Mapping const& _other, - function<_KeyType(_KeyType)> const& _keyTrans = [](_KeyType _k) { return _k; } -) +template <class _Mapping> void intersect(_Mapping& _this, _Mapping const& _other) { for (auto it = _this.begin(); it != _this.end();) - if (_other.count(_keyTrans(it->first)) && _other.at(_keyTrans(it->first)) == it->second) + if (_other.count(it->first) && _other.at(it->first) == it->second) ++it; else it = _this.erase(it); } -template <class _Mapping> void intersect(_Mapping& _this, _Mapping const& _other) -{ - intersect<_Mapping, ExpressionClasses::Id>(_this, _other, [](ExpressionClasses::Id _k) { return _k; }); -} - void KnownState::reduceToCommonKnowledge(KnownState const& _other) { int stackDiff = m_stackHeight - _other.m_stackHeight; - function<int(int)> stackKeyTransform = [=](int _key) -> int { return _key - stackDiff; }; - intersect(m_stackElements, _other.m_stackElements, stackKeyTransform); + for (auto it = m_stackElements.begin(); it != m_stackElements.end();) + if (_other.m_stackElements.count(it->first - stackDiff)) + { + Id other = _other.m_stackElements.at(it->first - stackDiff); + if (it->second == other) + ++it; + else + { + set<u256> theseTags = tagsInExpression(it->second); + set<u256> otherTags = tagsInExpression(other); + if (!theseTags.empty() && !otherTags.empty()) + { + theseTags.insert(otherTags.begin(), otherTags.end()); + it->second = tagUnion(theseTags); + ++it; + } + else + it = m_stackElements.erase(it); + } + } + else + it = m_stackElements.erase(it); + // Use the smaller stack height. Essential to terminate in case of loops. if (m_stackHeight > _other.m_stackHeight) { @@ -201,10 +213,15 @@ void KnownState::reduceToCommonKnowledge(KnownState const& _other) bool KnownState::operator==(const KnownState& _other) const { - return m_storageContent == _other.m_storageContent && - m_memoryContent == _other.m_memoryContent && - m_stackHeight == _other.m_stackHeight && - m_stackElements == _other.m_stackElements; + if (m_storageContent != _other.m_storageContent || m_memoryContent != _other.m_memoryContent) + return false; + int stackDiff = m_stackHeight - _other.m_stackHeight; + auto thisIt = m_stackElements.cbegin(); + auto otherIt = _other.m_stackElements.cbegin(); + for (; thisIt != m_stackElements.cend() && otherIt != _other.m_stackElements.cend(); ++thisIt, ++otherIt) + if (thisIt->first - stackDiff != otherIt->first || thisIt->second != otherIt->second) + return false; + return (thisIt == m_stackElements.cend() && otherIt == _other.m_stackElements.cend()); } ExpressionClasses::Id KnownState::stackElement(int _stackHeight, SourceLocation const& _location) @@ -212,18 +229,17 @@ ExpressionClasses::Id KnownState::stackElement(int _stackHeight, SourceLocation if (m_stackElements.count(_stackHeight)) return m_stackElements.at(_stackHeight); // Stack element not found (not assigned yet), create new unknown equivalence class. - //@todo check that we do not infer incorrect equivalences when the stack is cleared partially - //in between. - return m_stackElements[_stackHeight] = initialStackElement(_stackHeight, _location); + return m_stackElements[_stackHeight] = + m_expressionClasses->find(AssemblyItem(UndefinedItem, _stackHeight, _location)); } -ExpressionClasses::Id KnownState::initialStackElement( - int _stackHeight, - SourceLocation const& _location -) +void KnownState::clearTagUnions() { - // This is a special assembly item that refers to elements pre-existing on the initial stack. - return m_expressionClasses->find(AssemblyItem(UndefinedItem, u256(_stackHeight), _location)); + for (auto it = m_stackElements.begin(); it != m_stackElements.end();) + if (m_tagUnions.left.count(it->second)) + it = m_stackElements.erase(it); + else + ++it; } void KnownState::setStackElement(int _stackHeight, Id _class) @@ -352,3 +368,27 @@ KnownState::Id KnownState::applySha3( return m_knownSha3Hashes[arguments] = v; } +set<u256> KnownState::tagsInExpression(KnownState::Id _expressionId) +{ + if (m_tagUnions.left.count(_expressionId)) + return m_tagUnions.left.at(_expressionId); + // Might be a tag, then return the set of itself. + ExpressionClasses::Expression expr = m_expressionClasses->representative(_expressionId); + if (expr.item && expr.item->type() == PushTag) + return set<u256>({expr.item->data()}); + else + return set<u256>(); +} + +KnownState::Id KnownState::tagUnion(set<u256> _tags) +{ + if (m_tagUnions.right.count(_tags)) + return m_tagUnions.right.at(_tags); + else + { + Id id = m_expressionClasses->newClass(SourceLocation()); + m_tagUnions.right.insert(make_pair(_tags, id)); + return id; + } +} + |