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/IRVariable.cpp
|
||||
codegen/ir/IRVariable.h
|
||||
codegen/ir/WellKnownUtilFunctions.cpp
|
||||
codegen/ir/WellKnownUtilFunctions.h
|
||||
formal/ArraySlicePredicate.cpp
|
||||
formal/ArraySlicePredicate.h
|
||||
formal/BMC.cpp
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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."
|
||||
|
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