#include <libyul/backends/evm/EVMObjectCompiler.h>
#include <libyul/backends/evm/EVMCodeTransform.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/backends/evm/OptimizedEVMCodeTransform.h>
#include <libyul/optimiser/FunctionCallFinder.h>
#include <libyul/Object.h>
#include <libyul/Exceptions.h>
#include <boost/algorithm/string.hpp>
using namespace solidity::yul;
using namespace std;
void EVMObjectCompiler::compile(Object& _object, AbstractAssembly& _assembly, EVMDialect const& _dialect, bool _optimize)
{
EVMObjectCompiler compiler(_assembly, _dialect);
compiler.run(_object, _optimize);
}
void EVMObjectCompiler::run(Object& _object, bool _optimize)
{
BuiltinContext context;
context.currentObject = &_object;
for (auto const& subNode: _object.subObjects)
if (auto* subObject = dynamic_cast<Object*>(subNode.get()))
{
bool isCreation = !boost::ends_with(subObject->name.str(), "_deployed");
auto subAssemblyAndID = m_assembly.createSubAssembly(isCreation, subObject->name.str());
context.subIDs[subObject->name] = subAssemblyAndID.second;
subObject->subId = subAssemblyAndID.second;
compile(*subObject, *subAssemblyAndID.first, m_dialect, _optimize);
}
else
{
Data const& data = dynamic_cast<Data const&>(*subNode);
if (data.name.str() == Object::metadataName())
m_assembly.appendToAuxiliaryData(data.data);
else
context.subIDs[data.name] = m_assembly.appendData(data.data);
}
yulAssert(_object.analysisInfo, "No analysis info.");
yulAssert(_object.code, "No code.");
if (_optimize && m_dialect.evmVersion().canOverchargeGasForCall())
{
auto stackErrors = OptimizedEVMCodeTransform::run(
m_assembly,
*_object.analysisInfo,
*_object.code,
m_dialect,
context,
OptimizedEVMCodeTransform::UseNamedLabels::ForFirstFunctionOfEachName
);
if (!stackErrors.empty())
{
vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run(
*_object.code,
"memoryguard"_yulstring
);
auto stackError = stackErrors.front();
string msg = stackError.comment() ? *stackError.comment() : "";
if (memoryGuardCalls.empty())
msg += "\nNo memoryguard was present. "
"Consider using memory-safe assembly only and annotating it via "
"'assembly (\"memory-safe\") { ... }'.";
else
msg += "\nmemoryguard was present.";
stackError << util::errinfo_comment(msg);
BOOST_THROW_EXCEPTION(stackError);
}
}
else
{
CodeTransform transform{
m_assembly,
*_object.analysisInfo,
*_object.code,
m_dialect,
context,
_optimize,
{},
CodeTransform::UseNamedLabels::ForFirstFunctionOfEachName
};
transform(*_object.code);
if (!transform.stackErrors().empty())
BOOST_THROW_EXCEPTION(transform.stackErrors().front());
}
}