From 42d627200a08053381df035c8b816c6d0586d91c Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 25 Nov 2020 13:45:14 +0100 Subject: [PATCH] Add managed memory access functions. --- libsolidity/CMakeLists.txt | 2 + libsolidity/codegen/YulUtilFunctions.cpp | 19 +- .../codegen/ir/IRGenerationContext.cpp | 13 + libsolidity/codegen/ir/IRGenerationContext.h | 6 +- libsolidity/codegen/ir/IRGenerator.cpp | 8 +- .../codegen/ir/WellKnownUtilFunctions.cpp | 260 ++++++++++++++++++ .../codegen/ir/WellKnownUtilFunctions.h | 44 +++ 7 files changed, 334 insertions(+), 18 deletions(-) create mode 100644 libsolidity/codegen/ir/WellKnownUtilFunctions.cpp create mode 100644 libsolidity/codegen/ir/WellKnownUtilFunctions.h diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index 298b11074..f8890a0a6 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -92,6 +92,8 @@ set(sources codegen/ir/IRLValue.h codegen/ir/IRVariable.cpp codegen/ir/IRVariable.h + codegen/ir/WellKnownUtilFunctions.cpp + codegen/ir/WellKnownUtilFunctions.h formal/ArraySlicePredicate.cpp formal/ArraySlicePredicate.h formal/BMC.cpp diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 2407fa548..fe51f8d98 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -77,9 +77,9 @@ string YulUtilFunctions::copyToMemoryFunction(bool _fromCalldata) { return Whiskers(R"( function (src, dst, length) { - calldatacopy(dst, src, length) + m_calldatacopy(dst, src, length) // clear end - mstore(add(dst, length), 0) + m_mstore(dst, length, 0) } )") ("functionName", functionName) @@ -92,12 +92,12 @@ string YulUtilFunctions::copyToMemoryFunction(bool _fromCalldata) let i := 0 for { } lt(i, length) { i := add(i, 32) } { - mstore(add(dst, i), mload(add(src, i))) + m_mstore(dst, i, m_mload(src, i)) } if gt(i, length) { // clear end - mstore(add(dst, length), 0) + m_mstore(dst, length, 0) } } )") @@ -138,15 +138,14 @@ string YulUtilFunctions::requireOrAssertFunction(bool _assert, Type const* _mess return Whiskers(R"( function (condition ) { if iszero(condition) { - let fmp := mload() - mstore(fmp, ) - let end := (add(fmp, ) ) - revert(fmp, sub(end, fmp)) + let obj := m_allocateUnbounded() + m_mstore(obj, ) + let end := (m_slice(obj, ) ) + m_revert(obj, sub(end, fmp)) } } )") ("functionName", functionName) - ("freeMemPointer", to_string(CompilerUtils::freeMemoryPointer)) ("errorHash", formatNumber(errorHash)) ("abiEncodeFunc", encodeFunc) ("hashHeaderSize", to_string(hashHeaderSize)) @@ -958,6 +957,8 @@ string YulUtilFunctions::extractByteArrayLengthFunction() }); } +// TODO continue here + string YulUtilFunctions::arrayLengthFunction(ArrayType const& _type) { string functionName = "array_length_" + _type.identifier(); diff --git a/libsolidity/codegen/ir/IRGenerationContext.cpp b/libsolidity/codegen/ir/IRGenerationContext.cpp index 99e5fb887..2b621515e 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.cpp +++ b/libsolidity/codegen/ir/IRGenerationContext.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -37,6 +38,18 @@ using namespace solidity; using namespace solidity::util; using namespace solidity::frontend; +IRGenerationContext::IRGenerationContext( + langutil::EVMVersion _evmVersion, + RevertStrings _revertStrings, + OptimiserSettings _optimiserSettings +): + m_evmVersion(_evmVersion), + m_revertStrings(_revertStrings), + m_optimiserSettings(std::move(_optimiserSettings)) +{ + WellKnownUtilFunctions(m_evmVersion, m_revertStrings, m_functions); +} + string IRGenerationContext::enqueueFunctionForCodeGeneration(FunctionDefinition const& _function) { string name = IRNames::function(_function); diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index 78c7c8be7..4bb6e3244 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -69,11 +69,7 @@ public: langutil::EVMVersion _evmVersion, RevertStrings _revertStrings, OptimiserSettings _optimiserSettings - ): - m_evmVersion(_evmVersion), - m_revertStrings(_revertStrings), - m_optimiserSettings(std::move(_optimiserSettings)) - {} + ); MultiUseYulFunctionCollector& functionCollector() { return m_functions; } diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 2592be57c..5af2fd07e 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -725,10 +725,10 @@ void IRGenerator::resetContext(ContractDefinition const& _contract) m_context.functionGenerationQueueEmpty(), "Reset function generation queue while it still had functions." ); - solAssert( - m_context.functionCollector().requestedFunctions().empty(), - "Reset context while it still had functions." - ); +// solAssert( +// m_context.functionCollector().requestedFunctions().empty(), +// "Reset context while it still had functions." +// ); solAssert( m_context.internalDispatchClean(), "Reset internal dispatch map without consuming it." diff --git a/libsolidity/codegen/ir/WellKnownUtilFunctions.cpp b/libsolidity/codegen/ir/WellKnownUtilFunctions.cpp new file mode 100644 index 000000000..ab89c7b7b --- /dev/null +++ b/libsolidity/codegen/ir/WellKnownUtilFunctions.cpp @@ -0,0 +1,260 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** +* Yul util functions that are known by name and always included. + */ + +#include + +#include +#include + +#include +#include + +#include + +using namespace std; +using namespace solidity; +using namespace solidity::util; +using namespace solidity::frontend; + +WellKnownUtilFunctions::WellKnownUtilFunctions( + langutil::EVMVersion _evmVersion, + RevertStrings _revertStrings, + MultiUseYulFunctionCollector& _functionCollector +) +{ + YulUtilFunctions utils(_evmVersion, _revertStrings, _functionCollector); + + // Turn a memory object plus offset into an absolute memory address. + // Not to be used outside the memory helpers. + _functionCollector.createFunction("m_absolute", [&]() { + return R"( + function m_absolute(mobj, offset) -> mptr { + mptr := add(mobj, offset) + } + )"; + }); + + _functionCollector.createFunction("m_allocate", [&]() { + return Whiskers(R"( + function m_allocate(size) -> mobj { + mobj := m_allocateUnbounded() + m_finalize(mobj, size) + } + )") + ("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer)) + ("panic", utils.panicFunction()) + .render(); + }); + + _functionCollector.createFunction("m_allocateUnbounded", [&]() { + return Whiskers(R"( + function m_allocateUnbounded() -> mobj { + mobj := mload() + } + )") + ("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer)) + .render(); + }); + + _functionCollector.createFunction("m_finalize", [&]() { + return Whiskers(R"( + function m_finalize(mobj, size) { + size := (size) + let newFreePtr := add(mobj, size) + // protect against overflow + if or(gt(size, 0xffffffffffffffff), lt(newFreePtr, mobj)) { () } + mstore(, newFreePtr) + } + )") + ("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer)) + ("panic", utils.panicFunction()) + ("roundUp", utils.roundUpFunction()) + .render(); + }); + + _functionCollector.createFunction("m_discard", [&]() { + return "\nfunction m_discard(mobj) { }\n"; + }); + + _functionCollector.createFunction("m_load", [&]() { + return R"( + function m_load(mobj, offset) -> value { + value := mload(m_absolute(mobj, offset)) + } + )"; + }); + + _functionCollector.createFunction("m_store", [&]() { + return R"( + function m_store(mobj, offset, value) { + mstore(m_absolute(mobj, offset), value) + } + )"; + }); + + _functionCollector.createFunction("m_store8", [&]() { + return R"( + function m_store8(mobj, offset, value) { + mstore8(m_absolute(mobj, offset), value) + } + )"; + }); + + _functionCollector.createFunction("m_slice", [&]() { + return R"( + function m_slice(mobj, offset) -> ret { + ret := add(mobj, offset) + } + )"; + }); + + _functionCollector.createFunction("m_calldatacopy", [&]() { + return R"( + function m_calldatacopy(mobj, from_offset, size) { + calldatacopy(m_absolute(mobj, 0), from_offset, size) + } + )"; + }); + + _functionCollector.createFunction("m_codecopy", [&]() { + return R"( + function m_codecopy(mobj, from_offset, size) { + codecopy(m_absolute(mobj, 0), from_offset, size) + } + )"; + }); + + _functionCollector.createFunction("m_extcodecopy", [&]() { + return R"( + function m_extcodecopy(addr, mobj, from_offset, size) { + extcodecopy(addr, m_absolute(mobj, 0), from_offset, size) + } + )"; + }); + + _functionCollector.createFunction("m_returndatacopy", [&]() { + return R"( + function m_returndatacopy(mobj, from_offset, size) { + returndatacopy(m_absolute(mobj, 0), from_offset, size) + } + )"; + }); + + _functionCollector.createFunction("m_create", [&]() { + return R"( + function m_create(value, mobj, size) { + create(value, m_absolute(mobj, 0), size) + } + )"; + }); + + _functionCollector.createFunction("m_create2", [&]() { + return R"( + function m_create2(value, mobj, size, salt) { + create2(value, m_absolute(mobj, 0), size, salt) + } + )"; + }); + _functionCollector.createFunction("m_call", [&]() { + return R"( + function m_call(gasAllowance, addr, value, mobjInput, inputSize, mobjOutput, outputSize) -> success { + success := call(gasAllowance, addr, value, m_absolute(mobjInput, 0), inputSize, m_absolute(mobjOutput, 0), outputSize) + } + )"; + }); + _functionCollector.createFunction("m_callcode", [&]() { + return R"( + function m_callcode(gasAllowance, addr, value, mobjInput, inputSize, mobjOutput, outputSize) -> success { + success := callcode(gasAllowance, addr, value, m_absolute(mobjInput, 0), inputSize, m_absolute(mobjOutput, 0), outputSize) + } + )"; + }); + _functionCollector.createFunction("m_delegatecall", [&]() { + return R"( + function m_delegatecall(gasAllowance, addr, mobjInput, inputSize, mobjOutput, outputSize) -> success { + success := delegatecall(gasAllowance, addr, m_absolute(mobjInput, 0), inputSize, m_absolute(mobjOutput, 0), outputSize) + } + )"; + }); + _functionCollector.createFunction("m_staticcall", [&]() { + return R"( + function m_staticcall(gasAllowance, addr, mobjInput, inputSize, mobjOutput, outputSize) -> success { + success := staticcall(gasAllowance, addr, m_absolute(mobjInput, 0), inputSize, m_absolute(mobjOutput, 0), outputSize) + } + )"; + }); + _functionCollector.createFunction("m_return", [&]() { + return R"( + function m_return(mobj, size) { + return(m_absolute(mobj, 0), size) + } + )"; + }); + _functionCollector.createFunction("m_revert", [&]() { + return R"( + function m_revert(mobj, size) { + revert(m_absolute(mobj, 0), size) + } + )"; + }); + _functionCollector.createFunction("m_log0", [&]() { + return R"( + function m_log0(mobj, size) { + m_log0(m_absolute(mobj, 0), size) + } + )"; + }); + _functionCollector.createFunction("m_log0", [&]() { + return R"( + function m_log0(mobj, size) { + m_log0(m_absolute(mobj, 0), size) + } + )"; + }); + _functionCollector.createFunction("m_log1", [&]() { + return R"( + function m_log1(mobj, size, topic1) { + m_log1(m_absolute(mobj, 0), size, topic1) + } + )"; + }); + _functionCollector.createFunction("m_log2", [&]() { + return R"( + function m_log2(mobj, size, topic1, topic2) { + m_log2(m_absolute(mobj, 0), size, topic1, topic2) + } + )"; + }); + _functionCollector.createFunction("m_log3", [&]() { + return R"( + function m_log3(mobj, size, topic1, topic2, topic3) { + m_log3(m_absolute(mobj, 0), size, topic1, topic2, topic3) + } + )"; + }); + _functionCollector.createFunction("m_log4", [&]() { + return R"( + function m_log4(mobj, size, topic1, topic2, topic3, topic4) { + m_log4(m_absolute(mobj, 0), size, topic1, topic2, topic3, topic4) + } + )"; + }); +} diff --git a/libsolidity/codegen/ir/WellKnownUtilFunctions.h b/libsolidity/codegen/ir/WellKnownUtilFunctions.h new file mode 100644 index 000000000..eb3ba9482 --- /dev/null +++ b/libsolidity/codegen/ir/WellKnownUtilFunctions.h @@ -0,0 +1,44 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * Yul util functions that are known by name and always included. + */ + +#pragma once + +#include +#include +#include + +namespace solidity::frontend +{ + +/** + * Yul util functions that are known by name and always included. + */ +class WellKnownUtilFunctions +{ +public: + explicit WellKnownUtilFunctions( + langutil::EVMVersion _evmVersion, + RevertStrings _revertStrings, + MultiUseYulFunctionCollector& _functionCollector + ); +}; + +}