mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Disable deduplication to align with evmone validation.
This commit is contained in:
parent
0d7d0bfa78
commit
77567d32f4
@ -1046,7 +1046,7 @@ jobs:
|
|||||||
name: Build evmone based on EOF branch
|
name: Build evmone based on EOF branch
|
||||||
command: |
|
command: |
|
||||||
( cd /usr/src; \
|
( cd /usr/src; \
|
||||||
git clone --branch="eof-functions" --recurse-submodules https://github.com/ethereum/evmone.git; \
|
git clone --branch="eof" --recurse-submodules https://github.com/ethereum/evmone.git; \
|
||||||
cd evmone; \
|
cd evmone; \
|
||||||
sed -i -e 's/GNULIKE TRUE/GNULIKE FALSE/g' cmake/cable/CableCompilerSettings.cmake; \
|
sed -i -e 's/GNULIKE TRUE/GNULIKE FALSE/g' cmake/cable/CableCompilerSettings.cmake; \
|
||||||
mkdir build; \
|
mkdir build; \
|
||||||
|
@ -408,7 +408,7 @@ map<u256, u256> const& Assembly::optimiseInternal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This only modifies PushTags, we have to run again to actually remove code.
|
// This only modifies PushTags, we have to run again to actually remove code.
|
||||||
if (_settings.runDeduplicate)
|
if (_settings.runDeduplicate && !m_eofVersion.has_value())
|
||||||
for (auto& section: m_codeSections)
|
for (auto& section: m_codeSections)
|
||||||
{
|
{
|
||||||
BlockDeduplicator deduplicator{section.items};
|
BlockDeduplicator deduplicator{section.items};
|
||||||
@ -500,6 +500,61 @@ map<u256, u256> const& Assembly::optimiseInternal(
|
|||||||
return *m_tagReplacements;
|
return *m_tagReplacements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
uint16_t calcMaxStackHeight(vector<AssemblyItem> const& _items, uint16_t _args)
|
||||||
|
{
|
||||||
|
uint16_t maxStackHeight = 0;
|
||||||
|
std::stack<size_t> worklist;
|
||||||
|
std::vector<int32_t> stack_heights(_items.size(), -1);
|
||||||
|
stack_heights[0] = _args;
|
||||||
|
worklist.push(0u);
|
||||||
|
while (!worklist.empty())
|
||||||
|
{
|
||||||
|
size_t i = worklist.top();
|
||||||
|
worklist.pop();
|
||||||
|
AssemblyItem const& item = _items.at(i);
|
||||||
|
size_t stack_height_change = item.deposit();
|
||||||
|
ptrdiff_t stackHeight = stack_heights.at(i);
|
||||||
|
assertThrow(stackHeight != -1, AssemblyException, "");
|
||||||
|
|
||||||
|
std::vector<size_t> successors;
|
||||||
|
|
||||||
|
if (
|
||||||
|
item.type() != RelativeJump &&
|
||||||
|
!(item.type() == Operation && SemanticInformation::terminatesControlFlow(item.instruction())) &&
|
||||||
|
item.type() != RetF
|
||||||
|
)
|
||||||
|
{
|
||||||
|
assertThrow(i < _items.size() - 1, AssemblyException, "No terminating instruction.");
|
||||||
|
successors.emplace_back(i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.type() == RelativeJump || item.type() == ConditionalRelativeJump)
|
||||||
|
{
|
||||||
|
auto it = std::find(_items.begin(), _items.end(), item.tag());
|
||||||
|
assertThrow(it != _items.end(), AssemblyException, "Tag not found.");
|
||||||
|
successors.emplace_back(static_cast<size_t>(std::distance(_items.begin(), it)));
|
||||||
|
}
|
||||||
|
|
||||||
|
maxStackHeight = std::max(maxStackHeight, static_cast<uint16_t>(stackHeight + static_cast<ptrdiff_t>(item.maxStackHeightDelta())));
|
||||||
|
stackHeight += static_cast<ptrdiff_t>(stack_height_change);
|
||||||
|
|
||||||
|
for (size_t s: successors)
|
||||||
|
{
|
||||||
|
if (stack_heights.at(s) == -1)
|
||||||
|
{
|
||||||
|
stack_heights[s] = static_cast<int32_t>(stackHeight);
|
||||||
|
worklist.push(s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
assertThrow(stack_heights.at(s) == stackHeight, AssemblyException, "Stack height mismatch.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxStackHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LinkerObject const& Assembly::assemble() const
|
LinkerObject const& Assembly::assemble() const
|
||||||
{
|
{
|
||||||
assertThrow(!m_invalid, AssemblyException, "Attempted to assemble invalid Assembly object.");
|
assertThrow(!m_invalid, AssemblyException, "Attempted to assemble invalid Assembly object.");
|
||||||
@ -627,7 +682,7 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
{
|
{
|
||||||
ret.bytecode.push_back(codeSection.inputs);
|
ret.bytecode.push_back(codeSection.inputs);
|
||||||
ret.bytecode.push_back(codeSection.outputs);
|
ret.bytecode.push_back(codeSection.outputs);
|
||||||
appendBigEndianUint16(ret.bytecode, codeSection.maxStackHeight);
|
appendBigEndianUint16(ret.bytecode, calcMaxStackHeight(codeSection.items, codeSection.inputs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,19 +77,14 @@ public:
|
|||||||
AssemblyItem newData(bytes const& _data) { util::h256 h(util::keccak256(util::asString(_data))); m_data[h] = _data; return AssemblyItem(PushData, h); }
|
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); }
|
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); }
|
AssemblyItem newSub(AssemblyPointer const& _sub) { m_subs.push_back(_sub); return AssemblyItem(PushSub, m_subs.size() - 1); }
|
||||||
uint16_t createFunction(uint8_t _args, uint8_t _rets, uint16_t _maxStackHeight)
|
uint16_t createFunction(uint8_t _args, uint8_t _rets)
|
||||||
{
|
{
|
||||||
size_t functionID = m_codeSections.size();
|
size_t functionID = m_codeSections.size();
|
||||||
assertThrow(functionID < 1024, AssemblyException, "Too many functions.");
|
assertThrow(functionID < 1024, AssemblyException, "Too many functions.");
|
||||||
assertThrow(m_currentCodeSection == 0, AssemblyException, "Functions need to be declared from the main block.");
|
assertThrow(m_currentCodeSection == 0, AssemblyException, "Functions need to be declared from the main block.");
|
||||||
m_codeSections.emplace_back(CodeSection{_args, _rets, _maxStackHeight, {}});
|
m_codeSections.emplace_back(CodeSection{_args, _rets, {}});
|
||||||
return static_cast<uint16_t>(functionID);
|
return static_cast<uint16_t>(functionID);
|
||||||
}
|
}
|
||||||
void setMaxStackHeight(uint16_t _functionID, uint16_t _maxStackHeight)
|
|
||||||
{
|
|
||||||
assertThrow(_functionID < m_codeSections.size(), AssemblyException, "Attempt to set the maximum stack height of an undeclared function.");
|
|
||||||
m_codeSections.at(_functionID).maxStackHeight = _maxStackHeight;
|
|
||||||
}
|
|
||||||
void beginFunction(uint16_t _functionID)
|
void beginFunction(uint16_t _functionID)
|
||||||
{
|
{
|
||||||
assertThrow(m_currentCodeSection == 0, AssemblyException, "Atempted to begin a function before ending the last one.");
|
assertThrow(m_currentCodeSection == 0, AssemblyException, "Atempted to begin a function before ending the last one.");
|
||||||
@ -214,7 +209,6 @@ public:
|
|||||||
{
|
{
|
||||||
uint8_t inputs = 0;
|
uint8_t inputs = 0;
|
||||||
uint8_t outputs = 0;
|
uint8_t outputs = 0;
|
||||||
uint16_t maxStackHeight = 0;
|
|
||||||
AssemblyItems items{};
|
AssemblyItems items{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -116,6 +116,21 @@ void AssemblyItem::setPushTagSubIdAndTag(size_t _subId, size_t _tag)
|
|||||||
setData(data);
|
setData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t AssemblyItem::maxStackHeightDelta() const
|
||||||
|
{
|
||||||
|
if (m_type == AssignImmutable)
|
||||||
|
{
|
||||||
|
assertThrow(m_immutableOccurrences.has_value(), util::Exception, "");
|
||||||
|
if (*m_immutableOccurrences == 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return (*m_immutableOccurrences - 1) * 2 + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return deposit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t AssemblyItem::bytesRequired(size_t _addressLength, Precision _precision) const
|
size_t AssemblyItem::bytesRequired(size_t _addressLength, Precision _precision) const
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
|
@ -187,6 +187,7 @@ public:
|
|||||||
size_t arguments() const;
|
size_t arguments() const;
|
||||||
size_t returnValues() const;
|
size_t returnValues() const;
|
||||||
size_t deposit() const { return returnValues() - arguments(); }
|
size_t deposit() const { return returnValues() - arguments(); }
|
||||||
|
size_t maxStackHeightDelta() const;
|
||||||
|
|
||||||
/// @returns true if the assembly item can be used in a functional context.
|
/// @returns true if the assembly item can be used in a functional context.
|
||||||
bool canBeFunctional() const;
|
bool canBeFunctional() const;
|
||||||
|
@ -101,8 +101,7 @@ public:
|
|||||||
/// Creates a new sub-assembly, which can be referenced using dataSize and dataOffset.
|
/// Creates a new sub-assembly, which can be referenced using dataSize and dataOffset.
|
||||||
virtual std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::optional<uint8_t> _eofVersion, std::string _name = "") = 0;
|
virtual std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::optional<uint8_t> _eofVersion, std::string _name = "") = 0;
|
||||||
|
|
||||||
virtual FunctionID createFunction(uint8_t _args, uint8_t _rets, uint16_t _maxStackHeight) = 0;
|
virtual FunctionID createFunction(uint8_t _args, uint8_t _rets) = 0;
|
||||||
virtual void setMaxStackHeight(FunctionID _functionID, uint16_t _maxStackHeight) = 0;
|
|
||||||
virtual void beginFunction(FunctionID _functionID) = 0;
|
virtual void beginFunction(FunctionID _functionID) = 0;
|
||||||
virtual void endFunction() = 0;
|
virtual void endFunction() = 0;
|
||||||
|
|
||||||
|
@ -146,14 +146,9 @@ pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::
|
|||||||
return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
|
return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractAssembly::FunctionID EthAssemblyAdapter::createFunction(uint8_t _args, uint8_t _rets, uint16_t _maxStackArgs)
|
AbstractAssembly::FunctionID EthAssemblyAdapter::createFunction(uint8_t _args, uint8_t _rets)
|
||||||
{
|
{
|
||||||
return m_assembly.createFunction(_args, _rets, _maxStackArgs);
|
return m_assembly.createFunction(_args, _rets);
|
||||||
}
|
|
||||||
|
|
||||||
void EthAssemblyAdapter::setMaxStackHeight(FunctionID _functionID, uint16_t _maxStackHeight)
|
|
||||||
{
|
|
||||||
m_assembly.setMaxStackHeight(_functionID, _maxStackHeight);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EthAssemblyAdapter::beginFunction(AbstractAssembly::FunctionID _functionID)
|
void EthAssemblyAdapter::beginFunction(AbstractAssembly::FunctionID _functionID)
|
||||||
|
@ -56,8 +56,7 @@ public:
|
|||||||
void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override;
|
void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override;
|
||||||
void appendAssemblySize() override;
|
void appendAssemblySize() override;
|
||||||
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::optional<uint8_t> _eofVersion, std::string _name = {}) override;
|
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::optional<uint8_t> _eofVersion, std::string _name = {}) override;
|
||||||
AbstractAssembly::FunctionID createFunction(uint8_t _args, uint8_t _rets, uint16_t _maxStackHeight) override;
|
AbstractAssembly::FunctionID createFunction(uint8_t _args, uint8_t _rets) override;
|
||||||
void setMaxStackHeight(FunctionID _functionID, uint16_t _maxStackHeight) override;
|
|
||||||
void beginFunction(AbstractAssembly::FunctionID _functionID) override;
|
void beginFunction(AbstractAssembly::FunctionID _functionID) override;
|
||||||
void endFunction() override;
|
void endFunction() override;
|
||||||
void appendFunctionCall(FunctionID _functionID) override;
|
void appendFunctionCall(FunctionID _functionID) override;
|
||||||
|
@ -104,7 +104,7 @@ pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::cr
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractAssembly::FunctionID NoOutputAssembly::createFunction(uint8_t _args, uint8_t _rets, uint16_t)
|
AbstractAssembly::FunctionID NoOutputAssembly::createFunction(uint8_t _args, uint8_t _rets)
|
||||||
{
|
{
|
||||||
yulAssert(m_context->numFunctions <= std::numeric_limits<AbstractAssembly::FunctionID>::max());
|
yulAssert(m_context->numFunctions <= std::numeric_limits<AbstractAssembly::FunctionID>::max());
|
||||||
AbstractAssembly::FunctionID id = static_cast<AbstractAssembly::FunctionID>(m_context->numFunctions++);
|
AbstractAssembly::FunctionID id = static_cast<AbstractAssembly::FunctionID>(m_context->numFunctions++);
|
||||||
|
@ -74,8 +74,7 @@ public:
|
|||||||
|
|
||||||
void appendAssemblySize() override;
|
void appendAssemblySize() override;
|
||||||
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::optional<uint8_t> _eofVersion, std::string _name = "") override;
|
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::optional<uint8_t> _eofVersion, std::string _name = "") override;
|
||||||
FunctionID createFunction(uint8_t _args, uint8_t rets, uint16_t _maxStackHeight) override;
|
FunctionID createFunction(uint8_t _args, uint8_t _rets) override;
|
||||||
void setMaxStackHeight(AbstractAssembly::FunctionID, uint16_t) override {}
|
|
||||||
void beginFunction(FunctionID) override;
|
void beginFunction(FunctionID) override;
|
||||||
void endFunction() override;
|
void endFunction() override;
|
||||||
void appendFunctionCall(FunctionID _functionID) override;
|
void appendFunctionCall(FunctionID _functionID) override;
|
||||||
|
@ -40,55 +40,6 @@ using namespace solidity;
|
|||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
uint16_t getMaxStackHeight(CFG::BasicBlock const& _block, StackLayout const& _stackLayout)
|
|
||||||
{
|
|
||||||
size_t maxStackHeight = 0;
|
|
||||||
|
|
||||||
std::list<CFG::BasicBlock const*> toVisit;
|
|
||||||
std::set<CFG::BasicBlock const*> visited;
|
|
||||||
toVisit.push_back(&_block);
|
|
||||||
|
|
||||||
while (!toVisit.empty())
|
|
||||||
{
|
|
||||||
CFG::BasicBlock const* block = toVisit.back();
|
|
||||||
toVisit.pop_back();
|
|
||||||
if (!visited.insert(block).second)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto& blockInfo = _stackLayout.blockInfos.at(block);
|
|
||||||
|
|
||||||
maxStackHeight = std::max(maxStackHeight, blockInfo.entryLayout.size());
|
|
||||||
for (auto const& operation: block->operations)
|
|
||||||
{
|
|
||||||
size_t entryLayout = _stackLayout.operationEntryLayout.at(&operation).size();
|
|
||||||
maxStackHeight = std::max(maxStackHeight, entryLayout);
|
|
||||||
size_t exitLayout = entryLayout - operation.input.size() + operation.output.size();
|
|
||||||
maxStackHeight = std::max(maxStackHeight, exitLayout);
|
|
||||||
}
|
|
||||||
maxStackHeight = std::max(maxStackHeight, blockInfo.exitLayout.size());
|
|
||||||
|
|
||||||
std::visit(util::GenericVisitor{
|
|
||||||
[&](CFG::BasicBlock::MainExit const&) {},
|
|
||||||
[&](CFG::BasicBlock::Jump const& _jump) { toVisit.emplace_back(_jump.target); },
|
|
||||||
[&](CFG::BasicBlock::ConditionalJump const& _conditionalJump)
|
|
||||||
{
|
|
||||||
toVisit.emplace_back(_conditionalJump.zero);
|
|
||||||
toVisit.emplace_back(_conditionalJump.nonZero);
|
|
||||||
},
|
|
||||||
[&](CFG::BasicBlock::FunctionReturn const&) {},
|
|
||||||
[&](CFG::BasicBlock::Terminated const&) {}
|
|
||||||
}, block->exit);
|
|
||||||
}
|
|
||||||
|
|
||||||
yulAssert(maxStackHeight <= 0xFFFF);
|
|
||||||
return static_cast<uint16_t>(maxStackHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
|
vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
|
||||||
AbstractAssembly& _assembly,
|
AbstractAssembly& _assembly,
|
||||||
AsmAnalysisInfo& _analysisInfo,
|
AsmAnalysisInfo& _analysisInfo,
|
||||||
@ -105,7 +56,6 @@ vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
|
|||||||
|
|
||||||
if (dfg->useFunctions)
|
if (dfg->useFunctions)
|
||||||
{
|
{
|
||||||
_assembly.setMaxStackHeight(0, getMaxStackHeight(*dfg->entry, stackLayout));
|
|
||||||
for (Scope::Function const* function: dfg->functions)
|
for (Scope::Function const* function: dfg->functions)
|
||||||
{
|
{
|
||||||
auto const& info = dfg->functionInfo.at(function);
|
auto const& info = dfg->functionInfo.at(function);
|
||||||
@ -113,8 +63,7 @@ vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
|
|||||||
yulAssert(info.returnVariables.size() <= 0xFF);
|
yulAssert(info.returnVariables.size() <= 0xFF);
|
||||||
auto functionID = _assembly.createFunction(
|
auto functionID = _assembly.createFunction(
|
||||||
static_cast<uint8_t>(info.parameters.size()),
|
static_cast<uint8_t>(info.parameters.size()),
|
||||||
static_cast<uint8_t>(info.returnVariables.size()),
|
static_cast<uint8_t>(info.returnVariables.size())
|
||||||
getMaxStackHeight(*info.entry, stackLayout)
|
|
||||||
);
|
);
|
||||||
_builtinContext.functionIDs[function] = functionID;
|
_builtinContext.functionIDs[function] = functionID;
|
||||||
}
|
}
|
||||||
@ -162,7 +111,11 @@ void OptimizedEVMCodeTransform::operator()(CFG::FunctionCall const& _call)
|
|||||||
{
|
{
|
||||||
m_assembly.setSourceLocation(originLocationOf(_call));
|
m_assembly.setSourceLocation(originLocationOf(_call));
|
||||||
if (m_dfg.useFunctions)
|
if (m_dfg.useFunctions)
|
||||||
|
{
|
||||||
m_assembly.appendFunctionCall(m_builtinContext.functionIDs.at(&_call.function.get()));
|
m_assembly.appendFunctionCall(m_builtinContext.functionIDs.at(&_call.function.get()));
|
||||||
|
if (!_call.canContinue)
|
||||||
|
m_assembly.appendInstruction(evmasm::Instruction::INVALID);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
m_assembly.appendJumpTo(
|
m_assembly.appendJumpTo(
|
||||||
getFunctionLabel(_call.function),
|
getFunctionLabel(_call.function),
|
||||||
|
Loading…
Reference in New Issue
Block a user