mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add managed memory access functions.
This commit is contained in:
parent
319b29bb4a
commit
42d627200a
@ -92,6 +92,8 @@ set(sources
|
|||||||
codegen/ir/IRLValue.h
|
codegen/ir/IRLValue.h
|
||||||
codegen/ir/IRVariable.cpp
|
codegen/ir/IRVariable.cpp
|
||||||
codegen/ir/IRVariable.h
|
codegen/ir/IRVariable.h
|
||||||
|
codegen/ir/WellKnownUtilFunctions.cpp
|
||||||
|
codegen/ir/WellKnownUtilFunctions.h
|
||||||
formal/ArraySlicePredicate.cpp
|
formal/ArraySlicePredicate.cpp
|
||||||
formal/ArraySlicePredicate.h
|
formal/ArraySlicePredicate.h
|
||||||
formal/BMC.cpp
|
formal/BMC.cpp
|
||||||
|
@ -77,9 +77,9 @@ string YulUtilFunctions::copyToMemoryFunction(bool _fromCalldata)
|
|||||||
{
|
{
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
function <functionName>(src, dst, length) {
|
function <functionName>(src, dst, length) {
|
||||||
calldatacopy(dst, src, length)
|
m_calldatacopy(dst, src, length)
|
||||||
// clear end
|
// clear end
|
||||||
mstore(add(dst, length), 0)
|
m_mstore(dst, length, 0)
|
||||||
}
|
}
|
||||||
)")
|
)")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
@ -92,12 +92,12 @@ string YulUtilFunctions::copyToMemoryFunction(bool _fromCalldata)
|
|||||||
let i := 0
|
let i := 0
|
||||||
for { } lt(i, length) { i := add(i, 32) }
|
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)
|
if gt(i, length)
|
||||||
{
|
{
|
||||||
// clear end
|
// 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"(
|
return Whiskers(R"(
|
||||||
function <functionName>(condition <messageVars>) {
|
function <functionName>(condition <messageVars>) {
|
||||||
if iszero(condition) {
|
if iszero(condition) {
|
||||||
let fmp := mload(<freeMemPointer>)
|
let obj := m_allocateUnbounded()
|
||||||
mstore(fmp, <errorHash>)
|
m_mstore(obj, <errorHash>)
|
||||||
let end := <abiEncodeFunc>(add(fmp, <hashHeaderSize>) <messageVars>)
|
let end := <abiEncodeFunc>(m_slice(obj, <hashHeaderSize>) <messageVars>)
|
||||||
revert(fmp, sub(end, fmp))
|
m_revert(obj, sub(end, fmp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)")
|
)")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
("freeMemPointer", to_string(CompilerUtils::freeMemoryPointer))
|
|
||||||
("errorHash", formatNumber(errorHash))
|
("errorHash", formatNumber(errorHash))
|
||||||
("abiEncodeFunc", encodeFunc)
|
("abiEncodeFunc", encodeFunc)
|
||||||
("hashHeaderSize", to_string(hashHeaderSize))
|
("hashHeaderSize", to_string(hashHeaderSize))
|
||||||
@ -958,6 +957,8 @@ string YulUtilFunctions::extractByteArrayLengthFunction()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO continue here
|
||||||
|
|
||||||
string YulUtilFunctions::arrayLengthFunction(ArrayType const& _type)
|
string YulUtilFunctions::arrayLengthFunction(ArrayType const& _type)
|
||||||
{
|
{
|
||||||
string functionName = "array_length_" + _type.identifier();
|
string functionName = "array_length_" + _type.identifier();
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <libsolidity/codegen/YulUtilFunctions.h>
|
#include <libsolidity/codegen/YulUtilFunctions.h>
|
||||||
#include <libsolidity/codegen/ABIFunctions.h>
|
#include <libsolidity/codegen/ABIFunctions.h>
|
||||||
#include <libsolidity/codegen/CompilerUtils.h>
|
#include <libsolidity/codegen/CompilerUtils.h>
|
||||||
|
#include <libsolidity/codegen/ir/WellKnownUtilFunctions.h>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
#include <libsolidity/ast/TypeProvider.h>
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
|
|
||||||
@ -37,6 +38,18 @@ using namespace solidity;
|
|||||||
using namespace solidity::util;
|
using namespace solidity::util;
|
||||||
using namespace solidity::frontend;
|
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 IRGenerationContext::enqueueFunctionForCodeGeneration(FunctionDefinition const& _function)
|
||||||
{
|
{
|
||||||
string name = IRNames::function(_function);
|
string name = IRNames::function(_function);
|
||||||
|
@ -69,11 +69,7 @@ public:
|
|||||||
langutil::EVMVersion _evmVersion,
|
langutil::EVMVersion _evmVersion,
|
||||||
RevertStrings _revertStrings,
|
RevertStrings _revertStrings,
|
||||||
OptimiserSettings _optimiserSettings
|
OptimiserSettings _optimiserSettings
|
||||||
):
|
);
|
||||||
m_evmVersion(_evmVersion),
|
|
||||||
m_revertStrings(_revertStrings),
|
|
||||||
m_optimiserSettings(std::move(_optimiserSettings))
|
|
||||||
{}
|
|
||||||
|
|
||||||
MultiUseYulFunctionCollector& functionCollector() { return m_functions; }
|
MultiUseYulFunctionCollector& functionCollector() { return m_functions; }
|
||||||
|
|
||||||
|
@ -725,10 +725,10 @@ void IRGenerator::resetContext(ContractDefinition const& _contract)
|
|||||||
m_context.functionGenerationQueueEmpty(),
|
m_context.functionGenerationQueueEmpty(),
|
||||||
"Reset function generation queue while it still had functions."
|
"Reset function generation queue while it still had functions."
|
||||||
);
|
);
|
||||||
solAssert(
|
// solAssert(
|
||||||
m_context.functionCollector().requestedFunctions().empty(),
|
// m_context.functionCollector().requestedFunctions().empty(),
|
||||||
"Reset context while it still had functions."
|
// "Reset context while it still had functions."
|
||||||
);
|
// );
|
||||||
solAssert(
|
solAssert(
|
||||||
m_context.internalDispatchClean(),
|
m_context.internalDispatchClean(),
|
||||||
"Reset internal dispatch map without consuming it."
|
"Reset internal dispatch map without consuming it."
|
||||||
|
260
libsolidity/codegen/ir/WellKnownUtilFunctions.cpp
Normal file
260
libsolidity/codegen/ir/WellKnownUtilFunctions.cpp
Normal 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)
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
});
|
||||||
|
}
|
44
libsolidity/codegen/ir/WellKnownUtilFunctions.h
Normal file
44
libsolidity/codegen/ir/WellKnownUtilFunctions.h
Normal 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
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user