From af9fc8b63488d55ebdb3dffe853e12e85e542c5e Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 4 Feb 2020 14:59:33 +0100 Subject: [PATCH] Mapping getters for Yul IR. --- libsolidity/codegen/ir/IRGenerator.cpp | 77 +++++++++++++++---- .../viaYul/mapping_enum_key_getter.sol | 26 +++++++ .../semanticTests/viaYul/mapping_getters.sol | 40 ++++++++++ 3 files changed, 129 insertions(+), 14 deletions(-) create mode 100644 test/libsolidity/semanticTests/viaYul/mapping_enum_key_getter.sol create mode 100644 test/libsolidity/semanticTests/viaYul/mapping_getters.sol diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index bd2099c4a..0798ebc37 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -159,21 +159,70 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) 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 := () + if (auto const* mappingType = dynamic_cast(type)) + return m_context.functionCollector()->createFunction(functionName, [&]() { + pair slot_offset = m_context.storageLocationOfVariable(_varDecl); + solAssert(slot_offset.second == 0, ""); + FunctionType funType(_varDecl); + solUnimplementedAssert(funType.returnParameterTypes().size() == 1, ""); + TypePointer returnType = funType.returnParameterTypes().front(); + unsigned num_keys = 0; + stringstream indexAccesses; + string slot = m_context.newYulVariable(); + do + { + solUnimplementedAssert( + mappingType->keyType()->sizeOnStack() == 1, + "Multi-slot mapping key unimplemented - might not be a problem" + ); + indexAccesses << + slot << + " := " << + m_utils.mappingIndexAccessFunction(*mappingType, *mappingType->keyType()) << + "(" << + slot; + if (mappingType->keyType()->sizeOnStack() > 0) + indexAccesses << + ", " << + suffixedVariableNameList("key", num_keys, num_keys + mappingType->keyType()->sizeOnStack()); + indexAccesses << ")\n"; + num_keys += mappingType->keyType()->sizeOnStack(); } - )") - ("functionName", functionName) - ("readStorage", m_utils.readFromStorage(*type, slot_offset.second, false)) - ("slot", slot_offset.first.str()) - .render(); - }); + while ((mappingType = dynamic_cast(mappingType->valueType()))); + + return Whiskers(R"( + function () -> rval { + let := + + rval := () + } + )") + ("functionName", functionName) + ("keys", suffixedVariableNameList("key", 0, num_keys)) + ("readStorage", m_utils.readFromStorage(*returnType, 0, false)) + ("indexAccesses", indexAccesses.str()) + ("slot", slot) + ("base", slot_offset.first.str()) + .render(); + }); + else + { + 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) diff --git a/test/libsolidity/semanticTests/viaYul/mapping_enum_key_getter.sol b/test/libsolidity/semanticTests/viaYul/mapping_enum_key_getter.sol new file mode 100644 index 000000000..78d9a39b9 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/mapping_enum_key_getter.sol @@ -0,0 +1,26 @@ +pragma experimental ABIEncoderV2; +contract test { + enum E { A, B, C } + mapping(E => uint8) public table; + function set(E k, uint8 v) public { + table[k] = v; + } +} +// ==== +// compileViaYul: also +// ---- +// table(uint8): 0 -> 0 +// table(uint8): 0x01 -> 0 +// table(uint8): 0xa7 -> FAILURE +// set(uint8,uint8): 0x01, 0xa1 -> +// table(uint8): 0 -> 0 +// table(uint8): 0x01 -> 0xa1 +// table(uint8): 0xa7 -> FAILURE +// set(uint8,uint8): 0x00, 0xef -> +// table(uint8): 0 -> 0xef +// table(uint8): 0x01 -> 0xa1 +// table(uint8): 0xa7 -> FAILURE +// set(uint8,uint8): 0x01, 0x05 -> +// table(uint8): 0 -> 0xef +// table(uint8): 0x01 -> 0x05 +// table(uint8): 0xa7 -> FAILURE diff --git a/test/libsolidity/semanticTests/viaYul/mapping_getters.sol b/test/libsolidity/semanticTests/viaYul/mapping_getters.sol new file mode 100644 index 000000000..1db4eb8c5 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/mapping_getters.sol @@ -0,0 +1,40 @@ +contract test { + mapping(uint256 => uint256) public m1; + mapping(uint256 => mapping(uint256 => uint256)) public m2; + function set(uint256 k, uint256 v) public { + m1[k] = v; + } + function set(uint256 k1, uint256 k2, uint256 v) public { + m2[k1][k2] = v; + } +} +// ==== +// compileViaYul: also +// ---- +// m1(uint256): 0 -> 0 +// m1(uint256): 0x01 -> 0 +// m1(uint256): 0xa7 -> 0 +// set(uint256,uint256): 0x01, 0xa1 -> +// m1(uint256): 0 -> 0 +// m1(uint256): 0x01 -> 0xa1 +// m1(uint256): 0xa7 -> 0 +// set(uint256,uint256): 0x00, 0xef -> +// m1(uint256): 0 -> 0xef +// m1(uint256): 0x01 -> 0xa1 +// m1(uint256): 0xa7 -> 0 +// set(uint256,uint256): 0x01, 0x05 -> +// m1(uint256): 0 -> 0xef +// m1(uint256): 0x01 -> 0x05 +// m1(uint256): 0xa7 -> 0 +// m2(uint256,uint256): 0, 0 -> 0 +// m2(uint256,uint256): 0, 0x01 -> 0 +// m2(uint256,uint256): 0xa7, 0 -> 0 +// m2(uint256,uint256): 0xa7, 0x01 -> 0 +// set(uint256,uint256,uint256): 0xa7, 0x01, 0x23 +// m2(uint256,uint256): 0, 0x01 -> 0 +// m2(uint256,uint256): 0xa7, 0 -> 0 +// m2(uint256,uint256): 0xa7, 0x01 -> 0x23 +// set(uint256,uint256,uint256): 0, 0x01, 0xef +// m2(uint256,uint256): 0, 0x01 -> 0xef +// m2(uint256,uint256): 0xa7, 0 -> 0 +// m2(uint256,uint256): 0xa7, 0x01 -> 0x23