Merge pull request #6348 from ethereum/varNameGenerator

ABIFunctions: Split out a function for generating a comma separated list of variable names.
This commit is contained in:
chriseth 2019-03-25 14:07:35 +01:00 committed by GitHub
commit 58610ab3b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 24 deletions

View File

@ -63,7 +63,6 @@ string ABIFunctions::tupleEncoder(
templ("functionName", functionName);
size_t const headSize_ = headSize(_targetTypes);
templ("headSize", to_string(headSize_));
string valueParams;
string encodeElements;
size_t headPos = 0;
size_t stackPos = 0;
@ -72,13 +71,6 @@ string ABIFunctions::tupleEncoder(
solAssert(_givenTypes[i], "");
solAssert(_targetTypes[i], "");
size_t sizeOnStack = _givenTypes[i]->sizeOnStack();
string valueNames = "";
for (size_t j = 0; j < sizeOnStack; j++)
{
valueNames += "value" + to_string(stackPos) + ", ";
valueParams = ", value" + to_string(stackPos) + valueParams;
stackPos++;
}
bool dynamic = _targetTypes[i]->isDynamicallyEncoded();
Whiskers elementTempl(
dynamic ?
@ -90,14 +82,17 @@ string ABIFunctions::tupleEncoder(
<abiEncode>(<values> add(headStart, <pos>))
)")
);
elementTempl("values", valueNames);
string values = suffixedVariableNameList("value", stackPos, stackPos + sizeOnStack);
elementTempl("values", values.empty() ? "" : values + ", ");
elementTempl("pos", to_string(headPos));
elementTempl("abiEncode", abiEncodingFunction(*_givenTypes[i], *_targetTypes[i], options));
encodeElements += elementTempl.render();
headPos += dynamic ? 0x20 : _targetTypes[i]->calldataEncodedSize();
stackPos += sizeOnStack;
}
solAssert(headPos == headSize_, "");
templ("valueParams", valueParams);
string valueParams = suffixedVariableNameList("value", stackPos, 0);
templ("valueParams", valueParams.empty() ? "" : ", " + valueParams);
templ("encodeElements", encodeElements);
return templ.render();
@ -134,7 +129,6 @@ string ABIFunctions::tupleEncoderPacked(
}
)");
templ("functionName", functionName);
string valueParams;
string encodeElements;
size_t stackPos = 0;
for (size_t i = 0; i < _givenTypes.size(); ++i)
@ -142,13 +136,6 @@ string ABIFunctions::tupleEncoderPacked(
solAssert(_givenTypes[i], "");
solAssert(_targetTypes[i], "");
size_t sizeOnStack = _givenTypes[i]->sizeOnStack();
string valueNames = "";
for (size_t j = 0; j < sizeOnStack; j++)
{
valueNames += "value" + to_string(stackPos) + ", ";
valueParams = ", value" + to_string(stackPos) + valueParams;
stackPos++;
}
bool dynamic = _targetTypes[i]->isDynamicallyEncoded();
Whiskers elementTempl(
dynamic ?
@ -160,13 +147,16 @@ string ABIFunctions::tupleEncoderPacked(
pos := add(pos, <calldataEncodedSize>)
)")
);
elementTempl("values", valueNames);
string values = suffixedVariableNameList("value", stackPos, stackPos + sizeOnStack);
elementTempl("values", values.empty() ? "" : values + ", ");
if (!dynamic)
elementTempl("calldataEncodedSize", to_string(_targetTypes[i]->calldataEncodedSize(false)));
elementTempl("abiEncode", abiEncodingFunction(*_givenTypes[i], *_targetTypes[i], options));
encodeElements += elementTempl.render();
stackPos += sizeOnStack;
}
templ("valueParams", valueParams);
string valueParams = suffixedVariableNameList("value", stackPos, 0);
templ("valueParams", valueParams.empty() ? "" : ", " + valueParams);
templ("encodeElements", encodeElements);
return templ.render();
@ -636,29 +626,32 @@ string ABIFunctions::abiEncodeAndReturnUpdatedPosFunction(
_targetType.identifier() +
_options.toFunctionNameSuffix();
return createFunction(functionName, [&]() {
string values = suffixedVariableNameList("value", 0, numVariablesForType(_givenType, _options));
string encoder = abiEncodingFunction(_givenType, _targetType, _options);
if (_targetType.isDynamicallyEncoded())
return Whiskers(R"(
function <functionName>(value, pos) -> updatedPos {
updatedPos := <encode>(value, pos)
function <functionName>(<values>, pos) -> updatedPos {
updatedPos := <encode>(<values>, pos)
}
)")
("functionName", functionName)
("encode", encoder)
("values", values)
.render();
else
{
unsigned encodedSize = _targetType.calldataEncodedSize(_options.padded);
solAssert(encodedSize != 0, "Invalid encoded size.");
return Whiskers(R"(
function <functionName>(value, pos) -> updatedPos {
<encode>(value, pos)
function <functionName>(<values>, pos) -> updatedPos {
<encode>(<values>, pos)
updatedPos := add(pos, <encodedSize>)
}
)")
("functionName", functionName)
("encode", encoder)
("encodedSize", toCompactHexWithPrefix(encodedSize))
("values", values)
.render();
}
});
@ -1566,3 +1559,28 @@ size_t ABIFunctions::headSize(TypePointers const& _targetTypes)
return headSize;
}
string ABIFunctions::suffixedVariableNameList(string const& _baseName, size_t _startSuffix, size_t _endSuffix)
{
string result;
if (_startSuffix < _endSuffix)
{
result = _baseName + to_string(_startSuffix++);
while (_startSuffix < _endSuffix)
result += ", " + _baseName + to_string(_startSuffix++);
}
else if (_endSuffix < _startSuffix)
{
result = _baseName + to_string(_endSuffix++);
while (_endSuffix < _startSuffix)
result = _baseName + to_string(_endSuffix++) + ", " + result;
}
return result;
}
size_t ABIFunctions::numVariablesForType(Type const& _type, EncodingOptions const& _options)
{
if (_type.category() == Type::Category::Function && !_options.encodeFunctionFromStack)
return 1;
else
return _type.sizeOnStack();
}

View File

@ -253,6 +253,18 @@ private:
/// @returns the size of the static part of the encoding of the given types.
static size_t headSize(TypePointers const& _targetTypes);
/// @returns a string containing a comma-separated list of variable names consisting of @a _baseName suffixed
/// with increasing integers in the range [@a _startSuffix, @a _endSuffix), if @a _startSuffix < @a _endSuffix,
/// and with decreasing integers in the range [@a _endSuffix, @a _startSuffix), if @a _endSuffix < @a _startSuffix.
/// If @a _startSuffix == @a _endSuffix, the empty string is returned.
static std::string suffixedVariableNameList(std::string const& _baseName, size_t _startSuffix, size_t _endSuffix);
/// @returns the number of variables needed to store a type.
/// This is one for almost all types. The exception being dynamically sized calldata arrays or
/// external function types (if we are encoding from stack, i.e. _options.encodeFunctionFromStack
/// is true), for which it is two.
static size_t numVariablesForType(Type const& _type, EncodingOptions const& _options);
langutil::EVMVersion m_evmVersion;
std::shared_ptr<MultiUseYulFunctionCollector> m_functionCollector;
std::set<std::string> m_externallyUsedFunctions;