mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Cleanup allocation.
This commit is contained in:
parent
2cc1e3393f
commit
3cc07694ed
@ -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))
|
||||||
@ -2308,19 +2308,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
|
||||||
@ -2331,10 +2331,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) } {
|
||||||
@ -2800,28 +2800,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 {
|
||||||
@ -2834,15 +2830,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();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -3633,7 +3636,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))
|
||||||
}
|
}
|
||||||
@ -3641,7 +3644,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();
|
||||||
});
|
});
|
||||||
@ -4157,7 +4160,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)
|
||||||
@ -4175,13 +4178,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();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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) ->
|
||||||
|
@ -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());
|
||||||
@ -2363,14 +2363,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>)
|
||||||
|
|
||||||
@ -2386,7 +2386,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>))
|
||||||
@ -2399,7 +2399,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());
|
||||||
@ -2421,7 +2422,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);
|
||||||
|
|
||||||
@ -2489,7 +2489,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)
|
||||||
@ -2502,7 +2502,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());
|
||||||
|
|
||||||
@ -2562,11 +2562,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)
|
||||||
|
@ -124,10 +124,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);
|
||||||
|
@ -14,7 +14,6 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ====
|
// ====
|
||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
|
Loading…
Reference in New Issue
Block a user