mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
new container
This commit is contained in:
parent
5fd0eae74c
commit
321bef463f
@ -583,29 +583,34 @@ LinkerObject const& Assembly::assemble() const
|
||||
};
|
||||
if (eof)
|
||||
{
|
||||
bool needsTypeSection = m_codeSections.size() > 1;
|
||||
bool needsTypeSection = true; // m_codeSections.size() > 1;
|
||||
// TODO: empty data is disallowed
|
||||
ret.bytecode.push_back(0xef);
|
||||
ret.bytecode.push_back(0x00);
|
||||
ret.bytecode.push_back(0x01); // version 1
|
||||
if (needsTypeSection)
|
||||
{
|
||||
ret.bytecode.push_back(0x03); // kind=type
|
||||
ret.bytecode.push_back(0x01); // kind=type
|
||||
ret.bytecode.push_back(0x00); // length of type section
|
||||
ret.bytecode.push_back(0x00);
|
||||
toBigEndian(m_codeSections.size() * 2, bytesRef(&ret.bytecode.back() + 1 - 2, 2));
|
||||
toBigEndian(m_codeSections.size() * 4, bytesRef(&ret.bytecode.back() + 1 - 2, 2));
|
||||
}
|
||||
ret.bytecode.push_back(0x02); // kind=code
|
||||
ret.bytecode.push_back(0x00); // placeholder for number of code sections
|
||||
ret.bytecode.push_back(0x00);
|
||||
{
|
||||
bytesRef numCodeSections(&ret.bytecode.back() + 1 - 2, 2);
|
||||
toBigEndian(m_codeSections.size(), numCodeSections);
|
||||
}
|
||||
for (auto const& codeSection: m_codeSections)
|
||||
{
|
||||
(void) codeSection;
|
||||
ret.bytecode.push_back(0x01); // kind=code
|
||||
codeSectionSizeOffsets.emplace_back(ret.bytecode.size());
|
||||
ret.bytecode.push_back(0x00); // placeholder for length of code
|
||||
ret.bytecode.push_back(0x00);
|
||||
}
|
||||
if (bytesRequiredForDataAndSubsUpperBound > 0)
|
||||
{
|
||||
ret.bytecode.push_back(0x02); // kind=data
|
||||
ret.bytecode.push_back(0x03); // kind=data
|
||||
dataSectionSizeOffset = ret.bytecode.size();
|
||||
ret.bytecode.push_back(0x00); // length of data
|
||||
ret.bytecode.push_back(0x00);
|
||||
@ -617,6 +622,10 @@ LinkerObject const& Assembly::assemble() const
|
||||
{
|
||||
ret.bytecode.push_back(codeSection.inputs);
|
||||
ret.bytecode.push_back(codeSection.outputs);
|
||||
ret.bytecode.push_back(0x00); // placeholder for max stack height
|
||||
ret.bytecode.push_back(0x00);
|
||||
// TODO: check why cast is necessary.
|
||||
toBigEndian(size_t(codeSection.maxStackHeight), bytesRef(&ret.bytecode.back() + 1 - 2, 2));
|
||||
}
|
||||
}
|
||||
|
||||
@ -903,13 +912,6 @@ LinkerObject const& Assembly::assemble() const
|
||||
|
||||
ret.bytecode += m_auxiliaryData;
|
||||
|
||||
// TODO: remove this when transitioning to unified spec headers
|
||||
if (eof && bytesRequiredForDataAndSubsUpperBound > 0 && ret.bytecode.size() == dataStart)
|
||||
{
|
||||
// We have committed to a data section, but not actually needed it, so create a fake one.
|
||||
ret.bytecode.push_back(0);
|
||||
}
|
||||
|
||||
for (unsigned pos: sizeRef)
|
||||
{
|
||||
bytesRef r(ret.bytecode.data() + pos, bytesPerDataRef);
|
||||
@ -919,16 +921,9 @@ LinkerObject const& Assembly::assemble() const
|
||||
auto dataLength = ret.bytecode.size() - dataStart;
|
||||
if (eof)
|
||||
{
|
||||
assertThrow(
|
||||
bytesRequiredForDataAndSubsUpperBound >= dataLength,
|
||||
AssemblyException,
|
||||
"More data than expected. " + to_string(dataLength) + " > " + to_string(bytesRequiredForDataUpperBound)
|
||||
);
|
||||
if (bytesRequiredForDataAndSubsUpperBound > 0)
|
||||
{
|
||||
assertThrow(0 < dataLength && dataLength <= 0xffff, AssemblyException, "Invalid data section size.");
|
||||
setDataSectionSize(dataLength);
|
||||
}
|
||||
assertThrow(bytesRequiredForDataAndSubsUpperBound >= dataLength, AssemblyException, "More data than expected. " + to_string(dataLength) + " > " + to_string(bytesRequiredForDataUpperBound));
|
||||
assertThrow(dataLength <= 0xffff, AssemblyException, "Invalid data section size.");
|
||||
setDataSectionSize(dataLength);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -77,14 +77,19 @@ public:
|
||||
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); }
|
||||
uint16_t createFunction(uint8_t _args, uint8_t _rets)
|
||||
uint16_t createFunction(uint8_t _args, uint8_t _rets, uint16_t _maxStackHeight)
|
||||
{
|
||||
size_t functionID = m_codeSections.size();
|
||||
assertThrow(functionID < 1024, AssemblyException, "Too many functions.");
|
||||
assertThrow(m_currentCodeSection == 0, AssemblyException, "Functions need to be declared from the main block.");
|
||||
m_codeSections.emplace_back(CodeSection{_args, _rets, {}});
|
||||
m_codeSections.emplace_back(CodeSection{_args, _rets, _maxStackHeight, {}});
|
||||
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)
|
||||
{
|
||||
assertThrow(m_currentCodeSection == 0, AssemblyException, "Atempted to begin a function before ending the last one.");
|
||||
@ -209,6 +214,7 @@ public:
|
||||
{
|
||||
uint8_t inputs = 0;
|
||||
uint8_t outputs = 0;
|
||||
uint16_t maxStackHeight = 0;
|
||||
AssemblyItems items{};
|
||||
};
|
||||
|
||||
|
@ -101,7 +101,8 @@ public:
|
||||
/// 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 FunctionID createFunction(uint8_t _args, uint8_t _rets) = 0;
|
||||
virtual FunctionID createFunction(uint8_t _args, uint8_t _rets, uint16_t _maxStackHeight) = 0;
|
||||
virtual void setMaxStackHeight(FunctionID _functionID, uint16_t _maxStackHeight) = 0;
|
||||
virtual void beginFunction(FunctionID _functionID) = 0;
|
||||
virtual void endFunction() = 0;
|
||||
|
||||
|
@ -146,9 +146,14 @@ pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::
|
||||
return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
|
||||
}
|
||||
|
||||
AbstractAssembly::FunctionID EthAssemblyAdapter::createFunction(uint8_t _args, uint8_t _rets)
|
||||
AbstractAssembly::FunctionID EthAssemblyAdapter::createFunction(uint8_t _args, uint8_t _rets, uint16_t _maxStackArgs)
|
||||
{
|
||||
return m_assembly.createFunction(_args, _rets);
|
||||
return m_assembly.createFunction(_args, _rets, _maxStackArgs);
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::setMaxStackHeight(FunctionID _functionID, uint16_t _maxStackHeight)
|
||||
{
|
||||
m_assembly.setMaxStackHeight(_functionID, _maxStackHeight);
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::beginFunction(AbstractAssembly::FunctionID _functionID)
|
||||
|
@ -56,7 +56,8 @@ public:
|
||||
void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override;
|
||||
void appendAssemblySize() 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) override;
|
||||
AbstractAssembly::FunctionID createFunction(uint8_t _args, uint8_t _rets, uint16_t _maxStackHeight) override;
|
||||
void setMaxStackHeight(FunctionID _functionID, uint16_t _maxStackHeight) override;
|
||||
void beginFunction(AbstractAssembly::FunctionID _functionID) override;
|
||||
void endFunction() override;
|
||||
void appendFunctionCall(FunctionID _functionID) override;
|
||||
|
@ -104,7 +104,7 @@ pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::cr
|
||||
return {};
|
||||
}
|
||||
|
||||
AbstractAssembly::FunctionID NoOutputAssembly::createFunction(uint8_t _args, uint8_t _rets)
|
||||
AbstractAssembly::FunctionID NoOutputAssembly::createFunction(uint8_t _args, uint8_t _rets, uint16_t)
|
||||
{
|
||||
yulAssert(m_context->numFunctions <= std::numeric_limits<AbstractAssembly::FunctionID>::max());
|
||||
AbstractAssembly::FunctionID id = static_cast<AbstractAssembly::FunctionID>(m_context->numFunctions++);
|
||||
|
@ -74,7 +74,8 @@ public:
|
||||
|
||||
void appendAssemblySize() 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) override;
|
||||
FunctionID createFunction(uint8_t _args, uint8_t rets, uint16_t _maxStackHeight) override;
|
||||
void setMaxStackHeight(AbstractAssembly::FunctionID, uint16_t) override {}
|
||||
void beginFunction(FunctionID) override;
|
||||
void endFunction() override;
|
||||
void appendFunctionCall(FunctionID _functionID) override;
|
||||
|
@ -40,6 +40,54 @@ using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
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(
|
||||
AbstractAssembly& _assembly,
|
||||
AsmAnalysisInfo& _analysisInfo,
|
||||
@ -55,6 +103,8 @@ vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
|
||||
StackLayout stackLayout = StackLayoutGenerator::run(*dfg);
|
||||
|
||||
if (dfg->useFunctions)
|
||||
{
|
||||
_assembly.setMaxStackHeight(0, getMaxStackHeight(*dfg->entry, stackLayout));
|
||||
for (Scope::Function const* function: dfg->functions)
|
||||
{
|
||||
auto const& info = dfg->functionInfo.at(function);
|
||||
@ -62,10 +112,12 @@ vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
|
||||
yulAssert(info.returnVariables.size() <= 0xFF);
|
||||
auto functionID = _assembly.createFunction(
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
OptimizedEVMCodeTransform optimizedCodeTransform(
|
||||
_assembly,
|
||||
|
@ -78,10 +78,18 @@ public:
|
||||
case uint8_t(0x00): // terminator
|
||||
stop = true;
|
||||
break;
|
||||
case uint8_t(0x01): // code section
|
||||
i += 2; // skip code size section
|
||||
case uint8_t(0x01): // type section
|
||||
i += 2; // skip type size section
|
||||
break;
|
||||
case uint8_t(0x02): // data section
|
||||
case uint8_t(0x02): // code section
|
||||
{
|
||||
bytesRef numCodeSectionsRef(&bytecode[i + 1], 2);
|
||||
size_t numCodeSections = fromBigEndian<size_t>(numCodeSectionsRef);
|
||||
i += numCodeSections * 2 + 2; // skip code section header
|
||||
break;
|
||||
}
|
||||
case uint8_t(0x03): // data section
|
||||
{
|
||||
auto dataSizeOffset = i + 1;
|
||||
bytesRef dataSizeRef(&bytecode[dataSizeOffset], 2);
|
||||
size_t dataSize = fromBigEndian<size_t>(dataSizeRef);
|
||||
@ -89,6 +97,7 @@ public:
|
||||
i += 2; // skip data size section
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (stop)
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user