mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Adding origin location notation to yul ir.
This commit is contained in:
committed by
chriseth
parent
921e21c7cb
commit
838f59fa5b
@@ -205,10 +205,34 @@ private:
|
||||
|
||||
}
|
||||
|
||||
string IRGeneratorForStatementsBase::code() const
|
||||
{
|
||||
return m_code.str();
|
||||
}
|
||||
|
||||
std::ostringstream& IRGeneratorForStatementsBase::appendCode(bool _addLocationComment)
|
||||
{
|
||||
if (
|
||||
_addLocationComment &&
|
||||
m_currentLocation.isValid() &&
|
||||
m_lastLocation != m_currentLocation
|
||||
)
|
||||
m_code << sourceLocationComment(m_currentLocation, m_context) << "\n";
|
||||
|
||||
m_lastLocation = m_currentLocation;
|
||||
|
||||
return m_code;
|
||||
}
|
||||
|
||||
void IRGeneratorForStatementsBase::setLocation(ASTNode const& _node)
|
||||
{
|
||||
m_currentLocation = _node.location();
|
||||
}
|
||||
|
||||
string IRGeneratorForStatements::code() const
|
||||
{
|
||||
solAssert(!m_currentLValue, "LValue not reset!");
|
||||
return m_code.str();
|
||||
return IRGeneratorForStatementsBase::code();
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::generate(Block const& _block)
|
||||
@@ -289,6 +313,8 @@ IRVariable IRGeneratorForStatements::evaluateExpression(Expression const& _expre
|
||||
setLocation(_expression);
|
||||
|
||||
_expression.accept(*this);
|
||||
|
||||
setLocation(_expression);
|
||||
IRVariable variable{m_context.newYulVariable(), _targetType};
|
||||
define(variable, _expression);
|
||||
return variable;
|
||||
@@ -305,16 +331,16 @@ string IRGeneratorForStatements::constantValueFunction(VariableDeclaration const
|
||||
{
|
||||
try
|
||||
{
|
||||
setLocation(_constant);
|
||||
|
||||
string functionName = IRNames::constantValueFunction(_constant);
|
||||
return m_context.functionCollector().createFunction(functionName, [&] {
|
||||
Whiskers templ(R"(
|
||||
<sourceLocationComment>
|
||||
function <functionName>() -> <ret> {
|
||||
<code>
|
||||
<ret> := <value>
|
||||
}
|
||||
)");
|
||||
templ("sourceLocationComment", sourceLocationComment(_constant, m_context));
|
||||
templ("functionName", functionName);
|
||||
IRGeneratorForStatements generator(m_context, m_utils);
|
||||
solAssert(_constant.value(), "");
|
||||
@@ -376,19 +402,19 @@ bool IRGeneratorForStatements::visit(Conditional const& _conditional)
|
||||
string condition = expressionAsType(_conditional.condition(), *TypeProvider::boolean());
|
||||
declare(_conditional);
|
||||
|
||||
m_code << "switch " << condition << "\n" "case 0 {\n";
|
||||
appendCode() << "switch " << condition << "\n" "case 0 {\n";
|
||||
|
||||
_conditional.falseExpression().accept(*this);
|
||||
setLocation(_conditional);
|
||||
|
||||
assign(_conditional, _conditional.falseExpression());
|
||||
m_code << "}\n" "default {\n";
|
||||
appendCode() << "}\n" "default {\n";
|
||||
|
||||
_conditional.trueExpression().accept(*this);
|
||||
setLocation(_conditional);
|
||||
|
||||
assign(_conditional, _conditional.trueExpression());
|
||||
m_code << "}\n";
|
||||
appendCode() << "}\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -472,7 +498,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple)
|
||||
component.accept(*this);
|
||||
setLocation(_tuple);
|
||||
IRVariable converted = convert(component, baseType);
|
||||
m_code <<
|
||||
appendCode() <<
|
||||
m_utils.writeToMemoryFunction(baseType) <<
|
||||
"(" <<
|
||||
("add(" + mpos + ", " + to_string(i * arrayType.memoryStride()) + ")") <<
|
||||
@@ -553,24 +579,25 @@ bool IRGeneratorForStatements::visit(IfStatement const& _ifStatement)
|
||||
|
||||
if (_ifStatement.falseStatement())
|
||||
{
|
||||
m_code << "switch " << condition << "\n" "case 0 {\n";
|
||||
appendCode() << "switch " << condition << "\n" "case 0 {\n";
|
||||
_ifStatement.falseStatement()->accept(*this);
|
||||
setLocation(_ifStatement);
|
||||
m_code << "}\n" "default {\n";
|
||||
appendCode() << "}\n" "default {\n";
|
||||
}
|
||||
else
|
||||
m_code << "if " << condition << " {\n";
|
||||
appendCode() << "if " << condition << " {\n";
|
||||
_ifStatement.trueStatement().accept(*this);
|
||||
setLocation(_ifStatement);
|
||||
m_code << "}\n";
|
||||
appendCode() << "}\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::endVisit(PlaceholderStatement const&)
|
||||
void IRGeneratorForStatements::endVisit(PlaceholderStatement const& _placeholder)
|
||||
{
|
||||
solAssert(m_placeholderCallback, "");
|
||||
m_code << m_placeholderCallback();
|
||||
setLocation(_placeholder);
|
||||
appendCode() << m_placeholderCallback();
|
||||
}
|
||||
|
||||
bool IRGeneratorForStatements::visit(ForStatement const& _forStatement)
|
||||
@@ -603,14 +630,14 @@ bool IRGeneratorForStatements::visit(WhileStatement const& _whileStatement)
|
||||
bool IRGeneratorForStatements::visit(Continue const& _continue)
|
||||
{
|
||||
setLocation(_continue);
|
||||
m_code << "continue\n";
|
||||
appendCode() << "continue\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IRGeneratorForStatements::visit(Break const& _break)
|
||||
{
|
||||
setLocation(_break);
|
||||
m_code << "break\n";
|
||||
appendCode() << "break\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -628,7 +655,7 @@ void IRGeneratorForStatements::endVisit(Return const& _return)
|
||||
else if (returnParameters.size() == 1)
|
||||
assign(m_context.localVariable(*returnParameters.front()), *value);
|
||||
}
|
||||
m_code << "leave\n";
|
||||
appendCode() << "leave\n";
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::endVisit(UnaryOperation const& _unaryOperation)
|
||||
@@ -643,7 +670,7 @@ void IRGeneratorForStatements::endVisit(UnaryOperation const& _unaryOperation)
|
||||
std::visit(
|
||||
util::GenericVisitor{
|
||||
[&](IRLValue::Storage const& _storage) {
|
||||
m_code <<
|
||||
appendCode() <<
|
||||
m_utils.storageSetToZeroFunction(m_currentLValue->type) <<
|
||||
"(" <<
|
||||
_storage.slot <<
|
||||
@@ -870,7 +897,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
for (size_t i = 0; i < arguments.size(); i++)
|
||||
{
|
||||
IRVariable converted = convert(*arguments[i], *parameterTypes[i]);
|
||||
m_code <<
|
||||
appendCode() <<
|
||||
m_utils.writeToMemoryFunction(*functionType->parameterTypes()[i]) <<
|
||||
"(add(" <<
|
||||
IRVariable(_functionCall).part("mpos").name() <<
|
||||
@@ -1001,7 +1028,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
templ("indexedArgs", joinHumanReadablePrefixed(indexedArgs | ranges::views::transform([&](auto const& _arg) {
|
||||
return _arg.commaSeparatedList();
|
||||
})));
|
||||
m_code << templ.render();
|
||||
appendCode() << templ.render();
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::Error:
|
||||
@@ -1030,10 +1057,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
messageArgumentType
|
||||
);
|
||||
|
||||
m_code << move(requireOrAssertFunction) << "(" << IRVariable(*arguments[0]).name();
|
||||
appendCode() << move(requireOrAssertFunction) << "(" << IRVariable(*arguments[0]).name();
|
||||
if (messageArgumentType && messageArgumentType->sizeOnStack() > 0)
|
||||
m_code << ", " << IRVariable(*arguments[1]).commaSeparatedList();
|
||||
m_code << ")\n";
|
||||
appendCode() << ", " << IRVariable(*arguments[1]).commaSeparatedList();
|
||||
appendCode() << ")\n";
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1075,7 +1102,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
// We might want to introduce a new set of memory handling functions here
|
||||
// a la "setMemoryCheckPoint" and "freeUntilCheckPoint".
|
||||
string freeMemoryPre = m_context.newYulVariable();
|
||||
m_code << "let " << freeMemoryPre << " := " << m_utils.allocateUnboundedFunction() << "()\n";
|
||||
appendCode() << "let " << freeMemoryPre << " := " << m_utils.allocateUnboundedFunction() << "()\n";
|
||||
IRVariable array = convert(*arguments[0], *TypeProvider::bytesMemory());
|
||||
IRVariable hashVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(32));
|
||||
|
||||
@@ -1092,7 +1119,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
IRVariable selectorVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(4));
|
||||
define(selectorVariable, hashVariable);
|
||||
selector = selectorVariable.name();
|
||||
m_code << m_utils.finalizeAllocationFunction() << "(" << freeMemoryPre << ", 0)\n";
|
||||
appendCode() << m_utils.finalizeAllocationFunction() << "(" << freeMemoryPre << ", 0)\n";
|
||||
}
|
||||
}
|
||||
else if (functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector)
|
||||
@@ -1122,7 +1149,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
templ("arguments", joinHumanReadablePrefixed(argumentVars));
|
||||
templ("finalizeAllocation", m_utils.finalizeAllocationFunction());
|
||||
|
||||
m_code << templ.render();
|
||||
appendCode() << templ.render();
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::ABIDecode:
|
||||
@@ -1161,7 +1188,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
}
|
||||
templ("retVars", IRVariable(_functionCall).commaSeparatedList());
|
||||
|
||||
m_code << templ.render();
|
||||
appendCode() << templ.render();
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::Revert:
|
||||
@@ -1173,7 +1200,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
arguments.front()->annotation().type->isImplicitlyConvertibleTo(*TypeProvider::stringMemory()),
|
||||
"");
|
||||
if (m_context.revertStrings() == RevertStrings::Strip || arguments.empty())
|
||||
m_code << "revert(0, 0)\n";
|
||||
appendCode() << "revert(0, 0)\n";
|
||||
else
|
||||
revertWithError(
|
||||
"Error(string)",
|
||||
@@ -1248,7 +1275,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
{
|
||||
auto slotName = m_context.newYulVariable();
|
||||
auto offsetName = m_context.newYulVariable();
|
||||
m_code << "let " << slotName << ", " << offsetName << " := " <<
|
||||
appendCode() << "let " << slotName << ", " << offsetName << " := " <<
|
||||
m_utils.storageArrayPushZeroFunction(*arrayType) <<
|
||||
"(" << IRVariable(_functionCall.expression()).commaSeparatedList() << ")\n";
|
||||
setLValue(_functionCall, IRLValue{
|
||||
@@ -1266,7 +1293,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
convert(*arguments.front(), *arrayType->baseType()) :
|
||||
*arguments.front();
|
||||
|
||||
m_code <<
|
||||
appendCode() <<
|
||||
m_utils.storageArrayPushFunction(*arrayType, &argument.type()) <<
|
||||
"(" <<
|
||||
IRVariable(_functionCall.expression()).commaSeparatedList() <<
|
||||
@@ -1311,7 +1338,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
Whiskers templ("if iszero(<modulus>) { <panic>() }\n");
|
||||
templ("modulus", modulus.name());
|
||||
templ("panic", m_utils.panicFunction(PanicCode::DivisionByZero));
|
||||
m_code << templ.render();
|
||||
appendCode() << templ.render();
|
||||
|
||||
string args;
|
||||
for (size_t i = 0; i < 2; ++i)
|
||||
@@ -1357,8 +1384,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
&dynamic_cast<ContractType const&>(*functionType->returnParameterTypes().front()).contractDefinition();
|
||||
m_context.subObjectsCreated().insert(contract);
|
||||
|
||||
Whiskers t(R"(
|
||||
let <memPos> := <allocateUnbounded>()
|
||||
Whiskers t(R"(let <memPos> := <allocateUnbounded>()
|
||||
let <memEnd> := add(<memPos>, datasize("<object>"))
|
||||
if or(gt(<memEnd>, 0xffffffffffffffff), lt(<memEnd>, <memPos>)) { <panic>() }
|
||||
datacopy(<memPos>, dataoffset("<object>"), datasize("<object>"))
|
||||
@@ -1394,7 +1420,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
t("success", IRNames::trySuccessConditionVariable(_functionCall));
|
||||
else
|
||||
t("forwardingRevert", m_utils.forwardingRevertFunction());
|
||||
m_code << t.render();
|
||||
appendCode() << t.render();
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1422,7 +1448,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
templ("success", IRVariable(_functionCall).commaSeparatedList());
|
||||
templ("isTransfer", functionType->kind() == FunctionType::Kind::Transfer);
|
||||
templ("forwardingRevert", m_utils.forwardingRevertFunction());
|
||||
m_code << templ.render();
|
||||
appendCode() << templ.render();
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1485,7 +1511,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
templ("gas", "sub(gas(), " + formatNumber(gasNeededByCaller) + ")");
|
||||
}
|
||||
|
||||
m_code << templ.render();
|
||||
appendCode() << templ.render();
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1722,7 +1748,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
solAssert(!contractType.isSuper(), "");
|
||||
ContractDefinition const& contract = contractType.contractDefinition();
|
||||
m_context.subObjectsCreated().insert(&contract);
|
||||
m_code << Whiskers(R"(
|
||||
appendCode() << Whiskers(R"(
|
||||
let <size> := datasize("<objectName>")
|
||||
let <result> := <allocationFunction>(add(<size>, 32))
|
||||
mstore(<result>, <size>)
|
||||
@@ -1775,7 +1801,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
{
|
||||
pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member);
|
||||
string slot = m_context.newYulVariable();
|
||||
m_code << "let " << slot << " := " <<
|
||||
appendCode() << "let " << slot << " := " <<
|
||||
("add(" + expression.part("slot").name() + ", " + offsets.first.str() + ")\n");
|
||||
setLValue(_memberAccess, IRLValue{
|
||||
type(_memberAccess),
|
||||
@@ -1786,7 +1812,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
case DataLocation::Memory:
|
||||
{
|
||||
string pos = m_context.newYulVariable();
|
||||
m_code << "let " << pos << " := " <<
|
||||
appendCode() << "let " << pos << " := " <<
|
||||
("add(" + expression.part("mpos").name() + ", " + structType.memoryOffsetOfMember(member).str() + ")\n");
|
||||
setLValue(_memberAccess, IRLValue{
|
||||
type(_memberAccess),
|
||||
@@ -1798,7 +1824,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
{
|
||||
string baseRef = expression.part("offset").name();
|
||||
string offset = m_context.newYulVariable();
|
||||
m_code << "let " << offset << " := " << "add(" << baseRef << ", " << to_string(structType.calldataOffsetOfMember(member)) << ")\n";
|
||||
appendCode() << "let " << offset << " := " << "add(" << baseRef << ", " << to_string(structType.calldataOffsetOfMember(member)) << ")\n";
|
||||
if (_memberAccess.annotation().type->isDynamicallyEncoded())
|
||||
define(_memberAccess) <<
|
||||
m_utils.accessCalldataTailFunction(*_memberAccess.annotation().type) <<
|
||||
@@ -2023,7 +2049,7 @@ bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
|
||||
solAssert(holds_alternative<yul::Block>(modified), "");
|
||||
|
||||
// Do not provide dialect so that we get the full type information.
|
||||
m_code << yul::AsmPrinter()(std::get<yul::Block>(modified)) << "\n";
|
||||
appendCode() << yul::AsmPrinter()(std::get<yul::Block>(modified)) << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2046,7 +2072,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
|
||||
templ("indexAccess", m_utils.mappingIndexAccessFunction(mappingType, keyType));
|
||||
templ("base", IRVariable(_indexAccess.baseExpression()).commaSeparatedList());
|
||||
templ("key", IRVariable(*_indexAccess.indexExpression()).commaSeparatedList());
|
||||
m_code << templ.render();
|
||||
appendCode() << templ.render();
|
||||
setLValue(_indexAccess, IRLValue{
|
||||
*_indexAccess.annotation().type,
|
||||
IRLValue::Storage{
|
||||
@@ -2074,7 +2100,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
|
||||
string slot = m_context.newYulVariable();
|
||||
string offset = m_context.newYulVariable();
|
||||
|
||||
m_code << Whiskers(R"(
|
||||
appendCode() << Whiskers(R"(
|
||||
let <slot>, <offset> := <indexFunc>(<array>, <index>)
|
||||
)")
|
||||
("slot", slot)
|
||||
@@ -2141,7 +2167,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
|
||||
|
||||
IRVariable index{m_context.newYulVariable(), *TypeProvider::uint256()};
|
||||
define(index, *_indexAccess.indexExpression());
|
||||
m_code << Whiskers(R"(
|
||||
appendCode() << Whiskers(R"(
|
||||
if iszero(lt(<index>, <length>)) { <panic>() }
|
||||
let <result> := <shl248>(byte(<index>, <array>))
|
||||
)")
|
||||
@@ -2307,7 +2333,6 @@ void IRGeneratorForStatements::handleVariableReference(
|
||||
Expression const& _referencingExpression
|
||||
)
|
||||
{
|
||||
setLocation(_referencingExpression);
|
||||
if ((_variable.isStateVariable() || _variable.isFileLevelVariable()) && _variable.isConstant())
|
||||
define(_referencingExpression) << constantValueFunction(_variable) << "()\n";
|
||||
else if (_variable.isStateVariable() && _variable.immutable())
|
||||
@@ -2377,11 +2402,10 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
|
||||
// We could also just use MLOAD; POP right before the gas calculation, but the optimizer
|
||||
// would remove that, so we use MSTORE here.
|
||||
if (!funType.gasSet() && returnInfo.estimatedReturnSize > 0)
|
||||
m_code << "mstore(add(" << m_utils.allocateUnboundedFunction() << "() , " << to_string(returnInfo.estimatedReturnSize) << "), 0)\n";
|
||||
appendCode() << "mstore(add(" << m_utils.allocateUnboundedFunction() << "() , " << to_string(returnInfo.estimatedReturnSize) << "), 0)\n";
|
||||
}
|
||||
|
||||
Whiskers templ(R"(
|
||||
if iszero(extcodesize(<address>)) { <revertNoCode>() }
|
||||
Whiskers templ(R"(if iszero(extcodesize(<address>)) { <revertNoCode>() }
|
||||
|
||||
// storage for arguments and returned data
|
||||
let <pos> := <allocateUnbounded>()
|
||||
@@ -2474,7 +2498,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
|
||||
|
||||
templ("forwardingRevert", m_utils.forwardingRevertFunction());
|
||||
|
||||
m_code << templ.render();
|
||||
appendCode() << templ.render();
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::appendBareCall(
|
||||
@@ -2565,7 +2589,7 @@ void IRGeneratorForStatements::appendBareCall(
|
||||
templ("gas", "sub(gas(), " + formatNumber(gasNeededByCaller) + ")");
|
||||
}
|
||||
|
||||
m_code << templ.render();
|
||||
appendCode() << templ.render();
|
||||
}
|
||||
|
||||
IRVariable IRGeneratorForStatements::convert(IRVariable const& _from, Type const& _to)
|
||||
@@ -2597,14 +2621,14 @@ std::string IRGeneratorForStatements::expressionAsType(Expression const& _expres
|
||||
std::ostream& IRGeneratorForStatements::define(IRVariable const& _var)
|
||||
{
|
||||
if (_var.type().sizeOnStack() > 0)
|
||||
m_code << "let " << _var.commaSeparatedList() << " := ";
|
||||
return m_code;
|
||||
appendCode() << "let " << _var.commaSeparatedList() << " := ";
|
||||
return appendCode(false);
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::declare(IRVariable const& _var)
|
||||
{
|
||||
if (_var.type().sizeOnStack() > 0)
|
||||
m_code << "let " << _var.commaSeparatedList() << "\n";
|
||||
appendCode() << "let " << _var.commaSeparatedList() << "\n";
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::declareAssign(IRVariable const& _lhs, IRVariable const& _rhs, bool _declare)
|
||||
@@ -2615,15 +2639,15 @@ void IRGeneratorForStatements::declareAssign(IRVariable const& _lhs, IRVariable
|
||||
if (stackItemType)
|
||||
declareAssign(_lhs.part(stackItemName), _rhs.part(stackItemName), _declare);
|
||||
else
|
||||
m_code << (_declare ? "let ": "") << _lhs.part(stackItemName).name() << " := " << _rhs.part(stackItemName).name() << "\n";
|
||||
appendCode() << (_declare ? "let ": "") << _lhs.part(stackItemName).name() << " := " << _rhs.part(stackItemName).name() << "\n";
|
||||
else
|
||||
{
|
||||
if (_lhs.type().sizeOnStack() > 0)
|
||||
m_code <<
|
||||
appendCode() <<
|
||||
(_declare ? "let ": "") <<
|
||||
_lhs.commaSeparatedList() <<
|
||||
" := ";
|
||||
m_code << m_context.utils().conversionFunction(_rhs.type(), _lhs.type()) <<
|
||||
appendCode() << m_context.utils().conversionFunction(_rhs.type(), _lhs.type()) <<
|
||||
"(" <<
|
||||
_rhs.commaSeparatedList() <<
|
||||
")\n";
|
||||
@@ -2761,13 +2785,13 @@ void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _b
|
||||
IRVariable value(_binOp);
|
||||
define(value, _binOp.leftExpression());
|
||||
if (op == Token::Or)
|
||||
m_code << "if iszero(" << value.name() << ") {\n";
|
||||
appendCode() << "if iszero(" << value.name() << ") {\n";
|
||||
else
|
||||
m_code << "if " << value.name() << " {\n";
|
||||
appendCode() << "if " << value.name() << " {\n";
|
||||
_binOp.rightExpression().accept(*this);
|
||||
setLocation(_binOp);
|
||||
assign(value, _binOp.rightExpression());
|
||||
m_code << "}\n";
|
||||
appendCode() << "}\n";
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable const& _value)
|
||||
@@ -2783,7 +2807,7 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable
|
||||
[&](string const& _offset) { offsetArgument = ", " + _offset; }
|
||||
}, _storage.offset);
|
||||
|
||||
m_code <<
|
||||
appendCode() <<
|
||||
m_utils.updateStorageValueFunction(_value.type(), _lvalue.type, offsetStatic) <<
|
||||
"(" <<
|
||||
_storage.slot <<
|
||||
@@ -2801,10 +2825,10 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable
|
||||
if (_memory.byteArrayElement)
|
||||
{
|
||||
solAssert(_lvalue.type == *TypeProvider::byte(), "");
|
||||
m_code << "mstore8(" + _memory.address + ", byte(0, " + prepared.commaSeparatedList() + "))\n";
|
||||
appendCode() << "mstore8(" + _memory.address + ", byte(0, " + prepared.commaSeparatedList() + "))\n";
|
||||
}
|
||||
else
|
||||
m_code << m_utils.writeToMemoryFunction(_lvalue.type) <<
|
||||
appendCode() << m_utils.writeToMemoryFunction(_lvalue.type) <<
|
||||
"(" <<
|
||||
_memory.address <<
|
||||
", " <<
|
||||
@@ -2812,7 +2836,7 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable
|
||||
")\n";
|
||||
}
|
||||
else if (auto const* literalType = dynamic_cast<StringLiteralType const*>(&_value.type()))
|
||||
m_code <<
|
||||
appendCode() <<
|
||||
m_utils.writeToMemoryFunction(*TypeProvider::uint256()) <<
|
||||
"(" <<
|
||||
_memory.address <<
|
||||
@@ -2824,7 +2848,7 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable
|
||||
solAssert(_lvalue.type.sizeOnStack() == 1, "");
|
||||
auto const* valueReferenceType = dynamic_cast<ReferenceType const*>(&_value.type());
|
||||
solAssert(valueReferenceType && valueReferenceType->dataStoredIn(DataLocation::Memory), "");
|
||||
m_code << "mstore(" + _memory.address + ", " + _value.part("mpos").name() + ")\n";
|
||||
appendCode() << "mstore(" + _memory.address + ", " + _value.part("mpos").name() + ")\n";
|
||||
}
|
||||
},
|
||||
[&](IRLValue::Stack const& _stack) { assign(_stack.variable, _value); },
|
||||
@@ -2838,7 +2862,7 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable
|
||||
IRVariable prepared(m_context.newYulVariable(), _lvalue.type);
|
||||
define(prepared, _value);
|
||||
|
||||
m_code << "mstore(" << to_string(memOffset) << ", " << prepared.commaSeparatedList() << ")\n";
|
||||
appendCode() << "mstore(" << to_string(memOffset) << ", " << prepared.commaSeparatedList() << ")\n";
|
||||
},
|
||||
[&](IRLValue::Tuple const& _tuple) {
|
||||
auto components = std::move(_tuple.components);
|
||||
@@ -2931,36 +2955,36 @@ void IRGeneratorForStatements::generateLoop(
|
||||
{
|
||||
solAssert(_conditionExpression, "Expected condition for doWhile");
|
||||
firstRun = m_context.newYulVariable();
|
||||
m_code << "let " << firstRun << " := 1\n";
|
||||
appendCode() << "let " << firstRun << " := 1\n";
|
||||
}
|
||||
|
||||
m_code << "for {\n";
|
||||
appendCode() << "for {\n";
|
||||
if (_initExpression)
|
||||
_initExpression->accept(*this);
|
||||
m_code << "} 1 {\n";
|
||||
appendCode() << "} 1 {\n";
|
||||
if (_loopExpression)
|
||||
_loopExpression->accept(*this);
|
||||
m_code << "}\n";
|
||||
m_code << "{\n";
|
||||
appendCode() << "}\n";
|
||||
appendCode() << "{\n";
|
||||
|
||||
if (_conditionExpression)
|
||||
{
|
||||
if (_isDoWhile)
|
||||
m_code << "if iszero(" << firstRun << ") {\n";
|
||||
appendCode() << "if iszero(" << firstRun << ") {\n";
|
||||
|
||||
_conditionExpression->accept(*this);
|
||||
m_code <<
|
||||
appendCode() <<
|
||||
"if iszero(" <<
|
||||
expressionAsType(*_conditionExpression, *TypeProvider::boolean()) <<
|
||||
") { break }\n";
|
||||
|
||||
if (_isDoWhile)
|
||||
m_code << "}\n" << firstRun << " := 0\n";
|
||||
appendCode() << "}\n" << firstRun << " := 0\n";
|
||||
}
|
||||
|
||||
_body.accept(*this);
|
||||
|
||||
m_code << "}\n";
|
||||
appendCode() << "}\n";
|
||||
}
|
||||
|
||||
Type const& IRGeneratorForStatements::type(Expression const& _expression)
|
||||
@@ -2975,9 +2999,9 @@ bool IRGeneratorForStatements::visit(TryStatement const& _tryStatement)
|
||||
externalCall.accept(*this);
|
||||
setLocation(_tryStatement);
|
||||
|
||||
m_code << "switch iszero(" << IRNames::trySuccessConditionVariable(externalCall) << ")\n";
|
||||
appendCode() << "switch iszero(" << IRNames::trySuccessConditionVariable(externalCall) << ")\n";
|
||||
|
||||
m_code << "case 0 { // success case\n";
|
||||
appendCode() << "case 0 { // success case\n";
|
||||
TryCatchClause const& successClause = *_tryStatement.clauses().front();
|
||||
if (successClause.parameters())
|
||||
{
|
||||
@@ -2995,32 +3019,34 @@ bool IRGeneratorForStatements::visit(TryStatement const& _tryStatement)
|
||||
|
||||
successClause.block().accept(*this);
|
||||
setLocation(_tryStatement);
|
||||
m_code << "}\n";
|
||||
appendCode() << "}\n";
|
||||
|
||||
m_code << "default { // failure case\n";
|
||||
appendCode() << "default { // failure case\n";
|
||||
handleCatch(_tryStatement);
|
||||
m_code << "}\n";
|
||||
appendCode() << "}\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::handleCatch(TryStatement const& _tryStatement)
|
||||
{
|
||||
setLocation(_tryStatement);
|
||||
string const runFallback = m_context.newYulVariable();
|
||||
m_code << "let " << runFallback << " := 1\n";
|
||||
appendCode() << "let " << runFallback << " := 1\n";
|
||||
|
||||
// This function returns zero on "short returndata". We have to add a success flag
|
||||
// once we implement custom error codes.
|
||||
if (_tryStatement.errorClause() || _tryStatement.panicClause())
|
||||
m_code << "switch " << m_utils.returnDataSelectorFunction() << "()\n";
|
||||
appendCode() << "switch " << m_utils.returnDataSelectorFunction() << "()\n";
|
||||
|
||||
if (TryCatchClause const* errorClause = _tryStatement.errorClause())
|
||||
{
|
||||
m_code << "case " << selectorFromSignature32("Error(string)") << " {\n";
|
||||
appendCode() << "case " << selectorFromSignature32("Error(string)") << " {\n";
|
||||
setLocation(*errorClause);
|
||||
string const dataVariable = m_context.newYulVariable();
|
||||
m_code << "let " << dataVariable << " := " << m_utils.tryDecodeErrorMessageFunction() << "()\n";
|
||||
m_code << "if " << dataVariable << " {\n";
|
||||
m_code << runFallback << " := 0\n";
|
||||
appendCode() << "let " << dataVariable << " := " << m_utils.tryDecodeErrorMessageFunction() << "()\n";
|
||||
appendCode() << "if " << dataVariable << " {\n";
|
||||
appendCode() << runFallback << " := 0\n";
|
||||
if (errorClause->parameters())
|
||||
{
|
||||
solAssert(errorClause->parameters()->parameters().size() == 1, "");
|
||||
@@ -3028,17 +3054,20 @@ void IRGeneratorForStatements::handleCatch(TryStatement const& _tryStatement)
|
||||
define(var) << dataVariable << "\n";
|
||||
}
|
||||
errorClause->accept(*this);
|
||||
m_code << "}\n";
|
||||
m_code << "}\n";
|
||||
setLocation(*errorClause);
|
||||
appendCode() << "}\n";
|
||||
setLocation(_tryStatement);
|
||||
appendCode() << "}\n";
|
||||
}
|
||||
if (TryCatchClause const* panicClause = _tryStatement.panicClause())
|
||||
{
|
||||
m_code << "case " << selectorFromSignature32("Panic(uint256)") << " {\n";
|
||||
appendCode() << "case " << selectorFromSignature32("Panic(uint256)") << " {\n";
|
||||
setLocation(*panicClause);
|
||||
string const success = m_context.newYulVariable();
|
||||
string const code = m_context.newYulVariable();
|
||||
m_code << "let " << success << ", " << code << " := " << m_utils.tryDecodePanicDataFunction() << "()\n";
|
||||
m_code << "if " << success << " {\n";
|
||||
m_code << runFallback << " := 0\n";
|
||||
appendCode() << "let " << success << ", " << code << " := " << m_utils.tryDecodePanicDataFunction() << "()\n";
|
||||
appendCode() << "if " << success << " {\n";
|
||||
appendCode() << runFallback << " := 0\n";
|
||||
if (panicClause->parameters())
|
||||
{
|
||||
solAssert(panicClause->parameters()->parameters().size() == 1, "");
|
||||
@@ -3046,20 +3075,25 @@ void IRGeneratorForStatements::handleCatch(TryStatement const& _tryStatement)
|
||||
define(var) << code << "\n";
|
||||
}
|
||||
panicClause->accept(*this);
|
||||
m_code << "}\n";
|
||||
m_code << "}\n";
|
||||
setLocation(*panicClause);
|
||||
appendCode() << "}\n";
|
||||
setLocation(_tryStatement);
|
||||
appendCode() << "}\n";
|
||||
}
|
||||
|
||||
m_code << "if " << runFallback << " {\n";
|
||||
setLocation(_tryStatement);
|
||||
appendCode() << "if " << runFallback << " {\n";
|
||||
if (_tryStatement.fallbackClause())
|
||||
handleCatchFallback(*_tryStatement.fallbackClause());
|
||||
else
|
||||
m_code << m_utils.forwardingRevertFunction() << "()\n";
|
||||
m_code << "}\n";
|
||||
appendCode() << m_utils.forwardingRevertFunction() << "()\n";
|
||||
setLocation(_tryStatement);
|
||||
appendCode() << "}\n";
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::handleCatchFallback(TryCatchClause const& _fallback)
|
||||
{
|
||||
setLocation(_fallback);
|
||||
if (_fallback.parameters())
|
||||
{
|
||||
solAssert(m_context.evmVersion().supportsReturndata(), "");
|
||||
@@ -3104,7 +3138,7 @@ void IRGeneratorForStatements::revertWithError(
|
||||
templ("argumentVars", joinHumanReadablePrefixed(errorArgumentVars));
|
||||
templ("encode", m_context.abiFunctions().tupleEncoder(errorArgumentTypes, _parameterTypes));
|
||||
|
||||
m_code << templ.render();
|
||||
appendCode() << templ.render();
|
||||
}
|
||||
|
||||
|
||||
@@ -3114,11 +3148,6 @@ bool IRGeneratorForStatements::visit(TryCatchClause const& _clause)
|
||||
return false;
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::setLocation(ASTNode const& _node)
|
||||
{
|
||||
m_currentLocation = _node.location();
|
||||
}
|
||||
|
||||
string IRGeneratorForStatements::linkerSymbol(ContractDefinition const& _library) const
|
||||
{
|
||||
solAssert(_library.isLibrary(), "");
|
||||
|
||||
Reference in New Issue
Block a user