new container

This commit is contained in:
Daniel Kirchner 2022-12-20 16:35:23 +01:00
parent 5fd0eae74c
commit 321bef463f
9 changed files with 105 additions and 35 deletions

View File

@ -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;

View File

@ -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{};
};

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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++);

View File

@ -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;

View File

@ -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,

View File

@ -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;
}