Merge pull request #10769 from ethereum/allocationCleanup

Cleanup allocation.
This commit is contained in:
chriseth 2021-01-26 11:58:11 +01:00 committed by GitHub
commit 4697beeab2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 239 additions and 164 deletions

View File

@ -183,15 +183,15 @@ string YulUtilFunctions::requireOrAssertFunction(bool _assert, Type const* _mess
return Whiskers(R"( return Whiskers(R"(
function <functionName>(condition <messageVars>) { function <functionName>(condition <messageVars>) {
if iszero(condition) { if iszero(condition) {
let fmp := mload(<freeMemPointer>) let memPtr := <allocateUnbounded>()
mstore(fmp, <errorHash>) mstore(memPtr, <errorHash>)
let end := <abiEncodeFunc>(add(fmp, <hashHeaderSize>) <messageVars>) let end := <abiEncodeFunc>(add(memPtr, <hashHeaderSize>) <messageVars>)
revert(fmp, sub(end, fmp)) revert(memPtr, sub(end, memPtr))
} }
} }
)") )")
("functionName", functionName) ("functionName", functionName)
("freeMemPointer", to_string(CompilerUtils::freeMemoryPointer)) ("allocateUnbounded", allocateUnboundedFunction())
("errorHash", formatNumber(errorHash)) ("errorHash", formatNumber(errorHash))
("abiEncodeFunc", encodeFunc) ("abiEncodeFunc", encodeFunc)
("hashHeaderSize", to_string(hashHeaderSize)) ("hashHeaderSize", to_string(hashHeaderSize))
@ -2301,19 +2301,19 @@ string YulUtilFunctions::copyArrayFromStorageToMemoryFunction(ArrayType const& _
solAssert(_from.baseType() == _to.baseType(), ""); solAssert(_from.baseType() == _to.baseType(), "");
ABIFunctions abi(m_evmVersion, m_revertStrings, m_functionCollector); ABIFunctions abi(m_evmVersion, m_revertStrings, m_functionCollector);
return Whiskers(R"( return Whiskers(R"(
function <functionName>(slot) -> memptr { function <functionName>(slot) -> memPtr {
memptr := <allocateTemp>() memPtr := <allocateUnbounded>()
let end := <encode>(slot, memptr) let end := <encode>(slot, memPtr)
mstore(<freeMemoryPointer>, end) <finalizeAllocation>(memPtr, sub(end, memPtr))
} }
)") )")
("functionName", functionName) ("functionName", functionName)
("allocateTemp", allocationTemporaryMemoryFunction()) ("allocateUnbounded", allocateUnboundedFunction())
( (
"encode", "encode",
abi.abiEncodeAndReturnUpdatedPosFunction(_from, _to, ABIFunctions::EncodingOptions{}) abi.abiEncodeAndReturnUpdatedPosFunction(_from, _to, ABIFunctions::EncodingOptions{})
) )
("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer)) ("finalizeAllocation", finalizeAllocationFunction())
.render(); .render();
} }
else else
@ -2324,10 +2324,10 @@ string YulUtilFunctions::copyArrayFromStorageToMemoryFunction(ArrayType const& _
solAssert(!_from.isByteArray(), ""); solAssert(!_from.isByteArray(), "");
solAssert(*_to.withLocation(DataLocation::Storage, _from.isPointer()) == _from, ""); solAssert(*_to.withLocation(DataLocation::Storage, _from.isPointer()) == _from, "");
return Whiskers(R"( return Whiskers(R"(
function <functionName>(slot) -> memptr { function <functionName>(slot) -> memPtr {
let length := <lengthFunction>(slot) let length := <lengthFunction>(slot)
memptr := <allocateArray>(length) memPtr := <allocateArray>(length)
let mpos := memptr let mpos := memPtr
<?dynamic>mpos := add(mpos, 0x20)</dynamic> <?dynamic>mpos := add(mpos, 0x20)</dynamic>
let spos := <arrayDataArea>(slot) let spos := <arrayDataArea>(slot)
for { let i := 0 } lt(i, length) { i := add(i, 1) } { for { let i := 0 } lt(i, length) { i := add(i, 1) } {
@ -2793,28 +2793,24 @@ string YulUtilFunctions::prepareStoreFunction(Type const& _type)
string YulUtilFunctions::allocationFunction() string YulUtilFunctions::allocationFunction()
{ {
string functionName = "allocateMemory"; string functionName = "allocate_memory";
return m_functionCollector.createFunction(functionName, [&]() { return m_functionCollector.createFunction(functionName, [&]() {
return Whiskers(R"( return Whiskers(R"(
function <functionName>(size) -> memPtr { function <functionName>(size) -> memPtr {
memPtr := mload(<freeMemoryPointer>) memPtr := <allocateUnbounded>()
let newFreePtr := add(memPtr, <roundUp>(size)) <finalizeAllocation>(memPtr, size)
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { <panic>() }
mstore(<freeMemoryPointer>, newFreePtr)
} }
)") )")
("functionName", functionName) ("functionName", functionName)
("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer)) ("allocateUnbounded", allocateUnboundedFunction())
("roundUp", roundUpFunction()) ("finalizeAllocation", finalizeAllocationFunction())
("panic", panicFunction(PanicCode::ResourceError))
.render(); .render();
}); });
} }
string YulUtilFunctions::allocationTemporaryMemoryFunction() string YulUtilFunctions::allocateUnboundedFunction()
{ {
string functionName = "allocateTemporaryMemory"; string functionName = "allocate_unbounded";
return m_functionCollector.createFunction(functionName, [&]() { return m_functionCollector.createFunction(functionName, [&]() {
return Whiskers(R"( return Whiskers(R"(
function <functionName>() -> memPtr { function <functionName>() -> memPtr {
@ -2827,15 +2823,22 @@ string YulUtilFunctions::allocationTemporaryMemoryFunction()
}); });
} }
string YulUtilFunctions::releaseTemporaryMemoryFunction() string YulUtilFunctions::finalizeAllocationFunction()
{ {
string functionName = "releaseTemporaryMemory"; string functionName = "finalize_allocation";
return m_functionCollector.createFunction(functionName, [&](){ return m_functionCollector.createFunction(functionName, [&]() {
return Whiskers(R"( return Whiskers(R"(
function <functionName>() { function <functionName>(memPtr, size) {
let newFreePtr := add(memPtr, <roundUp>(size))
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { <panic>() }
mstore(<freeMemoryPointer>, newFreePtr)
} }
)") )")
("functionName", functionName) ("functionName", functionName)
("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer))
("roundUp", roundUpFunction())
("panic", panicFunction(PanicCode::ResourceError))
.render(); .render();
}); });
} }
@ -3625,7 +3628,7 @@ string YulUtilFunctions::packedHashFunction(
return m_functionCollector.createFunction(functionName, [&]() { return m_functionCollector.createFunction(functionName, [&]() {
Whiskers templ(R"( Whiskers templ(R"(
function <functionName>(<variables>) -> hash { function <functionName>(<variables>) -> hash {
let pos := mload(<freeMemoryPointer>) let pos := <allocateUnbounded>()
let end := <packedEncode>(pos <comma> <variables>) let end := <packedEncode>(pos <comma> <variables>)
hash := keccak256(pos, sub(end, pos)) hash := keccak256(pos, sub(end, pos))
} }
@ -3633,7 +3636,7 @@ string YulUtilFunctions::packedHashFunction(
templ("functionName", functionName); templ("functionName", functionName);
templ("variables", suffixedVariableNameList("var_", 1, 1 + sizeOnStack)); templ("variables", suffixedVariableNameList("var_", 1, 1 + sizeOnStack));
templ("comma", sizeOnStack > 0 ? "," : ""); templ("comma", sizeOnStack > 0 ? "," : "");
templ("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer)); templ("allocateUnbounded", allocateUnboundedFunction());
templ("packedEncode", ABIFunctions(m_evmVersion, m_revertStrings, m_functionCollector).tupleEncoderPacked(_givenTypes, _targetTypes)); templ("packedEncode", ABIFunctions(m_evmVersion, m_revertStrings, m_functionCollector).tupleEncoderPacked(_givenTypes, _targetTypes));
return templ.render(); return templ.render();
}); });
@ -4149,7 +4152,7 @@ string YulUtilFunctions::tryDecodeErrorMessageFunction()
function <functionName>() -> ret { function <functionName>() -> ret {
if lt(returndatasize(), 0x44) { leave } if lt(returndatasize(), 0x44) { leave }
let data := mload(<freeMemoryPointer>) let data := <allocateUnbounded>()
returndatacopy(data, 4, sub(returndatasize(), 4)) returndatacopy(data, 4, sub(returndatasize(), 4))
let offset := mload(data) let offset := mload(data)
@ -4167,13 +4170,13 @@ string YulUtilFunctions::tryDecodeErrorMessageFunction()
let end := add(add(msg, 0x20), length) let end := add(add(msg, 0x20), length)
if gt(end, add(data, sub(returndatasize(), 4))) { leave } if gt(end, add(data, sub(returndatasize(), 4))) { leave }
mstore(<freeMemoryPointer>, add(add(msg, 0x20), <roundUp>(length))) <finalizeAllocation>(data, add(offset, add(0x20, length)))
ret := msg ret := msg
} }
)") )")
("functionName", functionName) ("functionName", functionName)
("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer)) ("allocateUnbounded", allocateUnboundedFunction())
("roundUp", roundUpFunction()) ("finalizeAllocation", finalizeAllocationFunction())
.render(); .render();
}); });
} }

View File

@ -352,16 +352,20 @@ public:
/// @returns the name of a function that allocates memory. /// @returns the name of a function that allocates memory.
/// Modifies the "free memory pointer" /// Modifies the "free memory pointer"
/// Arguments: size /// signature: (size) -> memPtr
/// Return value: pointer
std::string allocationFunction(); std::string allocationFunction();
/// @returns the name of the function that allocates temporary memory with predefined size /// @returns the name of the function that allocates memory whose size might be defined later.
/// Return value: pointer /// The allocation can be finalized using finalizeAllocationFunction.
std::string allocationTemporaryMemoryFunction(); /// Any other allocation will invalidate the memory pointer unless finalizeAllocationFunction
/// is called.
/// signature: () -> memPtr
std::string allocateUnboundedFunction();
/// @returns the name of the function that releases previously allocated temporary memory /// @returns the name of the function that finalizes an unbounded memory allocation,
std::string releaseTemporaryMemoryFunction(); /// i.e. sets its size and makes the allocation permanent.
/// signature: (memPtr, size) ->
std::string finalizeAllocationFunction();
/// @returns the name of a function that zeroes an array. /// @returns the name of a function that zeroes an array.
/// signature: (dataStart, dataSizeInBytes) -> /// signature: (dataStart, dataSizeInBytes) ->

View File

@ -1035,13 +1035,13 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
} }
solAssert(indexedArgs.size() <= 4, "Too many indexed arguments."); solAssert(indexedArgs.size() <= 4, "Too many indexed arguments.");
Whiskers templ(R"({ Whiskers templ(R"({
let <pos> := <freeMemory> let <pos> := <allocateUnbounded>()
let <end> := <encode>(<pos> <nonIndexedArgs>) let <end> := <encode>(<pos> <nonIndexedArgs>)
<log>(<pos>, sub(<end>, <pos>) <indexedArgs>) <log>(<pos>, sub(<end>, <pos>) <indexedArgs>)
})"); })");
templ("pos", m_context.newYulVariable()); templ("pos", m_context.newYulVariable());
templ("end", m_context.newYulVariable()); templ("end", m_context.newYulVariable());
templ("freeMemory", freeMemory()); templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
templ("encode", abi.tupleEncoder(nonIndexedArgTypes, nonIndexedParamTypes)); templ("encode", abi.tupleEncoder(nonIndexedArgTypes, nonIndexedParamTypes));
templ("nonIndexedArgs", joinHumanReadablePrefixed(nonIndexedArgs)); templ("nonIndexedArgs", joinHumanReadablePrefixed(nonIndexedArgs));
templ("log", "log" + to_string(indexedArgs.size())); templ("log", "log" + to_string(indexedArgs.size()));
@ -1107,8 +1107,11 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
else else
{ {
// Used to reset the free memory pointer later. // Used to reset the free memory pointer later.
// TODO This is an abuse of the `allocateUnbounded` function.
// We might want to introduce a new set of memory handling functions here
// a la "setMemoryCheckPoint" and "freeUntilCheckPoint".
string freeMemoryPre = m_context.newYulVariable(); string freeMemoryPre = m_context.newYulVariable();
m_code << "let " << freeMemoryPre << " := " << freeMemory() << "\n"; m_code << "let " << freeMemoryPre << " := " << m_utils.allocateUnboundedFunction() << "()\n";
IRVariable array = convert(*arguments[0], *TypeProvider::bytesMemory()); IRVariable array = convert(*arguments[0], *TypeProvider::bytesMemory());
IRVariable hashVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(32)); IRVariable hashVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(32));
@ -1125,26 +1128,26 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
IRVariable selectorVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(4)); IRVariable selectorVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(4));
define(selectorVariable, hashVariable); define(selectorVariable, hashVariable);
selector = selectorVariable.name(); selector = selectorVariable.name();
m_code << "mstore(" << to_string(CompilerUtils::freeMemoryPointer) << ", " << freeMemoryPre << ")\n"; m_code << m_utils.finalizeAllocationFunction() << "(" << freeMemoryPre << ", 0)\n";
} }
} }
else if (functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector) else if (functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector)
selector = convert(*arguments.front(), *TypeProvider::fixedBytes(4)).name(); selector = convert(*arguments.front(), *TypeProvider::fixedBytes(4)).name();
Whiskers templ(R"( Whiskers templ(R"(
let <data> := <allocateTemporary>() let <data> := <allocateUnbounded>()
let <mpos> := add(<data>, 0x20) let <memPtr> := add(<data>, 0x20)
<?+selector> <?+selector>
mstore(<mpos>, <selector>) mstore(<memPtr>, <selector>)
<mpos> := add(<mpos>, 4) <memPtr> := add(<memPtr>, 4)
</+selector> </+selector>
let <mend> := <encode>(<mpos><arguments>) let <mend> := <encode>(<memPtr><arguments>)
mstore(<data>, sub(<mend>, add(<data>, 0x20))) mstore(<data>, sub(<mend>, add(<data>, 0x20)))
mstore(<freeMemPtr>, <roundUp>(<mend>)) <finalizeAllocation>(<data>, sub(<mend>, <data>))
)"); )");
templ("data", IRVariable(_functionCall).part("mpos").name()); templ("data", IRVariable(_functionCall).part("mpos").name());
templ("allocateTemporary", m_utils.allocationTemporaryMemoryFunction()); templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
templ("mpos", m_context.newYulVariable()); templ("memPtr", m_context.newYulVariable());
templ("mend", m_context.newYulVariable()); templ("mend", m_context.newYulVariable());
templ("selector", selector); templ("selector", selector);
templ("encode", templ("encode",
@ -1153,8 +1156,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
m_context.abiFunctions().tupleEncoder(argumentTypes, targetTypes, false) m_context.abiFunctions().tupleEncoder(argumentTypes, targetTypes, false)
); );
templ("arguments", joinHumanReadablePrefixed(argumentVars)); templ("arguments", joinHumanReadablePrefixed(argumentVars));
templ("freeMemPtr", to_string(CompilerUtils::freeMemoryPointer)); templ("finalizeAllocation", m_utils.finalizeAllocationFunction());
templ("roundUp", m_utils.roundUpFunction());
m_code << templ.render(); m_code << templ.render();
break; break;
@ -1214,7 +1216,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
solAssert(type(*arguments.front()).isImplicitlyConvertibleTo(*TypeProvider::stringMemory()),""); solAssert(type(*arguments.front()).isImplicitlyConvertibleTo(*TypeProvider::stringMemory()),"");
Whiskers templ(R"({ Whiskers templ(R"({
let <pos> := <allocateTemporary>() let <pos> := <allocateUnbounded>()
mstore(<pos>, <hash>) mstore(<pos>, <hash>)
let <end> := <encode>(add(<pos>, 4) <argumentVars>) let <end> := <encode>(add(<pos>, 4) <argumentVars>)
revert(<pos>, sub(<end>, <pos>)) revert(<pos>, sub(<end>, <pos>))
@ -1222,7 +1224,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
templ("pos", m_context.newYulVariable()); templ("pos", m_context.newYulVariable());
templ("end", m_context.newYulVariable()); templ("end", m_context.newYulVariable());
templ("hash", util::selectorFromSignature("Error(string)").str()); templ("hash", util::selectorFromSignature("Error(string)").str());
templ("allocateTemporary", m_utils.allocationTemporaryMemoryFunction()); templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
templ( templ(
"argumentVars", "argumentVars",
joinHumanReadablePrefixed(IRVariable{*arguments.front()}.stackSlots()) joinHumanReadablePrefixed(IRVariable{*arguments.front()}.stackSlots())
@ -1396,7 +1398,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
m_context.subObjectsCreated().insert(contract); m_context.subObjectsCreated().insert(contract);
Whiskers t(R"( Whiskers t(R"(
let <memPos> := <allocateTemporaryMemory>() let <memPos> := <allocateUnbounded>()
let <memEnd> := add(<memPos>, datasize("<object>")) let <memEnd> := add(<memPos>, datasize("<object>"))
if or(gt(<memEnd>, 0xffffffffffffffff), lt(<memEnd>, <memPos>)) { <panic>() } if or(gt(<memEnd>, 0xffffffffffffffff), lt(<memEnd>, <memPos>)) { <panic>() }
datacopy(<memPos>, dataoffset("<object>"), datasize("<object>")) datacopy(<memPos>, dataoffset("<object>"), datasize("<object>"))
@ -1411,12 +1413,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
<!isTryCall> <!isTryCall>
if iszero(<address>) { <forwardingRevert>() } if iszero(<address>) { <forwardingRevert>() }
</isTryCall> </isTryCall>
<releaseTemporaryMemory>()
)"); )");
t("memPos", m_context.newYulVariable()); t("memPos", m_context.newYulVariable());
t("memEnd", m_context.newYulVariable()); t("memEnd", m_context.newYulVariable());
t("allocateTemporaryMemory", m_utils.allocationTemporaryMemoryFunction()); t("allocateUnbounded", m_utils.allocateUnboundedFunction());
t("releaseTemporaryMemory", m_utils.releaseTemporaryMemoryFunction());
t("object", IRNames::creationObject(*contract)); t("object", IRNames::creationObject(*contract));
t("panic", m_utils.panicFunction(PanicCode::ResourceError)); t("panic", m_utils.panicFunction(PanicCode::ResourceError));
t("abiEncode", t("abiEncode",
@ -1489,7 +1489,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
argumentStrings += IRVariable(*arg).stackSlots(); argumentStrings += IRVariable(*arg).stackSlots();
} }
Whiskers templ(R"( Whiskers templ(R"(
let <pos> := <allocateTemporary>() let <pos> := <allocateUnbounded>()
let <end> := <encodeArgs>(<pos> <argumentString>) let <end> := <encodeArgs>(<pos> <argumentString>)
<?isECRecover> <?isECRecover>
mstore(0, 0) mstore(0, 0)
@ -1501,7 +1501,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
templ("call", m_context.evmVersion().hasStaticCall() ? "staticcall" : "call"); templ("call", m_context.evmVersion().hasStaticCall() ? "staticcall" : "call");
templ("isCall", !m_context.evmVersion().hasStaticCall()); templ("isCall", !m_context.evmVersion().hasStaticCall());
templ("shl", m_utils.shiftLeftFunction(offset * 8)); templ("shl", m_utils.shiftLeftFunction(offset * 8));
templ("allocateTemporary", m_utils.allocationTemporaryMemoryFunction()); templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
templ("pos", m_context.newYulVariable()); templ("pos", m_context.newYulVariable());
templ("end", m_context.newYulVariable()); templ("end", m_context.newYulVariable());
templ("isECRecover", FunctionType::Kind::ECRecover == functionType->kind()); templ("isECRecover", FunctionType::Kind::ECRecover == functionType->kind());
@ -2398,14 +2398,14 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
// We could also just use MLOAD; POP right before the gas calculation, but the optimizer // We could also just use MLOAD; POP right before the gas calculation, but the optimizer
// would remove that, so we use MSTORE here. // would remove that, so we use MSTORE here.
if (!funType.gasSet() && returnInfo.estimatedReturnSize > 0) if (!funType.gasSet() && returnInfo.estimatedReturnSize > 0)
m_code << "mstore(add(" << freeMemory() << ", " << to_string(returnInfo.estimatedReturnSize) << "), 0)\n"; m_code << "mstore(add(" << m_utils.allocateUnboundedFunction() << "() , " << to_string(returnInfo.estimatedReturnSize) << "), 0)\n";
} }
Whiskers templ(R"( Whiskers templ(R"(
if iszero(extcodesize(<address>)) { <revertNoCode> } if iszero(extcodesize(<address>)) { <revertNoCode> }
// storage for arguments and returned data // storage for arguments and returned data
let <pos> := <freeMemory> let <pos> := <allocateUnbounded>()
mstore(<pos>, <shl28>(<funSel>)) mstore(<pos>, <shl28>(<funSel>))
let <end> := <encodeArgs>(add(<pos>, 4) <argumentString>) let <end> := <encodeArgs>(add(<pos>, 4) <argumentString>)
@ -2421,7 +2421,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
</dynamicReturnSize> </dynamicReturnSize>
// update freeMemoryPointer according to dynamic return size // update freeMemoryPointer according to dynamic return size
mstore(<freeMemoryPointer>, add(<pos>, <roundUp>(<returnSize>))) <finalizeAllocation>(<pos>, <returnSize>)
// decode return parameters from external try-call into retVars // decode return parameters from external try-call into retVars
<?+retVars> <retVars> := </+retVars> <abiDecode>(<pos>, add(<pos>, <returnSize>)) <?+retVars> <retVars> := </+retVars> <abiDecode>(<pos>, add(<pos>, <returnSize>))
@ -2434,7 +2434,8 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
templ("success", IRNames::trySuccessConditionVariable(_functionCall)); templ("success", IRNames::trySuccessConditionVariable(_functionCall));
else else
templ("success", m_context.newYulVariable()); templ("success", m_context.newYulVariable());
templ("freeMemory", freeMemory()); templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
templ("finalizeAllocation", m_utils.finalizeAllocationFunction());
templ("shl28", m_utils.shiftLeftFunction(8 * (32 - 4))); templ("shl28", m_utils.shiftLeftFunction(8 * (32 - 4)));
templ("funSel", IRVariable(_functionCall.expression()).part("functionSelector").name()); templ("funSel", IRVariable(_functionCall.expression()).part("functionSelector").name());
@ -2456,7 +2457,6 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
templ("roundUp", m_utils.roundUpFunction()); templ("roundUp", m_utils.roundUpFunction());
templ("abiDecode", m_context.abiFunctions().tupleDecoder(returnInfo.returnTypes, true)); templ("abiDecode", m_context.abiFunctions().tupleDecoder(returnInfo.returnTypes, true));
templ("dynamicReturnSize", returnInfo.dynamicReturnSize); templ("dynamicReturnSize", returnInfo.dynamicReturnSize);
templ("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer));
templ("noTryCall", !_functionCall.annotation().tryCall); templ("noTryCall", !_functionCall.annotation().tryCall);
@ -2524,7 +2524,7 @@ void IRGeneratorForStatements::appendBareCall(
solAssert(!_functionCall.annotation().tryCall, ""); solAssert(!_functionCall.annotation().tryCall, "");
Whiskers templ(R"( Whiskers templ(R"(
<?needsEncoding> <?needsEncoding>
let <pos> := mload(<freeMemoryPointer>) let <pos> := <allocateUnbounded>()
let <length> := sub(<encode>(<pos> <?+arg>,</+arg> <arg>), <pos>) let <length> := sub(<encode>(<pos> <?+arg>,</+arg> <arg>), <pos>)
<!needsEncoding> <!needsEncoding>
let <pos> := add(<arg>, 0x20) let <pos> := add(<arg>, 0x20)
@ -2537,7 +2537,7 @@ void IRGeneratorForStatements::appendBareCall(
</+returndataVar> </+returndataVar>
)"); )");
templ("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer)); templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
templ("pos", m_context.newYulVariable()); templ("pos", m_context.newYulVariable());
templ("length", m_context.newYulVariable()); templ("length", m_context.newYulVariable());
@ -2597,11 +2597,6 @@ void IRGeneratorForStatements::appendBareCall(
m_code << templ.render(); m_code << templ.render();
} }
string IRGeneratorForStatements::freeMemory()
{
return "mload(" + to_string(CompilerUtils::freeMemoryPointer) + ")";
}
IRVariable IRGeneratorForStatements::convert(IRVariable const& _from, Type const& _to) IRVariable IRGeneratorForStatements::convert(IRVariable const& _from, Type const& _to)
{ {
if (_from.type() == _to) if (_from.type() == _to)

View File

@ -125,10 +125,6 @@ private:
std::vector<ASTPointer<Expression const>> const& _arguments std::vector<ASTPointer<Expression const>> const& _arguments
); );
/// @returns code that evaluates to the first unused memory slot (which does not have to
/// be empty).
static std::string freeMemory();
/// Generates the required conversion code and @returns an IRVariable referring to the value of @a _variable /// Generates the required conversion code and @returns an IRVariable referring to the value of @a _variable
/// converted to type @a _to. /// converted to type @a _to.
IRVariable convert(IRVariable const& _variable, Type const& _to); IRVariable convert(IRVariable const& _variable, Type const& _to);

View File

@ -39,7 +39,7 @@ object "C_81" {
if callvalue() { revert(0, 0) } if callvalue() { revert(0, 0) }
let param_0, param_1, param_2, param_3 := abi_decode_tuple_t_uint256t_uint256t_uint256t_uint256(4, calldatasize()) let param_0, param_1, param_2, param_3 := abi_decode_tuple_t_uint256t_uint256t_uint256t_uint256(4, calldatasize())
let ret_0, ret_1, ret_2, ret_3 := fun_f_80(param_0, param_1, param_2, param_3) let ret_0, ret_1, ret_2, ret_3 := fun_f_80(param_0, param_1, param_2, param_3)
let memPos := allocateMemory(0) let memPos := allocate_memory(0)
let memEnd := abi_encode_tuple_t_uint256_t_int256_t_uint256_t_uint256__to_t_uint256_t_int256_t_uint256_t_uint256__fromStack(memPos , ret_0, ret_1, ret_2, ret_3) let memEnd := abi_encode_tuple_t_uint256_t_int256_t_uint256_t_uint256__to_t_uint256_t_int256_t_uint256_t_uint256__fromStack(memPos , ret_0, ret_1, ret_2, ret_3)
return(memPos, sub(memEnd, memPos)) return(memPos, sub(memEnd, memPos))
} }
@ -108,12 +108,13 @@ object "C_81" {
} }
function allocateMemory(size) -> memPtr { function allocate_memory(size) -> memPtr {
memPtr := allocate_unbounded()
finalize_allocation(memPtr, size)
}
function allocate_unbounded() -> memPtr {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr)
} }
function checked_exp_t_rational_0_by_1_t_uint256(exponent) -> power { function checked_exp_t_rational_0_by_1_t_uint256(exponent) -> power {
@ -202,6 +203,13 @@ object "C_81" {
converted := cleanup_t_int256(value) converted := cleanup_t_int256(value)
} }
function finalize_allocation(memPtr, size) {
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr)
}
function fun_f_80(vloc_a_4, vloc_b_6, vloc_c_8, vloc_d_10) -> vloc__13, vloc__15, vloc__17, vloc__19 { function fun_f_80(vloc_a_4, vloc_b_6, vloc_c_8, vloc_d_10) -> vloc__13, vloc__15, vloc__17, vloc__19 {
let zero_value_for_type_t_uint256_1 := zero_value_for_split_t_uint256() let zero_value_for_type_t_uint256_1 := zero_value_for_split_t_uint256()
vloc__13 := zero_value_for_type_t_uint256_1 vloc__13 := zero_value_for_type_t_uint256_1

View File

@ -64,12 +64,12 @@ object "D_16" {
returndatacopy(_1, _1, returndatasize()) returndatacopy(_1, _1, returndatasize())
revert(_1, returndatasize()) revert(_1, returndatasize())
} }
return(allocateMemory(_1), _1) return(allocate_memory(_1), _1)
} }
} }
revert(0, 0) revert(0, 0)
} }
function allocateMemory(size) -> memPtr function allocate_memory(size) -> memPtr
{ {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, and(add(size, 31), not(31))) let newFreePtr := add(memPtr, and(add(size, 31), not(31)))

View File

@ -35,7 +35,7 @@ object "C_59" {
let _4 := calldataload(add(4, offset)) let _4 := calldataload(add(4, offset))
if gt(_4, _3) { panic_error_0x41() } if gt(_4, _3) { panic_error_0x41() }
let _5 := mul(_4, _2) let _5 := mul(_4, _2)
let dst := allocateMemory(add(_5, _2)) let dst := allocate_memory(add(_5, _2))
let dst_1 := dst let dst_1 := dst
mstore(dst, _4) mstore(dst, _4)
dst := add(dst, _2) dst := add(dst, _2)
@ -45,14 +45,14 @@ object "C_59" {
for { } lt(i, _4) { i := add(i, 1) } for { } lt(i, _4) { i := add(i, 1) }
{ {
if slt(sub(calldatasize(), src), _2) { revert(_1, _1) } if slt(sub(calldatasize(), src), _2) { revert(_1, _1) }
let value := allocateMemory(_2) let value := allocate_memory(_2)
mstore(value, calldataload(src)) mstore(value, calldataload(src))
mstore(dst, value) mstore(dst, value)
dst := add(dst, _2) dst := add(dst, _2)
src := add(src, _2) src := add(src, _2)
} }
let ret, ret_1 := fun_sumArray_58(dst_1) let ret, ret_1 := fun_sumArray_58(dst_1)
let memPos := allocateMemory(_1) let memPos := allocate_memory(_1)
return(memPos, sub(abi_encode_uint256_t_string(memPos, ret, ret_1), memPos)) return(memPos, sub(abi_encode_uint256_t_string(memPos, ret, ret_1), memPos))
} }
} }
@ -76,7 +76,7 @@ object "C_59" {
} }
tail := add(add(headStart, and(add(length, 31), not(31))), 96) tail := add(add(headStart, and(add(length, 31), not(31))), 96)
} }
function allocateMemory(size) -> memPtr function allocate_memory(size) -> memPtr
{ {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, and(add(size, 31), not(31))) let newFreePtr := add(memPtr, and(add(size, 31), not(31)))
@ -85,7 +85,7 @@ object "C_59" {
} }
function copy_literal_to_memory_64902fd228f7ef267f3b474dd6ef84bae434cf5546eee948e7ca26df3eda1927() -> memPtr function copy_literal_to_memory_64902fd228f7ef267f3b474dd6ef84bae434cf5546eee948e7ca26df3eda1927() -> memPtr
{ {
let memPtr_1 := allocateMemory(160) let memPtr_1 := allocate_memory(160)
mstore(memPtr_1, 100) mstore(memPtr_1, 100)
memPtr := memPtr_1 memPtr := memPtr_1
mstore(add(memPtr_1, 0x20), "longstringlongstringlongstringlo") mstore(add(memPtr_1, 0x20), "longstringlongstringlongstringlo")

View File

@ -40,7 +40,7 @@ object "Arraysum_34" {
mstore(_1, _1) mstore(_1, _1)
vloc_sum := checked_add_t_uint256(vloc_sum, sload(add(keccak256(_1, 0x20), vloc_i))) vloc_sum := checked_add_t_uint256(vloc_sum, sload(add(keccak256(_1, 0x20), vloc_i)))
} }
let memPos := allocateMemory(_1) let memPos := allocate_memory(_1)
return(memPos, sub(abi_encode_uint(memPos, vloc_sum), memPos)) return(memPos, sub(abi_encode_uint(memPos, vloc_sum), memPos))
} }
} }
@ -51,7 +51,7 @@ object "Arraysum_34" {
tail := add(headStart, 32) tail := add(headStart, 32)
mstore(headStart, value0) mstore(headStart, value0)
} }
function allocateMemory(size) -> memPtr function allocate_memory(size) -> memPtr
{ {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, and(add(size, 31), not(31))) let newFreePtr := add(memPtr, and(add(size, 31), not(31)))

File diff suppressed because one or more lines are too long

View File

@ -26,7 +26,7 @@ object \"C_7\" {
if callvalue() { revert(0, 0) } if callvalue() { revert(0, 0) }
abi_decode_tuple_(4, calldatasize()) abi_decode_tuple_(4, calldatasize())
fun_f_6() fun_f_6()
let memPos := allocateMemory(0) let memPos := allocate_memory(0)
let memEnd := abi_encode_tuple__to__fromStack(memPos) let memEnd := abi_encode_tuple__to__fromStack(memPos)
return(memPos, sub(memEnd, memPos)) return(memPos, sub(memEnd, memPos))
} }
@ -40,9 +40,15 @@ object \"C_7\" {
} }
function abi_encode_tuple__to__fromStack(headStart) -> tail function abi_encode_tuple__to__fromStack(headStart) -> tail
{ tail := add(headStart, 0) } { tail := add(headStart, 0) }
function allocateMemory(size) -> memPtr function allocate_memory(size) -> memPtr
{
memPtr := allocate_unbounded()
finalize_allocation(memPtr, size)
}
function allocate_unbounded() -> memPtr
{ memPtr := mload(64) }
function finalize_allocation(memPtr, size)
{ {
memPtr := mload(64)
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr) mstore(64, newFreePtr)

View File

@ -38,7 +38,7 @@ object \"C_7\" {
if callvalue() { revert(0, 0) } if callvalue() { revert(0, 0) }
abi_decode_tuple_(4, calldatasize()) abi_decode_tuple_(4, calldatasize())
fun_f_6() fun_f_6()
let memPos := allocateMemory(0) let memPos := allocate_memory(0)
let memEnd := abi_encode_tuple__to__fromStack(memPos ) let memEnd := abi_encode_tuple__to__fromStack(memPos )
return(memPos, sub(memEnd, memPos)) return(memPos, sub(memEnd, memPos))
} }
@ -58,8 +58,16 @@ object \"C_7\" {
} }
function allocateMemory(size) -> memPtr { function allocate_memory(size) -> memPtr {
memPtr := allocate_unbounded()
finalize_allocation(memPtr, size)
}
function allocate_unbounded() -> memPtr {
memPtr := mload(64) memPtr := mload(64)
}
function finalize_allocation(memPtr, size) {
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
// protect against overflow // protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }

View File

@ -89,7 +89,7 @@ object \"D_16\" {
if callvalue() { revert(0, 0) } if callvalue() { revert(0, 0) }
abi_decode_tuple_(4, calldatasize()) abi_decode_tuple_(4, calldatasize())
fun_f_15() fun_f_15()
let memPos := allocateMemory(0) let memPos := allocate_memory(0)
let memEnd := abi_encode_tuple__to__fromStack(memPos ) let memEnd := abi_encode_tuple__to__fromStack(memPos )
return(memPos, sub(memEnd, memPos)) return(memPos, sub(memEnd, memPos))
} }
@ -109,21 +109,25 @@ object \"D_16\" {
} }
function allocateMemory(size) -> memPtr { function allocate_memory(size) -> memPtr {
memPtr := allocate_unbounded()
finalize_allocation(memPtr, size)
}
function allocate_unbounded() -> memPtr {
memPtr := mload(64) memPtr := mload(64)
}
function finalize_allocation(memPtr, size) {
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
// protect against overflow // protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr) mstore(64, newFreePtr)
} }
function allocateTemporaryMemory() -> memPtr {
memPtr := mload(64)
}
function fun_f_15() { function fun_f_15() {
let _1 := allocateTemporaryMemory() let _1 := allocate_unbounded()
let _2 := add(_1, datasize(\"C_3\")) let _2 := add(_1, datasize(\"C_3\"))
if or(gt(_2, 0xffffffffffffffff), lt(_2, _1)) { panic_error_0x41() } if or(gt(_2, 0xffffffffffffffff), lt(_2, _1)) { panic_error_0x41() }
datacopy(_1, dataoffset(\"C_3\"), datasize(\"C_3\")) datacopy(_1, dataoffset(\"C_3\"), datasize(\"C_3\"))
@ -133,7 +137,6 @@ object \"D_16\" {
if iszero(expr_12_address) { revert_forward_1() } if iszero(expr_12_address) { revert_forward_1() }
releaseTemporaryMemory()
let vloc_c_8_address := expr_12_address let vloc_c_8_address := expr_12_address
} }
@ -144,9 +147,6 @@ object \"D_16\" {
revert(0, 0x24) revert(0, 0x24)
} }
function releaseTemporaryMemory() {
}
function revert_forward_1() { function revert_forward_1() {
returndatacopy(0, 0, returndatasize()) returndatacopy(0, 0, returndatasize())
revert(0, returndatasize()) revert(0, returndatasize())

View File

@ -39,7 +39,7 @@ object "test_11" {
if callvalue() { revert(0, 0) } if callvalue() { revert(0, 0) }
abi_decode_tuple_(4, calldatasize()) abi_decode_tuple_(4, calldatasize())
let ret_0 := fun_f_10() let ret_0 := fun_f_10()
let memPos := allocateMemory(0) let memPos := allocate_memory(0)
let memEnd := abi_encode_tuple_t_bool__to_t_bool__fromStack(memPos , ret_0) let memEnd := abi_encode_tuple_t_bool__to_t_bool__fromStack(memPos , ret_0)
return(memPos, sub(memEnd, memPos)) return(memPos, sub(memEnd, memPos))
} }
@ -65,18 +65,26 @@ object "test_11" {
} }
function allocateMemory(size) -> memPtr { function allocate_memory(size) -> memPtr {
memPtr := allocate_unbounded()
finalize_allocation(memPtr, size)
}
function allocate_unbounded() -> memPtr {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr)
} }
function cleanup_t_bool(value) -> cleaned { function cleanup_t_bool(value) -> cleaned {
cleaned := iszero(iszero(value)) cleaned := iszero(iszero(value))
} }
function finalize_allocation(memPtr, size) {
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr)
}
function fun_f_10() -> vloc__5 { function fun_f_10() -> vloc__5 {
let zero_value_for_type_t_bool_1 := zero_value_for_split_t_bool() let zero_value_for_type_t_bool_1 := zero_value_for_split_t_bool()
vloc__5 := zero_value_for_type_t_bool_1 vloc__5 := zero_value_for_type_t_bool_1

View File

@ -76,12 +76,12 @@ object "D_16" {
returndatacopy(_1, _1, returndatasize()) returndatacopy(_1, _1, returndatasize())
revert(_1, returndatasize()) revert(_1, returndatasize())
} }
return(allocateMemory(_1), _1) return(allocate_memory(_1), _1)
} }
} }
revert(0, 0) revert(0, 0)
} }
function allocateMemory(size) -> memPtr function allocate_memory(size) -> memPtr
{ {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, and(add(size, 31), not(31))) let newFreePtr := add(memPtr, and(add(size, 31), not(31)))

View File

@ -38,7 +38,7 @@ object \"C_11\" {
if callvalue() { revert(0, 0) } if callvalue() { revert(0, 0) }
abi_decode_tuple_(4, calldatasize()) abi_decode_tuple_(4, calldatasize())
let ret_0 := fun_f_10() let ret_0 := fun_f_10()
let memPos := allocateMemory(0) let memPos := allocate_memory(0)
let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0)
return(memPos, sub(memEnd, memPos)) return(memPos, sub(memEnd, memPos))
} }
@ -68,22 +68,23 @@ object \"C_11\" {
} }
function allocateMemory(size) -> memPtr { function allocate_memory(size) -> memPtr {
memPtr := mload(64) memPtr := allocate_unbounded()
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) finalize_allocation(memPtr, size)
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr)
} }
function allocate_memory_array_t_string_memory_ptr(length) -> memPtr { function allocate_memory_array_t_string_memory_ptr(length) -> memPtr {
let allocSize := array_allocation_size_t_string_memory_ptr(length) let allocSize := array_allocation_size_t_string_memory_ptr(length)
memPtr := allocateMemory(allocSize) memPtr := allocate_memory(allocSize)
mstore(memPtr, length) mstore(memPtr, length)
} }
function allocate_unbounded() -> memPtr {
memPtr := mload(64)
}
function array_allocation_size_t_string_memory_ptr(length) -> size { function array_allocation_size_t_string_memory_ptr(length) -> size {
// Make sure we can allocate memory without overflow // Make sure we can allocate memory without overflow
if gt(length, 0xffffffffffffffff) { panic_error_0x41() } if gt(length, 0xffffffffffffffff) { panic_error_0x41() }
@ -128,6 +129,13 @@ object \"C_11\" {
} }
} }
function finalize_allocation(memPtr, size) {
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr)
}
function fun_f_10() -> vloc__5_mpos { function fun_f_10() -> vloc__5_mpos {
let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr() let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr()
vloc__5_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos vloc__5_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos

View File

@ -38,7 +38,7 @@ object \"C_11\" {
if callvalue() { revert(0, 0) } if callvalue() { revert(0, 0) }
abi_decode_tuple_(4, calldatasize()) abi_decode_tuple_(4, calldatasize())
let ret_0 := fun_f_10() let ret_0 := fun_f_10()
let memPos := allocateMemory(0) let memPos := allocate_memory(0)
let memEnd := abi_encode_tuple_t_bytes32__to_t_bytes32__fromStack(memPos , ret_0) let memEnd := abi_encode_tuple_t_bytes32__to_t_bytes32__fromStack(memPos , ret_0)
return(memPos, sub(memEnd, memPos)) return(memPos, sub(memEnd, memPos))
} }
@ -64,12 +64,13 @@ object \"C_11\" {
} }
function allocateMemory(size) -> memPtr { function allocate_memory(size) -> memPtr {
memPtr := allocate_unbounded()
finalize_allocation(memPtr, size)
}
function allocate_unbounded() -> memPtr {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr)
} }
function cleanup_t_bytes32(value) -> cleaned { function cleanup_t_bytes32(value) -> cleaned {
@ -80,6 +81,13 @@ object \"C_11\" {
converted := 0x6162636162630000000000000000000000000000000000000000000000000000 converted := 0x6162636162630000000000000000000000000000000000000000000000000000
} }
function finalize_allocation(memPtr, size) {
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr)
}
function fun_f_10() -> vloc__5 { function fun_f_10() -> vloc__5 {
let zero_value_for_type_t_bytes32_1 := zero_value_for_split_t_bytes32() let zero_value_for_type_t_bytes32_1 := zero_value_for_split_t_bytes32()
vloc__5 := zero_value_for_type_t_bytes32_1 vloc__5 := zero_value_for_type_t_bytes32_1

View File

@ -38,7 +38,7 @@ object \"C_11\" {
if callvalue() { revert(0, 0) } if callvalue() { revert(0, 0) }
abi_decode_tuple_(4, calldatasize()) abi_decode_tuple_(4, calldatasize())
let ret_0 := fun_f_10() let ret_0 := fun_f_10()
let memPos := allocateMemory(0) let memPos := allocate_memory(0)
let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0)
return(memPos, sub(memEnd, memPos)) return(memPos, sub(memEnd, memPos))
} }
@ -64,12 +64,13 @@ object \"C_11\" {
} }
function allocateMemory(size) -> memPtr { function allocate_memory(size) -> memPtr {
memPtr := allocate_unbounded()
finalize_allocation(memPtr, size)
}
function allocate_unbounded() -> memPtr {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr)
} }
function cleanup_t_bytes4(value) -> cleaned { function cleanup_t_bytes4(value) -> cleaned {
@ -84,6 +85,13 @@ object \"C_11\" {
converted := shift_left_224(cleanup_t_rational_1633837924_by_1(value)) converted := shift_left_224(cleanup_t_rational_1633837924_by_1(value))
} }
function finalize_allocation(memPtr, size) {
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr)
}
function fun_f_10() -> vloc__5 { function fun_f_10() -> vloc__5 {
let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4() let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4()
vloc__5 := zero_value_for_type_t_bytes4_1 vloc__5 := zero_value_for_type_t_bytes4_1

View File

@ -38,7 +38,7 @@ object \"C_11\" {
if callvalue() { revert(0, 0) } if callvalue() { revert(0, 0) }
abi_decode_tuple_(4, calldatasize()) abi_decode_tuple_(4, calldatasize())
let ret_0 := fun_f_10() let ret_0 := fun_f_10()
let memPos := allocateMemory(0) let memPos := allocate_memory(0)
let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0)
return(memPos, sub(memEnd, memPos)) return(memPos, sub(memEnd, memPos))
} }
@ -68,22 +68,23 @@ object \"C_11\" {
} }
function allocateMemory(size) -> memPtr { function allocate_memory(size) -> memPtr {
memPtr := mload(64) memPtr := allocate_unbounded()
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) finalize_allocation(memPtr, size)
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr)
} }
function allocate_memory_array_t_string_memory_ptr(length) -> memPtr { function allocate_memory_array_t_string_memory_ptr(length) -> memPtr {
let allocSize := array_allocation_size_t_string_memory_ptr(length) let allocSize := array_allocation_size_t_string_memory_ptr(length)
memPtr := allocateMemory(allocSize) memPtr := allocate_memory(allocSize)
mstore(memPtr, length) mstore(memPtr, length)
} }
function allocate_unbounded() -> memPtr {
memPtr := mload(64)
}
function array_allocation_size_t_string_memory_ptr(length) -> size { function array_allocation_size_t_string_memory_ptr(length) -> size {
// Make sure we can allocate memory without overflow // Make sure we can allocate memory without overflow
if gt(length, 0xffffffffffffffff) { panic_error_0x41() } if gt(length, 0xffffffffffffffff) { panic_error_0x41() }
@ -128,6 +129,13 @@ object \"C_11\" {
} }
} }
function finalize_allocation(memPtr, size) {
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr)
}
function fun_f_10() -> vloc__5_mpos { function fun_f_10() -> vloc__5_mpos {
let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr() let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr()
vloc__5_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos vloc__5_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos

View File

@ -38,7 +38,7 @@ object \"C_11\" {
if callvalue() { revert(0, 0) } if callvalue() { revert(0, 0) }
abi_decode_tuple_(4, calldatasize()) abi_decode_tuple_(4, calldatasize())
let ret_0 := fun_f_10() let ret_0 := fun_f_10()
let memPos := allocateMemory(0) let memPos := allocate_memory(0)
let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0)
return(memPos, sub(memEnd, memPos)) return(memPos, sub(memEnd, memPos))
} }
@ -64,12 +64,13 @@ object \"C_11\" {
} }
function allocateMemory(size) -> memPtr { function allocate_memory(size) -> memPtr {
memPtr := allocate_unbounded()
finalize_allocation(memPtr, size)
}
function allocate_unbounded() -> memPtr {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr)
} }
function cleanup_t_bytes4(value) -> cleaned { function cleanup_t_bytes4(value) -> cleaned {
@ -84,6 +85,13 @@ object \"C_11\" {
converted := shift_left_224(cleanup_t_rational_2864434397_by_1(value)) converted := shift_left_224(cleanup_t_rational_2864434397_by_1(value))
} }
function finalize_allocation(memPtr, size) {
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr)
}
function fun_f_10() -> vloc__5 { function fun_f_10() -> vloc__5 {
let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4() let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4()
vloc__5 := zero_value_for_type_t_bytes4_1 vloc__5 := zero_value_for_type_t_bytes4_1

View File

@ -14,9 +14,9 @@ contract C {
} }
// ---- // ----
// creation: // creation:
// codeDepositCost: 1175600 // codeDepositCost: 1181400
// executionCost: 1221 // executionCost: 1227
// totalCost: 1176821 // totalCost: 1182627
// external: // external:
// a(): 1130 // a(): 1130
// b(uint256): infinite // b(uint256): infinite

View File

@ -14,7 +14,6 @@ contract C {
} }
} }
} }
// ==== // ====
// compileViaYul: also // compileViaYul: also
// ---- // ----