mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8863 from ethereum/nonReversedEncoder
Introduce non-reversed version of tupleEncoder.
This commit is contained in:
commit
f42dc70c9f
@ -37,7 +37,8 @@ using namespace solidity::frontend;
|
||||
string ABIFunctions::tupleEncoder(
|
||||
TypePointers const& _givenTypes,
|
||||
TypePointers const& _targetTypes,
|
||||
bool _encodeAsLibraryTypes
|
||||
bool _encodeAsLibraryTypes,
|
||||
bool _reversed
|
||||
)
|
||||
{
|
||||
EncodingOptions options;
|
||||
@ -53,6 +54,8 @@ string ABIFunctions::tupleEncoder(
|
||||
for (auto const& t: _targetTypes)
|
||||
functionName += t->identifier() + "_";
|
||||
functionName += options.toFunctionNameSuffix();
|
||||
if (_reversed)
|
||||
functionName += "_reversed";
|
||||
|
||||
return createFunction(functionName, [&]() {
|
||||
// Note that the values are in reverse due to the difference in calling semantics.
|
||||
@ -93,7 +96,10 @@ string ABIFunctions::tupleEncoder(
|
||||
stackPos += sizeOnStack;
|
||||
}
|
||||
solAssert(headPos == headSize_, "");
|
||||
string valueParams = suffixedVariableNameList("value", stackPos, 0);
|
||||
string valueParams =
|
||||
_reversed ?
|
||||
suffixedVariableNameList("value", stackPos, 0) :
|
||||
suffixedVariableNameList("value", 0, stackPos);
|
||||
templ("valueParams", valueParams.empty() ? "" : ", " + valueParams);
|
||||
templ("encodeElements", encodeElements);
|
||||
|
||||
@ -103,7 +109,8 @@ string ABIFunctions::tupleEncoder(
|
||||
|
||||
string ABIFunctions::tupleEncoderPacked(
|
||||
TypePointers const& _givenTypes,
|
||||
TypePointers const& _targetTypes
|
||||
TypePointers const& _targetTypes,
|
||||
bool _reversed
|
||||
)
|
||||
{
|
||||
EncodingOptions options;
|
||||
@ -119,6 +126,8 @@ string ABIFunctions::tupleEncoderPacked(
|
||||
for (auto const& t: _targetTypes)
|
||||
functionName += t->identifier() + "_";
|
||||
functionName += options.toFunctionNameSuffix();
|
||||
if (_reversed)
|
||||
functionName += "_reversed";
|
||||
|
||||
return createFunction(functionName, [&]() {
|
||||
solAssert(!_givenTypes.empty(), "");
|
||||
@ -157,7 +166,10 @@ string ABIFunctions::tupleEncoderPacked(
|
||||
encodeElements += elementTempl.render();
|
||||
stackPos += sizeOnStack;
|
||||
}
|
||||
string valueParams = suffixedVariableNameList("value", stackPos, 0);
|
||||
string valueParams =
|
||||
_reversed ?
|
||||
suffixedVariableNameList("value", stackPos, 0) :
|
||||
suffixedVariableNameList("value", 0, stackPos);
|
||||
templ("valueParams", valueParams.empty() ? "" : ", " + valueParams);
|
||||
templ("encodeElements", encodeElements);
|
||||
|
||||
|
@ -67,31 +67,53 @@ public:
|
||||
|
||||
/// @returns name of an assembly function to ABI-encode values of @a _givenTypes
|
||||
/// into memory, converting the types to @a _targetTypes on the fly.
|
||||
/// Parameters are: <headStart> <value_n> ... <value_1>, i.e.
|
||||
/// the layout on the stack is <value_1> ... <value_n> <headStart> with
|
||||
/// Parameters are: <headStart> <value_1> ... <value_n>, i.e.
|
||||
/// the layout on the stack is <value_n> ... <value_1> <headStart> with
|
||||
/// the top of the stack on the right.
|
||||
/// The values represent stack slots. If a type occupies more or less than one
|
||||
/// stack slot, it takes exactly that number of values.
|
||||
/// Returns a pointer to the end of the area written in memory.
|
||||
/// Does not allocate memory (does not change the free memory pointer), but writes
|
||||
/// to memory starting at $headStart and an unrestricted amount after that.
|
||||
/// If @reversed is true, the order of the variables after <headStart> is reversed.
|
||||
std::string tupleEncoder(
|
||||
TypePointers const& _givenTypes,
|
||||
TypePointers const& _targetTypes,
|
||||
bool _encodeAsLibraryTypes = false
|
||||
bool _encodeAsLibraryTypes = false,
|
||||
bool _reversed = false
|
||||
);
|
||||
|
||||
/// Specialization of tupleEncoder to _reversed = true
|
||||
std::string tupleEncoderReversed(
|
||||
TypePointers const& _givenTypes,
|
||||
TypePointers const& _targetTypes,
|
||||
bool _encodeAsLibraryTypes = false
|
||||
) {
|
||||
return tupleEncoder(_givenTypes, _targetTypes, _encodeAsLibraryTypes, true);
|
||||
}
|
||||
|
||||
/// @returns name of an assembly function to encode values of @a _givenTypes
|
||||
/// with packed encoding into memory, converting the types to @a _targetTypes on the fly.
|
||||
/// Parameters are: <memPos> <value_n> ... <value_1>, i.e.
|
||||
/// the layout on the stack is <value_1> ... <value_n> <memPos> with
|
||||
/// Parameters are: <memPos> <value_1> ... <value_n>, i.e.
|
||||
/// the layout on the stack is <value_n> ... <value_1> <memPos> with
|
||||
/// the top of the stack on the right.
|
||||
/// The values represent stack slots. If a type occupies more or less than one
|
||||
/// stack slot, it takes exactly that number of values.
|
||||
/// Returns a pointer to the end of the area written in memory.
|
||||
/// Does not allocate memory (does not change the free memory pointer), but writes
|
||||
/// to memory starting at memPos and an unrestricted amount after that.
|
||||
std::string tupleEncoderPacked(TypePointers const& _givenTypes, TypePointers const& _targetTypes);
|
||||
/// If @reversed is true, the order of the variables after <headStart> is reversed.
|
||||
std::string tupleEncoderPacked(
|
||||
TypePointers const& _givenTypes,
|
||||
TypePointers const& _targetTypes,
|
||||
bool _reversed = false
|
||||
);
|
||||
|
||||
/// Specialization of tupleEncoderPacked to _reversed = true
|
||||
std::string tupleEncoderPackedReversed(TypePointers const& _givenTypes, TypePointers const& _targetTypes)
|
||||
{
|
||||
return tupleEncoderPacked(_givenTypes, _targetTypes, true);
|
||||
}
|
||||
|
||||
/// @returns name of an assembly function to ABI-decode values of @a _types
|
||||
/// into memory. If @a _fromMemory is true, decodes from memory instead of
|
||||
|
@ -559,8 +559,8 @@ void CompilerUtils::abiEncodeV2(
|
||||
|
||||
string encoderName =
|
||||
_padToWordBoundaries ?
|
||||
m_context.abiFunctions().tupleEncoder(_givenTypes, _targetTypes, _encodeAsLibraryTypes) :
|
||||
m_context.abiFunctions().tupleEncoderPacked(_givenTypes, _targetTypes);
|
||||
m_context.abiFunctions().tupleEncoderReversed(_givenTypes, _targetTypes, _encodeAsLibraryTypes) :
|
||||
m_context.abiFunctions().tupleEncoderPackedReversed(_givenTypes, _targetTypes);
|
||||
m_context.callYulFunction(encoderName, sizeOnStack(_givenTypes) + 1, 1);
|
||||
}
|
||||
|
||||
|
@ -1122,13 +1122,12 @@ string YulUtilFunctions::mappingIndexAccessFunction(MappingType const& _mappingT
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
if (_mappingType.keyType()->isDynamicallySized())
|
||||
return Whiskers(R"(
|
||||
function <functionName>(slot <comma> <key>) -> dataSlot {
|
||||
dataSlot := <hash>(slot <comma> <key>)
|
||||
function <functionName>(slot <?+key>,</+key> <key>) -> dataSlot {
|
||||
dataSlot := <hash>(<key> <?+key>,</+key> slot)
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("key", _keyType.sizeOnStack() > 0 ? "key" : "")
|
||||
("comma", _keyType.sizeOnStack() > 0 ? "," : "")
|
||||
("hash", packedHashFunction(
|
||||
{&_keyType, TypeProvider::uint256()},
|
||||
{_mappingType.keyType(), TypeProvider::uint256()}
|
||||
|
@ -479,10 +479,10 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
||||
{
|
||||
// <functionName>
|
||||
<callValueCheck>
|
||||
<assignToParams> <abiDecode>(4, calldatasize())
|
||||
<assignToRetParams> <function>(<params>)
|
||||
<?+params>let <params> := </+params> <abiDecode>(4, calldatasize())
|
||||
<?+retParams>let <retParams> := </+retParams> <function>(<params>)
|
||||
let memPos := <allocate>(0)
|
||||
let memEnd := <abiEncode>(memPos <comma> <retParams>)
|
||||
let memEnd := <abiEncode>(memPos <?+retParams>,</+retParams> <retParams>)
|
||||
return(memPos, sub(memEnd, memPos))
|
||||
}
|
||||
</cases>
|
||||
@ -504,13 +504,11 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
||||
|
||||
unsigned paramVars = make_shared<TupleType>(type->parameterTypes())->sizeOnStack();
|
||||
unsigned retVars = make_shared<TupleType>(type->returnParameterTypes())->sizeOnStack();
|
||||
templ["assignToParams"] = paramVars == 0 ? "" : "let " + suffixedVariableNameList("param_", 0, paramVars) + " := ";
|
||||
templ["assignToRetParams"] = retVars == 0 ? "" : "let " + suffixedVariableNameList("ret_", 0, retVars) + " := ";
|
||||
|
||||
ABIFunctions abiFunctions(m_evmVersion, m_context.revertStrings(), m_context.functionCollector());
|
||||
templ["abiDecode"] = abiFunctions.tupleDecoder(type->parameterTypes());
|
||||
templ["params"] = suffixedVariableNameList("param_", 0, paramVars);
|
||||
templ["retParams"] = suffixedVariableNameList("ret_", retVars, 0);
|
||||
templ["retParams"] = suffixedVariableNameList("ret_", 0, retVars);
|
||||
|
||||
if (FunctionDefinition const* funDef = dynamic_cast<FunctionDefinition const*>(&type->declaration()))
|
||||
templ["function"] = m_context.enqueueFunctionForCodeGeneration(*funDef);
|
||||
@ -521,7 +519,6 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
||||
|
||||
templ["allocate"] = m_utils.allocationFunction();
|
||||
templ["abiEncode"] = abiFunctions.tupleEncoder(type->returnParameterTypes(), type->returnParameterTypes(), false);
|
||||
templ["comma"] = retVars == 0 ? "" : ", ";
|
||||
}
|
||||
t("cases", functions);
|
||||
if (FunctionDefinition const* fallback = _contract.fallbackFunction())
|
||||
|
@ -741,8 +741,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
{
|
||||
string vars = IRVariable(arg).commaSeparatedList();
|
||||
if (!vars.empty())
|
||||
// In reverse because abi_encode expects it like that.
|
||||
nonIndexedArgs = ", " + move(vars) + nonIndexedArgs;
|
||||
nonIndexedArgs += ", " + move(vars);
|
||||
nonIndexedArgTypes.push_back(arg.annotation().type);
|
||||
nonIndexedParamTypes.push_back(paramTypes[i]);
|
||||
}
|
||||
@ -1022,7 +1021,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
t("releaseTemporaryMemory", m_utils.releaseTemporaryMemoryFunction());
|
||||
t("object", m_context.creationObjectName(*contract));
|
||||
t("abiEncode",
|
||||
m_context.abiFunctions().tupleEncoder(argumentTypes, functionType->parameterTypes(),false)
|
||||
m_context.abiFunctions().tupleEncoder(argumentTypes, functionType->parameterTypes(), false)
|
||||
);
|
||||
t("constructorParams", constructorParams);
|
||||
t("value", functionType->valueSet() ? IRVariable(_functionCall.expression()).part("value").name() : "0");
|
||||
|
@ -38,7 +38,7 @@ object \"C_10\" {
|
||||
abi_decode_tuple_(4, calldatasize())
|
||||
let ret_0 := fun_f_9()
|
||||
let memPos := allocateMemory(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))
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ object \"C_10\" {
|
||||
abi_decode_tuple_(4, calldatasize())
|
||||
let ret_0 := fun_f_9()
|
||||
let memPos := allocateMemory(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))
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ object \"C_10\" {
|
||||
abi_decode_tuple_(4, calldatasize())
|
||||
let ret_0 := fun_f_9()
|
||||
let memPos := allocateMemory(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))
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ object \"C_10\" {
|
||||
abi_decode_tuple_(4, calldatasize())
|
||||
let ret_0 := fun_f_9()
|
||||
let memPos := allocateMemory(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))
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ object \"C_10\" {
|
||||
abi_decode_tuple_(4, calldatasize())
|
||||
let ret_0 := fun_f_9()
|
||||
let memPos := allocateMemory(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))
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,8 @@ contract C {
|
||||
return this.f(x);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g(uint256[][2][]): 0x20, 0x01, 0x20, 0x40, 0x60, 0x00, 0x00 -> 42
|
||||
// g(uint256[][2][]): 0x20, 0x01, 0x20, 0x00, 0x00 -> 42
|
||||
|
@ -16,6 +16,8 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(uint256): 7 -> 8
|
||||
// f2(uint256): 7 -> 8
|
||||
|
Loading…
Reference in New Issue
Block a user