diff --git a/libsolidity/codegen/ir/IRGenerationContext.cpp b/libsolidity/codegen/ir/IRGenerationContext.cpp index 73fed46bf..54e997e4e 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.cpp +++ b/libsolidity/codegen/ir/IRGenerationContext.cpp @@ -65,6 +65,11 @@ string IRGenerationContext::functionName(FunctionDefinition const& _function) return "fun_" + _function.name() + "_" + to_string(_function.id()); } +string IRGenerationContext::functionName(VariableDeclaration const& _varDecl) +{ + return "getter_fun_" + _varDecl.name() + "_" + to_string(_varDecl.id()); +} + FunctionDefinition const& IRGenerationContext::virtualFunction(FunctionDefinition const& _function) { // @TODO previously, we had to distinguish creation context and runtime context, diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index 7152975df..ed9fc5bc5 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -76,6 +76,7 @@ public: } std::string functionName(FunctionDefinition const& _function); + std::string functionName(VariableDeclaration const& _varDecl); FunctionDefinition const& virtualFunction(FunctionDefinition const& _functionDeclaration); std::string virtualFunctionName(FunctionDefinition const& _functionDeclaration); diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index f27130296..e3b4d5401 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -149,6 +149,32 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function) }); } +string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) +{ + string functionName = m_context.functionName(_varDecl); + + Type const* type = _varDecl.annotation().type; + + solAssert(!_varDecl.isConstant(), ""); + solAssert(_varDecl.isStateVariable(), ""); + + solUnimplementedAssert(type->isValueType(), ""); + + return m_context.functionCollector()->createFunction(functionName, [&]() { + pair slot_offset = m_context.storageLocationOfVariable(_varDecl); + + return Whiskers(R"( + function () -> rval { + rval := () + } + )") + ("functionName", functionName) + ("readStorage", m_utils.readFromStorage(*type, slot_offset.second, false)) + ("slot", slot_offset.first.str()) + .render(); + }); +} + string IRGenerator::constructorCode(ContractDefinition const& _contract) { // TODO initialize state variables in base to derived order. @@ -234,7 +260,14 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) templ["abiDecode"] = abiFunctions.tupleDecoder(type->parameterTypes()); templ["params"] = suffixedVariableNameList("param_", 0, paramVars); templ["retParams"] = suffixedVariableNameList("ret_", retVars, 0); - templ["function"] = generateFunction(dynamic_cast(type->declaration())); + + if (FunctionDefinition const* funDef = dynamic_cast(&type->declaration())) + templ["function"] = generateFunction(*funDef); + else if (VariableDeclaration const* varDecl = dynamic_cast(&type->declaration())) + templ["function"] = generateGetter(*varDecl); + else + solAssert(false, "Unexpected declaration for function!"); + templ["allocate"] = m_utils.allocationFunction(); templ["abiEncode"] = abiFunctions.tupleEncoder(type->returnParameterTypes(), type->returnParameterTypes(), false); templ["comma"] = retVars == 0 ? "" : ", "; diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index 2b2d6e68e..0da85018c 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -56,6 +56,8 @@ private: /// Generates code for and returns the name of the function. std::string generateFunction(FunctionDefinition const& _function); + /// Generates a getter for the given declaration and returns its name + std::string generateGetter(VariableDeclaration const& _varDecl); std::string constructorCode(ContractDefinition const& _contract); std::string deployCode(ContractDefinition const& _contract); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 81a8048e4..094ac8ddd 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -607,6 +607,26 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) break; } + case FunctionType::Kind::KECCAK256: + { + solAssert(arguments.size() == 1, ""); + + ArrayType const* arrayType = TypeProvider::bytesMemory(); + string const& array = m_context.newYulVariable(); + m_code << "let " << array << " := " << expressionAsType(*arguments[0], *arrayType) << "\n"; + + defineExpression(_functionCall) << + "keccak256(" << + m_utils.arrayDataAreaFunction(*arrayType) << "(" << + array << + "), " << + m_utils.arrayLengthFunction(*arrayType) << + "(" << + array << + "))\n"; + + break; + } default: solUnimplemented("FunctionKind " + toString(static_cast(functionType->kind())) + " not yet implemented"); } diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 4e36eec4b..f669c7f71 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1095,12 +1095,14 @@ BOOST_AUTO_TEST_CASE(multiple_elementary_accessors) uint256 super_secret_data; } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("data()"), encodeArgs(8)); - ABI_CHECK(callContractFunction("name()"), encodeArgs("Celina")); - ABI_CHECK(callContractFunction("a_hash()"), encodeArgs(dev::keccak256(bytes(1, 0x7b)))); - ABI_CHECK(callContractFunction("an_address()"), encodeArgs(toBigEndian(u160(0x1337)))); - ABI_CHECK(callContractFunction("super_secret_data()"), bytes()); + ALSO_VIA_YUL( + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("data()"), encodeArgs(8)); + ABI_CHECK(callContractFunction("name()"), encodeArgs("Celina")); + ABI_CHECK(callContractFunction("a_hash()"), encodeArgs(dev::keccak256(bytes(1, 0x7b)))); + ABI_CHECK(callContractFunction("an_address()"), encodeArgs(toBigEndian(u160(0x1337)))); + ABI_CHECK(callContractFunction("super_secret_data()"), bytes()); + ); } BOOST_AUTO_TEST_CASE(balance) @@ -3470,8 +3472,10 @@ BOOST_AUTO_TEST_CASE(keccak256_empty) } } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), fromHex("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")); + ALSO_VIA_YUL( + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("f()"), fromHex("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")); + ) } BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments) diff --git a/test/libsolidity/semanticTests/viaYul/keccak.sol b/test/libsolidity/semanticTests/viaYul/keccak.sol new file mode 100644 index 000000000..887faf9e4 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/keccak.sol @@ -0,0 +1,14 @@ +contract C { + function keccak1() public pure returns (bytes32) { + return keccak256("123"); + } + function keccak2() public pure returns (bytes32) { + bytes memory a = "123"; + return keccak256(a); + } +} +// ==== +// compileViaYul: only +// ---- +// keccak1() -> 0x64e604787cbf194841e7b68d7cd28786f6c9a0a3ab9f8b0a0e87cb4387ab0107 +// keccak2() -> 0x64e604787cbf194841e7b68d7cd28786f6c9a0a3ab9f8b0a0e87cb4387ab0107