mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8462 from ethereum/allocate_memory_zero_function
[Yul codegen] Zero initialize memory arrays
This commit is contained in:
commit
ed1000dde7
@ -2338,7 +2338,7 @@ TypePointers StructType::memoryMemberTypes() const
|
||||
TypePointers types;
|
||||
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
|
||||
if (variable->annotation().type->canLiveOutsideStorage())
|
||||
types.push_back(variable->annotation().type);
|
||||
types.push_back(TypeProvider::withLocationIfReference(DataLocation::Memory, variable->annotation().type));
|
||||
return types;
|
||||
}
|
||||
|
||||
|
@ -658,6 +658,8 @@ string YulUtilFunctions::storageArrayPushZeroFunction(ArrayType const& _type)
|
||||
solUnimplementedAssert(!_type.isByteArray(), "Byte Arrays not yet implemented!");
|
||||
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, "Base type is not yet implemented.");
|
||||
|
||||
solAssert(_type.baseType()->isValueType(), "");
|
||||
|
||||
string functionName = "array_push_zero_" + _type.identifier();
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
return Whiskers(R"(
|
||||
@ -794,6 +796,7 @@ string YulUtilFunctions::arrayConvertLengthToSize(ArrayType const& _type)
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::arrayAllocationSizeFunction(ArrayType const& _type)
|
||||
{
|
||||
solAssert(_type.dataStoredIn(DataLocation::Memory), "");
|
||||
@ -1178,7 +1181,7 @@ string YulUtilFunctions::writeToMemoryFunction(Type const& _type)
|
||||
return Whiskers(R"(
|
||||
function <functionName>(memPtr, value) {
|
||||
mstore(memPtr, value)
|
||||
}
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
.render();
|
||||
@ -1202,7 +1205,7 @@ string YulUtilFunctions::writeToMemoryFunction(Type const& _type)
|
||||
return Whiskers(R"(
|
||||
function <functionName>(memPtr, value) {
|
||||
mstore(memPtr, <cleanup>(value))
|
||||
}
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("cleanup", cleanupFunction(_type))
|
||||
@ -1334,28 +1337,112 @@ string YulUtilFunctions::allocationFunction()
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::allocateMemoryArrayFunction(ArrayType const& _type)
|
||||
string YulUtilFunctions::zeroMemoryArrayFunction(ArrayType const& _type)
|
||||
{
|
||||
solUnimplementedAssert(!_type.isByteArray(), "");
|
||||
if (_type.baseType()->hasSimpleZeroValueInMemory())
|
||||
return zeroMemoryFunction(*_type.baseType());
|
||||
return zeroComplexMemoryArrayFunction(_type);
|
||||
}
|
||||
|
||||
string functionName = "allocate_memory_array_" + _type.identifier();
|
||||
string YulUtilFunctions::zeroMemoryFunction(Type const& _type)
|
||||
{
|
||||
solAssert(_type.hasSimpleZeroValueInMemory(), "");
|
||||
|
||||
string functionName = "zero_memory_chunk_" + _type.identifier();
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
return Whiskers(R"(
|
||||
function <functionName>(length) -> memPtr {
|
||||
memPtr := <alloc>(<allocSize>(length))
|
||||
<?dynamic>
|
||||
mstore(memPtr, length)
|
||||
</dynamic>
|
||||
function <functionName>(dataStart, dataSizeInBytes) {
|
||||
calldatacopy(dataStart, calldatasize(), dataSizeInBytes)
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("alloc", allocationFunction())
|
||||
("allocSize", arrayAllocationSizeFunction(_type))
|
||||
("dynamic", _type.isDynamicallySized())
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::zeroComplexMemoryArrayFunction(ArrayType const& _type)
|
||||
{
|
||||
solAssert(!_type.baseType()->hasSimpleZeroValueInMemory(), "");
|
||||
|
||||
string functionName = "zero_complex_memory_array_" + _type.identifier();
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
solAssert(_type.memoryStride() == 32, "");
|
||||
return Whiskers(R"(
|
||||
function <functionName>(dataStart, dataSizeInBytes) {
|
||||
for {let i := 0} lt(i, dataSizeInBytes) { i := add(i, <stride>) } {
|
||||
mstore(add(dataStart, i), <zeroValue>())
|
||||
}
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("stride", to_string(_type.memoryStride()))
|
||||
("zeroValue", zeroValueFunction(*_type.baseType(), false))
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::allocateAndInitializeMemoryArrayFunction(ArrayType const& _type)
|
||||
{
|
||||
solUnimplementedAssert(!_type.isByteArray(), "");
|
||||
|
||||
string functionName = "allocate_and_zero_memory_array_" + _type.identifier();
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
return Whiskers(R"(
|
||||
function <functionName>(length) -> memPtr {
|
||||
let allocSize := <allocSize>(length)
|
||||
memPtr := <alloc>(allocSize)
|
||||
let dataStart := memPtr
|
||||
let dataSize := allocSize
|
||||
<?dynamic>
|
||||
dataStart := add(dataStart, 32)
|
||||
dataSize := sub(dataSize, 32)
|
||||
mstore(memPtr, length)
|
||||
</dynamic>
|
||||
<zeroArrayFunction>(dataStart, dataSize)
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("alloc", allocationFunction())
|
||||
("allocSize", arrayAllocationSizeFunction(_type))
|
||||
("zeroArrayFunction", zeroMemoryArrayFunction(_type))
|
||||
("dynamic", _type.isDynamicallySized())
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::allocateAndInitializeMemoryStructFunction(StructType const& _type)
|
||||
{
|
||||
string functionName = "allocate_and_initialize_memory_struct_" + _type.identifier();
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
Whiskers templ(R"(
|
||||
function <functionName>() -> memPtr {
|
||||
let allocSize := <allocSize>()
|
||||
memPtr := <alloc>(allocSize)
|
||||
let offset := memPtr
|
||||
<#member>
|
||||
mstore(offset, <zeroValue>())
|
||||
offset := add(offset, 32)
|
||||
</member>
|
||||
}
|
||||
)");
|
||||
templ("functionName", functionName);
|
||||
templ("alloc", allocationFunction());
|
||||
|
||||
TypePointers const& members = _type.memoryMemberTypes();
|
||||
templ("allocSize", _type.memoryDataSize().str());
|
||||
|
||||
vector<map<string, string>> memberParams(members.size());
|
||||
for (size_t i = 0; i < members.size(); ++i)
|
||||
{
|
||||
solAssert(members[i]->memoryHeadSize() == 32, "");
|
||||
solAssert(members[i]->dataStoredIn(DataLocation::Memory), "");
|
||||
memberParams[i]["zeroValue"] = zeroValueFunction(*members[i], false);
|
||||
}
|
||||
templ("member", memberParams);
|
||||
return templ.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
||||
{
|
||||
if (_from.category() == Type::Category::Function)
|
||||
@ -1884,23 +1971,58 @@ string YulUtilFunctions::negateNumberCheckedFunction(Type const& _type)
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::zeroValueFunction(Type const& _type)
|
||||
string YulUtilFunctions::zeroValueFunction(Type const& _type, bool _splitFunctionTypes)
|
||||
{
|
||||
solUnimplementedAssert(_type.sizeOnStack() == 1, "Stacksize not yet implemented!");
|
||||
solUnimplementedAssert(_type.isValueType(), "Zero value for non-value types not yet implemented");
|
||||
solAssert(_type.category() != Type::Category::Mapping, "");
|
||||
|
||||
string const functionName = "zero_value_for_" + _type.identifier();
|
||||
string const functionName = "zero_value_for_" + string(_splitFunctionTypes ? "split_" : "") + _type.identifier();
|
||||
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
return Whiskers(R"(
|
||||
function <functionName>() -> ret {
|
||||
<body>
|
||||
}
|
||||
)")
|
||||
FunctionType const* fType = dynamic_cast<FunctionType const*>(&_type);
|
||||
if (fType && fType->kind() == FunctionType::Kind::External && _splitFunctionTypes)
|
||||
return Whiskers(R"(
|
||||
function <functionName>() -> retAddress, retFunction {
|
||||
retAddress := 0
|
||||
retFunction := 0
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("body", "ret := 0x0")
|
||||
.render();
|
||||
});
|
||||
|
||||
Whiskers templ(R"(
|
||||
function <functionName>() -> ret {
|
||||
ret := <zeroValue>
|
||||
}
|
||||
)");
|
||||
templ("functionName", functionName);
|
||||
|
||||
if (_type.isValueType())
|
||||
{
|
||||
solAssert((
|
||||
_type.hasSimpleZeroValueInMemory() ||
|
||||
(fType && (fType->kind() == FunctionType::Kind::Internal || fType->kind() == FunctionType::Kind::External))
|
||||
), "");
|
||||
templ("zeroValue", "0");
|
||||
}
|
||||
else
|
||||
{
|
||||
solAssert(_type.dataStoredIn(DataLocation::Memory), "");
|
||||
if (auto const* arrayType = dynamic_cast<ArrayType const*>(&_type))
|
||||
{
|
||||
if (_type.isDynamicallySized())
|
||||
templ("zeroValue", to_string(CompilerUtils::zeroPointer));
|
||||
else
|
||||
templ("zeroValue", allocateAndInitializeMemoryArrayFunction(*arrayType) + "(" + to_string(unsigned(arrayType->length())) + ")");
|
||||
|
||||
}
|
||||
else if (auto const* structType = dynamic_cast<StructType const*>(&_type))
|
||||
templ("zeroValue", allocateAndInitializeMemoryStructFunction(*structType) + "()");
|
||||
else
|
||||
solUnimplementedAssert(false, "");
|
||||
}
|
||||
|
||||
return templ.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::storageSetToZeroFunction(Type const& _type)
|
||||
|
@ -37,6 +37,7 @@ class Type;
|
||||
class ArrayType;
|
||||
class MappingType;
|
||||
class IntegerType;
|
||||
class StructType;
|
||||
|
||||
/**
|
||||
* Component that can generate various useful Yul functions.
|
||||
@ -154,6 +155,7 @@ public:
|
||||
/// to store an array in memory given its length (internally encoded, not ABI encoded).
|
||||
/// The function reverts for too large lengths.
|
||||
std::string arrayAllocationSizeFunction(ArrayType const& _type);
|
||||
|
||||
/// @returns the name of a function that converts a storage slot number
|
||||
/// a memory pointer or a calldata pointer to the slot number / memory pointer / calldata pointer
|
||||
/// for the data position of an array which is stored in that slot / memory area / calldata area.
|
||||
@ -250,10 +252,27 @@ public:
|
||||
/// Return value: pointer
|
||||
std::string allocationFunction();
|
||||
|
||||
/// @returns the name of a function that allocates a memory array.
|
||||
/// @returns the name of a function that zeroes an array.
|
||||
/// signature: (dataStart, dataSizeInBytes) ->
|
||||
std::string zeroMemoryArrayFunction(ArrayType const& _type);
|
||||
|
||||
/// @returns the name of a function that zeroes a chunk of memory.
|
||||
/// signature: (dataStart, dataSizeInBytes) ->
|
||||
std::string zeroMemoryFunction(Type const& _type);
|
||||
|
||||
/// @returns the name of a function that zeroes an array
|
||||
/// where the base does not have simple zero value in memory.
|
||||
/// signature: (dataStart, dataSizeInBytes) ->
|
||||
std::string zeroComplexMemoryArrayFunction(ArrayType const& _type);
|
||||
|
||||
/// @returns the name of a function that allocates and zeroes a memory array.
|
||||
/// For dynamic arrays it adds space for length and stores it.
|
||||
/// signature: (length) -> memPtr
|
||||
std::string allocateMemoryArrayFunction(ArrayType const& _type);
|
||||
std::string allocateAndInitializeMemoryArrayFunction(ArrayType const& _type);
|
||||
|
||||
/// @returns the name of a function that allocates and zeroes a memory struct.
|
||||
/// signature: (members) -> memPtr
|
||||
std::string allocateAndInitializeMemoryStructFunction(StructType const& _type);
|
||||
|
||||
/// @returns the name of the function that converts a value of type @a _from
|
||||
/// to a value of type @a _to. The resulting vale is guaranteed to be in range
|
||||
@ -288,8 +307,9 @@ public:
|
||||
std::string negateNumberCheckedFunction(Type const& _type);
|
||||
|
||||
/// @returns the name of a function that returns the zero value for the
|
||||
/// provided type
|
||||
std::string zeroValueFunction(Type const& _type);
|
||||
/// provided type.
|
||||
/// @param _splitFunctionTypes if false, returns two zeroes
|
||||
std::string zeroValueFunction(Type const& _type, bool _splitFunctionTypes = true);
|
||||
|
||||
/// @returns the name of a function that will set the given storage item to
|
||||
/// zero
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <libsolidity/codegen/YulUtilFunctions.h>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
|
||||
#include <libsolutil/Whiskers.h>
|
||||
#include <libsolutil/StringUtils.h>
|
||||
@ -112,9 +113,10 @@ string IRGenerationContext::internalDispatch(size_t _in, size_t _out)
|
||||
for (auto const& contract: mostDerivedContract().annotation().linearizedBaseContracts)
|
||||
for (FunctionDefinition const* function: contract->definedFunctions())
|
||||
if (
|
||||
FunctionType const* functionType = TypeProvider::function(*function)->asCallableFunction(false);
|
||||
!function->isConstructor() &&
|
||||
function->parameters().size() == _in &&
|
||||
function->returnParameters().size() == _out
|
||||
TupleType(functionType->parameterTypes()).sizeOnStack() == _in &&
|
||||
TupleType(functionType->returnParameterTypes()).sizeOnStack() == _out
|
||||
)
|
||||
{
|
||||
// 0 is reserved for uninitialized function pointers
|
||||
|
@ -133,6 +133,7 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function)
|
||||
return m_context.functionCollector().createFunction(functionName, [&]() {
|
||||
Whiskers t(R"(
|
||||
function <functionName>(<params>) <returns> {
|
||||
<initReturnVariables>
|
||||
<body>
|
||||
}
|
||||
)");
|
||||
@ -142,9 +143,14 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function)
|
||||
params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList();
|
||||
t("params", params);
|
||||
string retParams;
|
||||
string retInit;
|
||||
for (auto const& varDecl: _function.returnParameters())
|
||||
{
|
||||
retParams += (retParams.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList();
|
||||
retInit += generateInitialAssignment(*varDecl);
|
||||
}
|
||||
t("returns", retParams.empty() ? "" : " -> " + retParams);
|
||||
t("initReturnVariables", retInit);
|
||||
t("body", generate(_function.body()));
|
||||
return t.render();
|
||||
});
|
||||
@ -226,6 +232,13 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
|
||||
}
|
||||
}
|
||||
|
||||
string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
IRGeneratorForStatements generator(m_context, m_utils);
|
||||
generator.initializeLocalVar(_varDecl);
|
||||
return generator.code();
|
||||
}
|
||||
|
||||
string IRGenerator::constructorCode(ContractDefinition const& _contract)
|
||||
{
|
||||
// Initialization of state variables in base-to-derived order.
|
||||
|
@ -61,6 +61,9 @@ private:
|
||||
/// Generates a getter for the given declaration and returns its name
|
||||
std::string generateGetter(VariableDeclaration const& _varDecl);
|
||||
|
||||
/// Generates code that assigns the initial value of the respective type.
|
||||
std::string generateInitialAssignment(VariableDeclaration const& _varDecl);
|
||||
|
||||
std::string constructorCode(ContractDefinition const& _contract);
|
||||
std::string deployCode(ContractDefinition const& _contract);
|
||||
std::string callValueCheck();
|
||||
|
@ -154,6 +154,19 @@ void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _va
|
||||
}
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::initializeLocalVar(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
solAssert(m_context.isLocalVariable(_varDecl), "Must be a local variable.");
|
||||
|
||||
auto const* type = _varDecl.type();
|
||||
if (auto const* refType = dynamic_cast<ReferenceType const*>(type))
|
||||
if (refType->dataStoredIn(DataLocation::Storage) && refType->isPointer())
|
||||
return;
|
||||
|
||||
IRVariable zero = zeroValue(*type);
|
||||
assign(m_context.localVariable(_varDecl), zero);
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _varDeclStatement)
|
||||
{
|
||||
if (Expression const* expression = _varDeclStatement.initialValue())
|
||||
@ -179,7 +192,10 @@ void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _var
|
||||
else
|
||||
for (auto const& decl: _varDeclStatement.declarations())
|
||||
if (decl)
|
||||
{
|
||||
declare(m_context.addLocalVariable(*decl));
|
||||
initializeLocalVar(*decl);
|
||||
}
|
||||
}
|
||||
|
||||
bool IRGeneratorForStatements::visit(Conditional const& _conditional)
|
||||
@ -670,7 +686,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
|
||||
IRVariable value = convert(*arguments[0], *TypeProvider::uint256());
|
||||
define(_functionCall) <<
|
||||
m_utils.allocateMemoryArrayFunction(arrayType) <<
|
||||
m_utils.allocateAndInitializeMemoryArrayFunction(arrayType) <<
|
||||
"(" <<
|
||||
value.commaSeparatedList() <<
|
||||
")\n";
|
||||
@ -1439,6 +1455,12 @@ std::ostream& IRGeneratorForStatements::define(IRVariable const& _var)
|
||||
return m_code;
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::declare(IRVariable const& _var)
|
||||
{
|
||||
if (_var.type().sizeOnStack() > 0)
|
||||
m_code << "let " << _var.commaSeparatedList() << "\n";
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::declareAssign(IRVariable const& _lhs, IRVariable const& _rhs, bool _declare)
|
||||
{
|
||||
string output;
|
||||
@ -1458,10 +1480,15 @@ void IRGeneratorForStatements::declareAssign(IRVariable const& _lhs, IRVariable
|
||||
_rhs.commaSeparatedList() <<
|
||||
")\n";
|
||||
}
|
||||
void IRGeneratorForStatements::declare(IRVariable const& _var)
|
||||
|
||||
IRVariable IRGeneratorForStatements::zeroValue(Type const& _type, bool _splitFunctionTypes)
|
||||
{
|
||||
if (_var.type().sizeOnStack() > 0)
|
||||
m_code << "let " << _var.commaSeparatedList() << "\n";
|
||||
IRVariable irVar{
|
||||
"zero_value_for_type_" + _type.identifier() + m_context.newYulVariable(),
|
||||
_type
|
||||
};
|
||||
define(irVar) << m_utils.zeroValueFunction(_type, _splitFunctionTypes) << "()\n";
|
||||
return irVar;
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr)
|
||||
|
@ -46,6 +46,8 @@ public:
|
||||
|
||||
/// Generates code to initialize the given state variable.
|
||||
void initializeStateVar(VariableDeclaration const& _varDecl);
|
||||
/// Generates code to initialize the given local variable.
|
||||
void initializeLocalVar(VariableDeclaration const& _varDecl);
|
||||
|
||||
void endVisit(VariableDeclarationStatement const& _variableDeclaration) override;
|
||||
bool visit(Conditional const& _conditional) override;
|
||||
@ -100,6 +102,11 @@ private:
|
||||
|
||||
void declareAssign(IRVariable const& _var, IRVariable const& _value, bool _define);
|
||||
|
||||
/// @returns an IRVariable with the zero
|
||||
/// value of @a _type.
|
||||
/// @param _splitFunctionTypes if false, returns two zeroes
|
||||
IRVariable zeroValue(Type const& _type, bool _splitFunctionTypes = true);
|
||||
|
||||
void appendAndOrOperatorCode(BinaryOperation const& _binOp);
|
||||
void appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr);
|
||||
|
||||
|
@ -20,6 +20,7 @@ object \"C_6\" {
|
||||
|
||||
function fun_f_5() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -69,6 +70,7 @@ object \"C_6\" {
|
||||
|
||||
function fun_f_5() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
function shift_right_224_unsigned(value) -> newValue {
|
||||
|
@ -35,11 +35,18 @@ object \"C_10\" {
|
||||
}
|
||||
|
||||
function fun_f_9() -> vloc__4_mpos {
|
||||
let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr()
|
||||
vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos
|
||||
|
||||
vloc__4_mpos := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_string_memory_ptr()
|
||||
leave
|
||||
|
||||
}
|
||||
|
||||
function zero_value_for_split_t_string_memory_ptr() -> ret {
|
||||
ret := 96
|
||||
}
|
||||
|
||||
}
|
||||
object \"C_10_deployed\" {
|
||||
code {
|
||||
@ -131,6 +138,9 @@ object \"C_10\" {
|
||||
}
|
||||
|
||||
function fun_f_9() -> vloc__4_mpos {
|
||||
let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr()
|
||||
vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos
|
||||
|
||||
vloc__4_mpos := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_string_memory_ptr()
|
||||
leave
|
||||
|
||||
@ -147,6 +157,10 @@ object \"C_10\" {
|
||||
|
||||
}
|
||||
|
||||
function zero_value_for_split_t_string_memory_ptr() -> ret {
|
||||
ret := 96
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,11 +23,18 @@ object \"C_10\" {
|
||||
}
|
||||
|
||||
function fun_f_9() -> vloc__4 {
|
||||
let zero_value_for_type_t_bytes32_1 := zero_value_for_split_t_bytes32()
|
||||
vloc__4 := zero_value_for_type_t_bytes32_1
|
||||
|
||||
vloc__4 := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_bytes32()
|
||||
leave
|
||||
|
||||
}
|
||||
|
||||
function zero_value_for_split_t_bytes32() -> ret {
|
||||
ret := 0
|
||||
}
|
||||
|
||||
}
|
||||
object \"C_10_deployed\" {
|
||||
code {
|
||||
@ -88,6 +95,9 @@ object \"C_10\" {
|
||||
}
|
||||
|
||||
function fun_f_9() -> vloc__4 {
|
||||
let zero_value_for_type_t_bytes32_1 := zero_value_for_split_t_bytes32()
|
||||
vloc__4 := zero_value_for_type_t_bytes32_1
|
||||
|
||||
vloc__4 := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_bytes32()
|
||||
leave
|
||||
|
||||
@ -100,6 +110,10 @@ object \"C_10\" {
|
||||
|
||||
}
|
||||
|
||||
function zero_value_for_split_t_bytes32() -> ret {
|
||||
ret := 0
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,9 @@ object \"C_10\" {
|
||||
}
|
||||
|
||||
function fun_f_9() -> vloc__4 {
|
||||
let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4()
|
||||
vloc__4 := zero_value_for_type_t_bytes4_1
|
||||
|
||||
let expr_6 := 0x61626364
|
||||
vloc__4 := convert_t_rational_1633837924_by_1_to_t_bytes4(expr_6)
|
||||
leave
|
||||
@ -40,6 +43,10 @@ object \"C_10\" {
|
||||
|
||||
}
|
||||
|
||||
function zero_value_for_split_t_bytes4() -> ret {
|
||||
ret := 0
|
||||
}
|
||||
|
||||
}
|
||||
object \"C_10_deployed\" {
|
||||
code {
|
||||
@ -104,6 +111,9 @@ object \"C_10\" {
|
||||
}
|
||||
|
||||
function fun_f_9() -> vloc__4 {
|
||||
let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4()
|
||||
vloc__4 := zero_value_for_type_t_bytes4_1
|
||||
|
||||
let expr_6 := 0x61626364
|
||||
vloc__4 := convert_t_rational_1633837924_by_1_to_t_bytes4(expr_6)
|
||||
leave
|
||||
@ -124,6 +134,10 @@ object \"C_10\" {
|
||||
|
||||
}
|
||||
|
||||
function zero_value_for_split_t_bytes4() -> ret {
|
||||
ret := 0
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,11 +39,18 @@ object \"C_10\" {
|
||||
}
|
||||
|
||||
function fun_f_9() -> vloc__4_mpos {
|
||||
let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr()
|
||||
vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos
|
||||
|
||||
vloc__4_mpos := convert_t_stringliteral_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571_to_t_string_memory_ptr()
|
||||
leave
|
||||
|
||||
}
|
||||
|
||||
function zero_value_for_split_t_string_memory_ptr() -> ret {
|
||||
ret := 96
|
||||
}
|
||||
|
||||
}
|
||||
object \"C_10_deployed\" {
|
||||
code {
|
||||
@ -139,6 +146,9 @@ object \"C_10\" {
|
||||
}
|
||||
|
||||
function fun_f_9() -> vloc__4_mpos {
|
||||
let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr()
|
||||
vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos
|
||||
|
||||
vloc__4_mpos := convert_t_stringliteral_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571_to_t_string_memory_ptr()
|
||||
leave
|
||||
|
||||
@ -155,6 +165,10 @@ object \"C_10\" {
|
||||
|
||||
}
|
||||
|
||||
function zero_value_for_split_t_string_memory_ptr() -> ret {
|
||||
ret := 96
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,9 @@ object \"C_10\" {
|
||||
}
|
||||
|
||||
function fun_f_9() -> vloc__4 {
|
||||
let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4()
|
||||
vloc__4 := zero_value_for_type_t_bytes4_1
|
||||
|
||||
let expr_6 := 0xaabbccdd
|
||||
vloc__4 := convert_t_rational_2864434397_by_1_to_t_bytes4(expr_6)
|
||||
leave
|
||||
@ -40,6 +43,10 @@ object \"C_10\" {
|
||||
|
||||
}
|
||||
|
||||
function zero_value_for_split_t_bytes4() -> ret {
|
||||
ret := 0
|
||||
}
|
||||
|
||||
}
|
||||
object \"C_10_deployed\" {
|
||||
code {
|
||||
@ -104,6 +111,9 @@ object \"C_10\" {
|
||||
}
|
||||
|
||||
function fun_f_9() -> vloc__4 {
|
||||
let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4()
|
||||
vloc__4 := zero_value_for_type_t_bytes4_1
|
||||
|
||||
let expr_6 := 0xaabbccdd
|
||||
vloc__4 := convert_t_rational_2864434397_by_1_to_t_bytes4(expr_6)
|
||||
leave
|
||||
@ -124,6 +134,10 @@ object \"C_10\" {
|
||||
|
||||
}
|
||||
|
||||
function zero_value_for_split_t_bytes4() -> ret {
|
||||
ret := 0
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
contract C {
|
||||
function f(uint n, uint m) public {
|
||||
function() internal returns (uint)[] memory arr = new function() internal returns (uint)[](n);
|
||||
arr[m]();
|
||||
}
|
||||
function f2(uint n, uint m, uint a, uint b) public {
|
||||
function() internal returns (uint)[][] memory arr = new function() internal returns (uint)[][](n);
|
||||
for (uint i = 0; i < n; ++i)
|
||||
arr[i] = new function() internal returns (uint)[](m);
|
||||
arr[a][b]();
|
||||
}
|
||||
function g(uint n, uint m) public {
|
||||
function() external returns (uint)[] memory arr = new function() external returns (uint)[](n);
|
||||
arr[m]();
|
||||
}
|
||||
function g2(uint n, uint m, uint a, uint b) public {
|
||||
function() external returns (uint)[][] memory arr = new function() external returns (uint)[][](n);
|
||||
for (uint i = 0; i < n; ++i)
|
||||
arr[i] = new function() external returns (uint)[](m);
|
||||
arr[a][b]();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(uint256,uint256): 1823621, 12323 -> FAILURE
|
||||
// f2(uint256,uint256,uint256,uint256): 18723921, 1823621, 123, 12323 -> FAILURE
|
||||
// g(uint256,uint256): 1823621, 12323 -> FAILURE
|
||||
// g2(uint256,uint256,uint256,uint256): 18723921, 1823621, 123, 12323 -> FAILURE
|
@ -0,0 +1,24 @@
|
||||
contract C {
|
||||
uint test1;
|
||||
uint test2;
|
||||
uint test3;
|
||||
uint test4;
|
||||
uint test5;
|
||||
uint test6;
|
||||
uint test7;
|
||||
mapping (string => uint) map;
|
||||
function set(string memory s, uint n, uint m, uint a, uint b) public returns (uint) {
|
||||
map[s] = 0;
|
||||
uint[][] memory x = new uint[][](n);
|
||||
for (uint i = 0; i < n; ++i)
|
||||
x[i] = new uint[](m);
|
||||
return x[a][b];
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 0, 0, 32, "01234567890123456789012345678901" -> 0
|
||||
// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 1, 3, 32, "01234567890123456789012345678901" -> 0
|
||||
// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 3, 3, 32, "01234567890123456789012345678901" -> FAILURE
|
||||
// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 1, 5, 32, "01234567890123456789012345678901" -> FAILURE
|
@ -0,0 +1,22 @@
|
||||
contract C {
|
||||
uint test1;
|
||||
uint test2;
|
||||
uint test3;
|
||||
uint test4;
|
||||
uint test5;
|
||||
uint test6;
|
||||
uint test7;
|
||||
mapping (string => uint) map;
|
||||
function set(string memory s, uint n, uint m) public returns (uint) {
|
||||
map[s] = 0;
|
||||
uint[4][] memory x = new uint[4][](n);
|
||||
return x[m][0];
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// set(string,uint256,uint256): 0x60, 2, 0, 32, "01234567890123456789012345678901" -> 0
|
||||
// set(string,uint256,uint256): 0x60, 2, 1, 32, "01234567890123456789012345678901" -> 0
|
||||
// set(string,uint256,uint256): 0x60, 2, 2, 32, "01234567890123456789012345678901" -> FAILURE
|
||||
// set(string,uint256,uint256): 0x60, 200, 199, 32, "01234567890123456789012345678901" -> 0
|
@ -0,0 +1,17 @@
|
||||
contract C {
|
||||
uint test1;
|
||||
uint test2;
|
||||
uint test3;
|
||||
uint test4;
|
||||
uint test5;
|
||||
uint test6;
|
||||
uint test7;
|
||||
mapping (string => uint) map;
|
||||
function set(string memory s) public returns (uint[3] memory x, uint[2] memory y, uint[] memory z, uint t) {
|
||||
map[s] = 0;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// set(string): 0x20, 32, "01234567890123456789012345678901" -> 0, 0, 0, 0, 0, 0xe0, 0, 0
|
@ -0,0 +1,19 @@
|
||||
contract C {
|
||||
uint test1;
|
||||
uint test2;
|
||||
uint test3;
|
||||
uint test4;
|
||||
uint test5;
|
||||
uint test6;
|
||||
uint test7;
|
||||
mapping (string => uint) map;
|
||||
function set(string memory s) public returns (uint) {
|
||||
map[s] = 0;
|
||||
uint[3] memory x;
|
||||
return x[2];
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// set(string): 0x20, 32, "01234567890123456789012345678901" -> 0
|
@ -0,0 +1,22 @@
|
||||
contract C {
|
||||
uint test1;
|
||||
uint test2;
|
||||
uint test3;
|
||||
uint test4;
|
||||
uint test5;
|
||||
uint test6;
|
||||
uint test7;
|
||||
mapping (string => uint) map;
|
||||
function set(string memory s, uint n, uint a) public returns (uint) {
|
||||
map[s] = 0;
|
||||
uint[] memory x = new uint[](n);
|
||||
return x[a];
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// set(string,uint256,uint256): 0x60, 5, 0, 32, "01234567890123456789012345678901" -> 0
|
||||
// set(string,uint256,uint256): 0x60, 5, 1, 32, "01234567890123456789012345678901" -> 0
|
||||
// set(string,uint256,uint256): 0x60, 5, 4, 32, "01234567890123456789012345678901" -> 0
|
||||
// set(string,uint256,uint256): 0x60, 5, 5, 32, "01234567890123456789012345678901" -> FAILURE
|
25
test/libsolidity/semanticTests/viaYul/function_pointers.sol
Normal file
25
test/libsolidity/semanticTests/viaYul/function_pointers.sol
Normal file
@ -0,0 +1,25 @@
|
||||
contract C {
|
||||
function f() public {
|
||||
function() internal returns (uint) _f;
|
||||
_f();
|
||||
}
|
||||
function g() public {
|
||||
function() external returns (uint) _g;
|
||||
_g();
|
||||
}
|
||||
function h1() internal returns (function() internal returns (uint) _h) {}
|
||||
function h2() public {
|
||||
h1()();
|
||||
}
|
||||
function k1() internal returns (function() external returns (uint) _k) {}
|
||||
function k2() public {
|
||||
k1()();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> FAILURE
|
||||
// g() -> FAILURE
|
||||
// h2() -> FAILURE
|
||||
// k2() -> FAILURE
|
@ -0,0 +1,16 @@
|
||||
contract C {
|
||||
uint[] arr1;
|
||||
uint[][] arr2;
|
||||
function f() internal returns (uint[] storage ptr1, uint[][] storage ptr2) {
|
||||
ptr1 = arr1;
|
||||
ptr2 = arr2;
|
||||
}
|
||||
function g() public returns (uint, uint) {
|
||||
return (arr1.length, arr2.length);
|
||||
}
|
||||
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 0, 0
|
Loading…
Reference in New Issue
Block a user