Add managed memory access functions.

This commit is contained in:
chriseth 2020-11-25 13:45:14 +01:00
parent 319b29bb4a
commit 42d627200a
7 changed files with 334 additions and 18 deletions

View File

@ -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

View File

@ -77,9 +77,9 @@ string YulUtilFunctions::copyToMemoryFunction(bool _fromCalldata)
{
return Whiskers(R"(
function <functionName>(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 <functionName>(condition <messageVars>) {
if iszero(condition) {
let fmp := mload(<freeMemPointer>)
mstore(fmp, <errorHash>)
let end := <abiEncodeFunc>(add(fmp, <hashHeaderSize>) <messageVars>)
revert(fmp, sub(end, fmp))
let obj := m_allocateUnbounded()
m_mstore(obj, <errorHash>)
let end := <abiEncodeFunc>(m_slice(obj, <hashHeaderSize>) <messageVars>)
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();

View File

@ -24,6 +24,7 @@
#include <libsolidity/codegen/YulUtilFunctions.h>
#include <libsolidity/codegen/ABIFunctions.h>
#include <libsolidity/codegen/CompilerUtils.h>
#include <libsolidity/codegen/ir/WellKnownUtilFunctions.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/TypeProvider.h>
@ -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);

View File

@ -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; }

View File

@ -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."

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
/**
* Yul util functions that are known by name and always included.
*/
#include <libsolidity/codegen/ir/WellKnownUtilFunctions.h>
#include <libsolidity/codegen/YulUtilFunctions.h>
#include <libsolidity/codegen/CompilerUtils.h>
#include <liblangutil/Exceptions.h>
#include <libsolutil/Whiskers.h>
#include <boost/algorithm/string/split.hpp>
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>)
}
)")
("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer))
.render();
});
_functionCollector.createFunction("m_finalize", [&]() {
return Whiskers(R"(
function m_finalize(mobj, size) {
size := <roundUp>(size)
let newFreePtr := add(mobj, size)
// protect against overflow
if or(gt(size, 0xffffffffffffffff), lt(newFreePtr, mobj)) { <panic>() }
mstore(<freeMemoryPointer>, 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)
}
)";
});
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
/**
* Yul util functions that are known by name and always included.
*/
#pragma once
#include <liblangutil/EVMVersion.h>
#include <libsolidity/codegen/MultiUseYulFunctionCollector.h>
#include <libsolidity/interface/DebugSettings.h>
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
);
};
}