diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index d78c6e7fb..eb73fcb9e 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -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( ( add(headStart, )) )") ); - 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, ) )") ); - 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 (value, pos) -> updatedPos { - updatedPos := (value, pos) + function (, pos) -> updatedPos { + updatedPos := (, 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 (value, pos) -> updatedPos { - (value, pos) + function (, pos) -> updatedPos { + (, pos) updatedPos := add(pos, ) } )") ("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(); +} diff --git a/libsolidity/codegen/ABIFunctions.h b/libsolidity/codegen/ABIFunctions.h index c1d88d68d..c9c19f80f 100644 --- a/libsolidity/codegen/ABIFunctions.h +++ b/libsolidity/codegen/ABIFunctions.h @@ -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 m_functionCollector; std::set m_externallyUsedFunctions;