mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Initial IR generator.
This commit is contained in:
parent
3795569da6
commit
420a7dc3d6
@ -67,6 +67,10 @@ set(sources
|
||||
codegen/MultiUseYulFunctionCollector.cpp
|
||||
codegen/YulUtilFunctions.h
|
||||
codegen/YulUtilFunctions.cpp
|
||||
codegen/ir/IRGenerator.cpp
|
||||
codegen/ir/IRGenerator.h
|
||||
codegen/ir/IRGenerationContext.cpp
|
||||
codegen/ir/IRGenerationContext.h
|
||||
formal/SMTChecker.cpp
|
||||
formal/SMTChecker.h
|
||||
formal/SMTLib2Interface.cpp
|
||||
|
37
libsolidity/codegen/ir/IRGenerationContext.cpp
Normal file
37
libsolidity/codegen/ir/IRGenerationContext.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* Class that contains contextual information during IR generation.
|
||||
*/
|
||||
|
||||
#include <libsolidity/codegen/ir/IRGenerationContext.h>
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
|
||||
using namespace dev;
|
||||
using namespace dev::solidity;
|
||||
using namespace std;
|
||||
|
||||
string IRGenerationContext::addLocalVariable(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
solUnimplementedAssert(
|
||||
_varDecl.annotation().type->sizeOnStack() == 1,
|
||||
"Multi-slot types not yet implemented."
|
||||
);
|
||||
|
||||
return m_localVariables[&_varDecl] = "vloc_" + _varDecl.name() + "_" + to_string(_varDecl.id());
|
||||
}
|
63
libsolidity/codegen/ir/IRGenerationContext.h
Normal file
63
libsolidity/codegen/ir/IRGenerationContext.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* Class that contains contextual information during IR generation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/interface/OptimiserSettings.h>
|
||||
|
||||
#include <libsolidity/codegen/MultiUseYulFunctionCollector.h>
|
||||
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace solidity
|
||||
{
|
||||
|
||||
class VariableDeclaration;
|
||||
|
||||
/**
|
||||
* Class that contains contextual information during IR generation.
|
||||
*/
|
||||
class IRGenerationContext
|
||||
{
|
||||
public:
|
||||
IRGenerationContext(langutil::EVMVersion _evmVersion, OptimiserSettings _optimiserSettings):
|
||||
m_evmVersion(_evmVersion),
|
||||
m_optimiserSettings(std::move(_optimiserSettings)),
|
||||
m_functions(std::make_shared<MultiUseYulFunctionCollector>())
|
||||
{}
|
||||
|
||||
std::shared_ptr<MultiUseYulFunctionCollector> functionCollector() const { return m_functions; }
|
||||
|
||||
std::string addLocalVariable(VariableDeclaration const& _varDecl);
|
||||
|
||||
private:
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
OptimiserSettings m_optimiserSettings;
|
||||
std::map<VariableDeclaration const*, std::string> m_localVariables;
|
||||
std::shared_ptr<MultiUseYulFunctionCollector> m_functions;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
243
libsolidity/codegen/ir/IRGenerator.cpp
Normal file
243
libsolidity/codegen/ir/IRGenerator.cpp
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* @author Alex Beregszaszi
|
||||
* @date 2017
|
||||
* Component that translates Solidity code into Yul.
|
||||
*/
|
||||
|
||||
#include <libsolidity/codegen/ir/IRGenerator.h>
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/codegen/ABIFunctions.h>
|
||||
#include <libsolidity/codegen/CompilerUtils.h>
|
||||
|
||||
#include <libyul/AssemblyStack.h>
|
||||
|
||||
#include <libdevcore/CommonData.h>
|
||||
#include <libdevcore/Whiskers.h>
|
||||
#include <libdevcore/StringUtils.h>
|
||||
|
||||
#include <liblangutil/SourceReferenceFormatter.h>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace dev::solidity;
|
||||
|
||||
pair<string, string> IRGenerator::run(ContractDefinition const& _contract)
|
||||
{
|
||||
// TODO Would be nice to pretty-print this while retaining comments.
|
||||
string ir = generateIR(_contract);
|
||||
|
||||
yul::AssemblyStack asmStack(m_evmVersion, yul::AssemblyStack::Language::StrictAssembly, m_optimiserSettings);
|
||||
if (!asmStack.parseAndAnalyze("", ir))
|
||||
{
|
||||
string errorMessage;
|
||||
for (auto const& error: asmStack.errors())
|
||||
errorMessage += langutil::SourceReferenceFormatter::formatExceptionInformation(
|
||||
*error,
|
||||
(error->type() == langutil::Error::Type::Warning) ? "Warning" : "Error"
|
||||
);
|
||||
solAssert(false, "Invalid IR generated:\n" + errorMessage + "\n" + ir);
|
||||
}
|
||||
asmStack.optimize();
|
||||
|
||||
string warning =
|
||||
"/*******************************************************\n"
|
||||
" * WARNING *\n"
|
||||
" * Solidity to Yul compilation is still EXPERIMENTAL *\n"
|
||||
" * It can result in LOSS OF FUNDS or worse *\n"
|
||||
" * !USE AT YOUR OWN RISK! *\n"
|
||||
" *******************************************************/\n\n";
|
||||
|
||||
return {warning + ir, warning + asmStack.print()};
|
||||
}
|
||||
|
||||
string IRGenerator::generateIR(ContractDefinition const& _contract)
|
||||
{
|
||||
Whiskers t(R"(
|
||||
object "<CreationObject>" {
|
||||
code {
|
||||
<memoryInit>
|
||||
<constructor>
|
||||
<deploy>
|
||||
<functions>
|
||||
}
|
||||
object "<RuntimeObject>" {
|
||||
code {
|
||||
<memoryInit>
|
||||
<dispatch>
|
||||
<runtimeFunctions>
|
||||
}
|
||||
}
|
||||
}
|
||||
)");
|
||||
|
||||
resetContext();
|
||||
t("CreationObject", creationObjectName(_contract));
|
||||
t("memoryInit", memoryInit());
|
||||
t("constructor", _contract.constructor() ? constructorCode(*_contract.constructor()) : "");
|
||||
t("deploy", deployCode(_contract));
|
||||
t("functions", m_context.functionCollector()->requestedFunctions());
|
||||
|
||||
resetContext();
|
||||
t("RuntimeObject", runtimeObjectName(_contract));
|
||||
t("dispatch", dispatchRoutine(_contract));
|
||||
t("runtimeFunctions", m_context.functionCollector()->requestedFunctions());
|
||||
return t.render();
|
||||
}
|
||||
|
||||
string IRGenerator::generateIRFunction(FunctionDefinition const& _function)
|
||||
{
|
||||
string functionName = "fun_" + to_string(_function.id()) + "_" + _function.name();
|
||||
return m_context.functionCollector()->createFunction(functionName, [&]() {
|
||||
Whiskers t("function <functionName>(<params>) <returns> {}");
|
||||
t("functionName", functionName);
|
||||
string params;
|
||||
for (auto const& varDecl: _function.parameters())
|
||||
params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl);
|
||||
t("params", params);
|
||||
string retParams;
|
||||
for (auto const& varDecl: _function.returnParameters())
|
||||
retParams += (retParams.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl);
|
||||
t("returns", retParams.empty() ? "" : " -> " + retParams);
|
||||
return t.render();
|
||||
});
|
||||
}
|
||||
|
||||
string IRGenerator::constructorCode(FunctionDefinition const& _constructor)
|
||||
{
|
||||
string out;
|
||||
if (!_constructor.isPayable())
|
||||
out = callValueCheck();
|
||||
|
||||
solUnimplemented("Constructors are not yet implemented.");
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
string IRGenerator::deployCode(ContractDefinition const& _contract)
|
||||
{
|
||||
Whiskers t(R"X(
|
||||
codecopy(0, dataoffset("<object>"), datasize("<object>"))
|
||||
return(0, datasize("<object>"))
|
||||
)X");
|
||||
t("object", runtimeObjectName(_contract));
|
||||
return t.render();
|
||||
}
|
||||
|
||||
string IRGenerator::callValueCheck()
|
||||
{
|
||||
return "if callvalue() { revert(0, 0) }";
|
||||
}
|
||||
|
||||
string IRGenerator::creationObjectName(ContractDefinition const& _contract)
|
||||
{
|
||||
return _contract.name() + "_" + to_string(_contract.id());
|
||||
}
|
||||
|
||||
string IRGenerator::runtimeObjectName(ContractDefinition const& _contract)
|
||||
{
|
||||
return _contract.name() + "_" + to_string(_contract.id()) + "_deployed";
|
||||
}
|
||||
|
||||
string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
||||
{
|
||||
Whiskers t(R"X(
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
let selector := <shr224>(calldataload(0))
|
||||
switch selector
|
||||
<#cases>
|
||||
case <functionSelector>
|
||||
{
|
||||
// <functionName>
|
||||
<callValueCheck>
|
||||
<assignToParams> <abiDecode>(4, calldatasize())
|
||||
<assignToRetParams> <function>(<params>)
|
||||
let memPos := <allocate>(0)
|
||||
let memEnd := <abiEncode>(memPos <comma> <retParams>)
|
||||
return(memPos, sub(memEnd, memPos))
|
||||
}
|
||||
</cases>
|
||||
default {}
|
||||
}
|
||||
<fallback>
|
||||
)X");
|
||||
t("shr224", m_utils.shiftRightFunction(224));
|
||||
vector<map<string, string>> functions;
|
||||
for (auto const& function: _contract.interfaceFunctions())
|
||||
{
|
||||
functions.push_back({});
|
||||
map<string, string>& templ = functions.back();
|
||||
templ["functionSelector"] = "0x" + function.first.hex();
|
||||
FunctionTypePointer const& type = function.second;
|
||||
templ["functionName"] = type->externalSignature();
|
||||
templ["callValueCheck"] = type->isPayable() ? "" : callValueCheck();
|
||||
|
||||
unsigned paramVars = make_shared<TupleType>(type->parameterTypes())->sizeOnStack();
|
||||
unsigned retVars = make_shared<TupleType>(type->returnParameterTypes())->sizeOnStack();
|
||||
templ["assignToParams"] = paramVars == 0 ? "" : "let " + m_utils.suffixedVariableNameList("param_", 0, paramVars) + " := ";
|
||||
templ["assignToRetParams"] = retVars == 0 ? "" : "let " + m_utils.suffixedVariableNameList("ret_", 0, retVars) + " := ";
|
||||
|
||||
ABIFunctions abiFunctions(m_evmVersion, m_context.functionCollector());
|
||||
templ["abiDecode"] = abiFunctions.tupleDecoder(type->parameterTypes());
|
||||
templ["params"] = m_utils.suffixedVariableNameList("param_", 0, paramVars);
|
||||
templ["retParams"] = m_utils.suffixedVariableNameList("ret_", retVars, 0);
|
||||
templ["function"] = generateIRFunction(dynamic_cast<FunctionDefinition const&>(type->declaration()));
|
||||
templ["allocate"] = m_utils.allocationFunction();
|
||||
templ["abiEncode"] = abiFunctions.tupleEncoder(type->returnParameterTypes(), type->returnParameterTypes(), false);
|
||||
templ["comma"] = retVars == 0 ? "" : ", ";
|
||||
}
|
||||
t("cases", functions);
|
||||
if (FunctionDefinition const* fallback = _contract.fallbackFunction())
|
||||
{
|
||||
string fallbackCode;
|
||||
if (!fallback->isPayable())
|
||||
fallbackCode += callValueCheck();
|
||||
fallbackCode += generateIRFunction(*fallback) + "() stop()";
|
||||
|
||||
t("fallback", fallbackCode);
|
||||
}
|
||||
else
|
||||
t("fallback", "revert(0, 0)");
|
||||
return t.render();
|
||||
}
|
||||
|
||||
string IRGenerator::memoryInit()
|
||||
{
|
||||
// This function should be called at the beginning of the EVM call frame
|
||||
// and thus can assume all memory to be zero, including the contents of
|
||||
// the "zero memory area" (the position CompilerUtils::zeroPointer points to).
|
||||
return
|
||||
Whiskers{"mstore(<memPtr>, <generalPurposeStart>)"}
|
||||
("memPtr", to_string(CompilerUtils::freeMemoryPointer))
|
||||
("generalPurposeStart", to_string(CompilerUtils::generalPurposeMemoryStart))
|
||||
.render();
|
||||
}
|
||||
|
||||
void IRGenerator::resetContext()
|
||||
{
|
||||
solAssert(
|
||||
m_context.functionCollector()->requestedFunctions().empty(),
|
||||
"Reset context while it still had functions."
|
||||
);
|
||||
m_context = IRGenerationContext(m_evmVersion, m_optimiserSettings);
|
||||
m_utils = YulUtilFunctions(m_evmVersion, m_context.functionCollector());
|
||||
}
|
78
libsolidity/codegen/ir/IRGenerator.h
Normal file
78
libsolidity/codegen/ir/IRGenerator.h
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* @author Alex Beregszaszi
|
||||
* @date 2017
|
||||
* Component that translates Solidity code into Yul.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/interface/OptimiserSettings.h>
|
||||
#include <libsolidity/ast/ASTForward.h>
|
||||
#include <libsolidity/codegen/ir/IRGenerationContext.h>
|
||||
#include <libsolidity/codegen/YulUtilFunctions.h>
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
#include <string>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace solidity
|
||||
{
|
||||
|
||||
class SourceUnit;
|
||||
|
||||
class IRGenerator
|
||||
{
|
||||
public:
|
||||
IRGenerator(langutil::EVMVersion _evmVersion, OptimiserSettings _optimiserSettings):
|
||||
m_evmVersion(_evmVersion),
|
||||
m_optimiserSettings(_optimiserSettings),
|
||||
m_context(_evmVersion, std::move(_optimiserSettings)),
|
||||
m_utils(_evmVersion, m_context.functionCollector())
|
||||
{}
|
||||
|
||||
/// Generates and returns the IR code, in unoptimized and optimized form
|
||||
/// (or just pretty-printed, depending on the optimizer settings).
|
||||
std::pair<std::string, std::string> run(ContractDefinition const& _contract);
|
||||
|
||||
private:
|
||||
std::string generateIR(ContractDefinition const& _contract);
|
||||
std::string generateIRFunction(FunctionDefinition const& _function);
|
||||
|
||||
std::string constructorCode(FunctionDefinition const& _constructor);
|
||||
std::string deployCode(ContractDefinition const& _contract);
|
||||
std::string callValueCheck();
|
||||
|
||||
std::string creationObjectName(ContractDefinition const& _contract);
|
||||
std::string runtimeObjectName(ContractDefinition const& _contract);
|
||||
|
||||
std::string dispatchRoutine(ContractDefinition const& _contract);
|
||||
|
||||
std::string memoryInit();
|
||||
|
||||
void resetContext();
|
||||
|
||||
langutil::EVMVersion const m_evmVersion;
|
||||
OptimiserSettings const m_optimiserSettings;
|
||||
|
||||
IRGenerationContext m_context;
|
||||
YulUtilFunctions m_utils;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
@ -46,6 +46,8 @@
|
||||
#include <libsolidity/interface/Version.h>
|
||||
#include <libsolidity/parsing/Parser.h>
|
||||
|
||||
#include <libsolidity/codegen/ir/IRGenerator.h>
|
||||
|
||||
#include <libyul/YulString.h>
|
||||
|
||||
#include <liblangutil/Scanner.h>
|
||||
@ -146,6 +148,7 @@ void CompilerStack::reset(bool _keepSettings)
|
||||
m_remappings.clear();
|
||||
m_libraries.clear();
|
||||
m_evmVersion = langutil::EVMVersion();
|
||||
m_generateIR = false;
|
||||
m_optimiserSettings = OptimiserSettings::minimal();
|
||||
m_metadataLiteralSources = false;
|
||||
}
|
||||
@ -387,7 +390,11 @@ bool CompilerStack::compile()
|
||||
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
|
||||
if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
|
||||
if (isRequestedContract(*contract))
|
||||
{
|
||||
compileContract(*contract, otherCompilers);
|
||||
if (m_generateIR)
|
||||
generateIR(*contract);
|
||||
}
|
||||
m_stackState = CompilationSuccessful;
|
||||
this->link();
|
||||
return true;
|
||||
@ -496,6 +503,22 @@ std::string const CompilerStack::filesystemFriendlyName(string const& _contractN
|
||||
return matchContract.contract->name();
|
||||
}
|
||||
|
||||
string const& CompilerStack::yulIR(string const& _contractName) const
|
||||
{
|
||||
if (m_stackState != CompilationSuccessful)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
|
||||
|
||||
return contract(_contractName).yulIR;
|
||||
}
|
||||
|
||||
string const& CompilerStack::yulIROptimized(string const& _contractName) const
|
||||
{
|
||||
if (m_stackState != CompilationSuccessful)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
|
||||
|
||||
return contract(_contractName).yulIROptimized;
|
||||
}
|
||||
|
||||
eth::LinkerObject const& CompilerStack::object(string const& _contractName) const
|
||||
{
|
||||
if (m_stackState != CompilationSuccessful)
|
||||
@ -902,6 +925,24 @@ void CompilerStack::compileContract(
|
||||
_otherCompilers[compiledContract.contract] = compiler;
|
||||
}
|
||||
|
||||
void CompilerStack::generateIR(ContractDefinition const& _contract)
|
||||
{
|
||||
solAssert(m_stackState >= AnalysisSuccessful, "");
|
||||
|
||||
if (!_contract.canBeDeployed())
|
||||
return;
|
||||
|
||||
Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
|
||||
if (!compiledContract.yulIR.empty())
|
||||
return;
|
||||
|
||||
for (auto const* dependency: _contract.annotation().contractDependencies)
|
||||
generateIR(*dependency);
|
||||
|
||||
IRGenerator generator(m_evmVersion, m_optimiserSettings);
|
||||
tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run(_contract);
|
||||
}
|
||||
|
||||
CompilerStack::Contract const& CompilerStack::contract(string const& _contractName) const
|
||||
{
|
||||
solAssert(m_stackState >= AnalysisSuccessful, "");
|
||||
|
@ -100,6 +100,7 @@ public:
|
||||
/// and must not emit exceptions.
|
||||
explicit CompilerStack(ReadCallback::Callback const& _readFile = ReadCallback::Callback()):
|
||||
m_readFile(_readFile),
|
||||
m_generateIR(false),
|
||||
m_errorList(),
|
||||
m_errorReporter(m_errorList) {}
|
||||
|
||||
@ -143,6 +144,9 @@ public:
|
||||
m_requestedContractNames = _contractNames;
|
||||
}
|
||||
|
||||
/// Enable experimental generation of Yul IR code.
|
||||
void enableIRGeneration(bool _enable = true) { m_generateIR = _enable; }
|
||||
|
||||
/// @arg _metadataLiteralSources When true, store sources as literals in the contract metadata.
|
||||
/// Must be set before parsing.
|
||||
void useMetadataLiteralSources(bool _metadataLiteralSources);
|
||||
@ -202,6 +206,12 @@ public:
|
||||
/// @returns either the contract's name or a mixture of its name and source file, sanitized for filesystem use
|
||||
std::string const filesystemFriendlyName(std::string const& _contractName) const;
|
||||
|
||||
/// @returns the IR representation of a contract.
|
||||
std::string const& yulIR(std::string const& _contractName) const;
|
||||
|
||||
/// @returns the optimized IR representation of a contract.
|
||||
std::string const& yulIROptimized(std::string const& _contractName) const;
|
||||
|
||||
/// @returns the assembled object for a contract.
|
||||
eth::LinkerObject const& object(std::string const& _contractName) const;
|
||||
|
||||
@ -273,6 +283,8 @@ private:
|
||||
std::shared_ptr<Compiler> compiler;
|
||||
eth::LinkerObject object; ///< Deployment object (includes the runtime sub-object).
|
||||
eth::LinkerObject runtimeObject; ///< Runtime object.
|
||||
std::string yulIR; ///< Experimental Yul IR code.
|
||||
std::string yulIROptimized; ///< Optimized experimental Yul IR code.
|
||||
mutable std::unique_ptr<std::string const> metadata; ///< The metadata json that will be hashed into the chain.
|
||||
mutable std::unique_ptr<Json::Value const> abi;
|
||||
mutable std::unique_ptr<Json::Value const> userDocumentation;
|
||||
@ -299,6 +311,10 @@ private:
|
||||
std::map<ContractDefinition const*, std::shared_ptr<Compiler const>>& _otherCompilers
|
||||
);
|
||||
|
||||
/// Generate Yul IR for a single contract.
|
||||
/// The IR is stored but otherwise unused.
|
||||
void generateIR(ContractDefinition const& _contract);
|
||||
|
||||
/// Links all the known library addresses in the available objects. Any unknown
|
||||
/// library will still be kept as an unlinked placeholder in the objects.
|
||||
void link();
|
||||
@ -351,6 +367,7 @@ private:
|
||||
OptimiserSettings m_optimiserSettings;
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
std::set<std::string> m_requestedContractNames;
|
||||
bool m_generateIR;
|
||||
std::map<std::string, h160> m_libraries;
|
||||
/// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum
|
||||
/// "context:prefix=target"
|
||||
|
@ -129,12 +129,18 @@ bool hashMatchesContent(string const& _hash, string const& _content)
|
||||
}
|
||||
}
|
||||
|
||||
bool isArtifactRequested(Json::Value const& _outputSelection, string const& _artifact)
|
||||
bool isArtifactRequested(Json::Value const& _outputSelection, string const& _artifact, bool _wildcardMatchesIR)
|
||||
{
|
||||
for (auto const& artifact: _outputSelection)
|
||||
/// @TODO support sub-matching, e.g "evm" matches "evm.assembly"
|
||||
if (artifact == "*" || artifact == _artifact)
|
||||
if (artifact == _artifact)
|
||||
return true;
|
||||
else if (artifact == "*")
|
||||
{
|
||||
// "ir" and "irOptimized" can only be matched by "*" if activated.
|
||||
if ((_artifact != "ir" && _artifact != "irOptimized") || _wildcardMatchesIR)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -151,7 +157,7 @@ bool isArtifactRequested(Json::Value const& _outputSelection, string const& _art
|
||||
///
|
||||
/// @TODO optimise this. Perhaps flatten the structure upfront.
|
||||
///
|
||||
bool isArtifactRequested(Json::Value const& _outputSelection, string const& _file, string const& _contract, string const& _artifact)
|
||||
bool isArtifactRequested(Json::Value const& _outputSelection, string const& _file, string const& _contract, string const& _artifact, bool _wildcardMatchesIR)
|
||||
{
|
||||
if (!_outputSelection.isObject())
|
||||
return false;
|
||||
@ -168,7 +174,7 @@ bool isArtifactRequested(Json::Value const& _outputSelection, string const& _fil
|
||||
if (
|
||||
_outputSelection[file].isMember(contract) &&
|
||||
_outputSelection[file][contract].isArray() &&
|
||||
isArtifactRequested(_outputSelection[file][contract], _artifact)
|
||||
isArtifactRequested(_outputSelection[file][contract], _artifact, _wildcardMatchesIR)
|
||||
)
|
||||
return true;
|
||||
}
|
||||
@ -176,10 +182,10 @@ bool isArtifactRequested(Json::Value const& _outputSelection, string const& _fil
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isArtifactRequested(Json::Value const& _outputSelection, string const& _file, string const& _contract, vector<string> const& _artifacts)
|
||||
bool isArtifactRequested(Json::Value const& _outputSelection, string const& _file, string const& _contract, vector<string> const& _artifacts, bool _wildcardMatchesIR)
|
||||
{
|
||||
for (auto const& artifact: _artifacts)
|
||||
if (isArtifactRequested(_outputSelection, _file, _contract, artifact))
|
||||
if (isArtifactRequested(_outputSelection, _file, _contract, artifact, _wildcardMatchesIR))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@ -193,6 +199,7 @@ bool isBinaryRequested(Json::Value const& _outputSelection)
|
||||
// This does not inculde "evm.methodIdentifiers" on purpose!
|
||||
static vector<string> const outputsThatRequireBinaries{
|
||||
"*",
|
||||
"ir", "irOptimized",
|
||||
"evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes",
|
||||
"evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences",
|
||||
"evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap",
|
||||
@ -203,11 +210,28 @@ bool isBinaryRequested(Json::Value const& _outputSelection)
|
||||
for (auto const& fileRequests: _outputSelection)
|
||||
for (auto const& requests: fileRequests)
|
||||
for (auto const& output: outputsThatRequireBinaries)
|
||||
if (isArtifactRequested(requests, output))
|
||||
if (isArtifactRequested(requests, output, false))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @returns true if any Yul IR was requested. Note that as an exception, '*' does not
|
||||
/// yet match "ir" or "irOptimized"
|
||||
bool isIRRequested(Json::Value const& _outputSelection)
|
||||
{
|
||||
if (!_outputSelection.isObject())
|
||||
return false;
|
||||
|
||||
for (auto const& fileRequests: _outputSelection)
|
||||
for (auto const& requests: fileRequests)
|
||||
for (auto const& request: requests)
|
||||
if (request == "ir" || request == "irOptimized")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Json::Value formatLinkReferences(std::map<size_t, std::string> const& linkReferences)
|
||||
{
|
||||
Json::Value ret(Json::objectValue);
|
||||
@ -657,6 +681,10 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
compilerStack.useMetadataLiteralSources(_inputsAndSettings.metadataLiteralSources);
|
||||
compilerStack.setRequestedContractNames(requestedContractNames(_inputsAndSettings.outputSelection));
|
||||
|
||||
bool const irRequested = isIRRequested(_inputsAndSettings.outputSelection);
|
||||
|
||||
compilerStack.enableIRGeneration(irRequested);
|
||||
|
||||
Json::Value errors = std::move(_inputsAndSettings.errors);
|
||||
|
||||
bool const binariesRequested = isBinaryRequested(_inputsAndSettings.outputSelection);
|
||||
@ -767,15 +795,17 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
for (string const& query: compilerStack.unhandledSMTLib2Queries())
|
||||
output["auxiliaryInputRequested"]["smtlib2queries"]["0x" + keccak256(query).hex()] = query;
|
||||
|
||||
bool const wildcardMatchesIR = false;
|
||||
|
||||
output["sources"] = Json::objectValue;
|
||||
unsigned sourceIndex = 0;
|
||||
for (string const& sourceName: analysisSuccess ? compilerStack.sourceNames() : vector<string>())
|
||||
{
|
||||
Json::Value sourceResult = Json::objectValue;
|
||||
sourceResult["id"] = sourceIndex++;
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, "", "ast"))
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, "", "ast", wildcardMatchesIR))
|
||||
sourceResult["ast"] = ASTJsonConverter(false, compilerStack.sourceIndices()).toJson(compilerStack.ast(sourceName));
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, "", "legacyAST"))
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, "", "legacyAST", wildcardMatchesIR))
|
||||
sourceResult["legacyAST"] = ASTJsonConverter(true, compilerStack.sourceIndices()).toJson(compilerStack.ast(sourceName));
|
||||
output["sources"][sourceName] = sourceResult;
|
||||
}
|
||||
@ -790,32 +820,38 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
|
||||
// ABI, documentation and metadata
|
||||
Json::Value contractData(Json::objectValue);
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "abi"))
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "abi", wildcardMatchesIR))
|
||||
contractData["abi"] = compilerStack.contractABI(contractName);
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "metadata"))
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "metadata", wildcardMatchesIR))
|
||||
contractData["metadata"] = compilerStack.metadata(contractName);
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "userdoc"))
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "userdoc", wildcardMatchesIR))
|
||||
contractData["userdoc"] = compilerStack.natspecUser(contractName);
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "devdoc"))
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "devdoc", wildcardMatchesIR))
|
||||
contractData["devdoc"] = compilerStack.natspecDev(contractName);
|
||||
|
||||
// IR
|
||||
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "ir", wildcardMatchesIR))
|
||||
contractData["ir"] = compilerStack.yulIR(contractName);
|
||||
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "irOptimized", wildcardMatchesIR))
|
||||
contractData["irOptimized"] = compilerStack.yulIROptimized(contractName);
|
||||
|
||||
// EVM
|
||||
Json::Value evmData(Json::objectValue);
|
||||
// @TODO: add ir
|
||||
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.assembly"))
|
||||
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.assembly", wildcardMatchesIR))
|
||||
evmData["assembly"] = compilerStack.assemblyString(contractName, sourceList);
|
||||
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.legacyAssembly"))
|
||||
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.legacyAssembly", wildcardMatchesIR))
|
||||
evmData["legacyAssembly"] = compilerStack.assemblyJSON(contractName, sourceList);
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.methodIdentifiers"))
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.methodIdentifiers", wildcardMatchesIR))
|
||||
evmData["methodIdentifiers"] = compilerStack.methodIdentifiers(contractName);
|
||||
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.gasEstimates"))
|
||||
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.gasEstimates", wildcardMatchesIR))
|
||||
evmData["gasEstimates"] = compilerStack.gasEstimates(contractName);
|
||||
|
||||
if (compilationSuccess && isArtifactRequested(
|
||||
_inputsAndSettings.outputSelection,
|
||||
file,
|
||||
name,
|
||||
{ "evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap", "evm.bytecode.linkReferences" }
|
||||
{ "evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap", "evm.bytecode.linkReferences" },
|
||||
wildcardMatchesIR
|
||||
))
|
||||
evmData["bytecode"] = collectEVMObject(
|
||||
compilerStack.object(contractName),
|
||||
@ -826,7 +862,8 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
_inputsAndSettings.outputSelection,
|
||||
file,
|
||||
name,
|
||||
{ "evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes", "evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences" }
|
||||
{ "evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes", "evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences" },
|
||||
wildcardMatchesIR
|
||||
))
|
||||
evmData["deployedBytecode"] = collectEVMObject(
|
||||
compilerStack.runtimeObject(contractName),
|
||||
@ -900,7 +937,8 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
|
||||
|
||||
string contractName = stack.parserResult()->name.str();
|
||||
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "ir"))
|
||||
bool const wildcardMatchesIR = true;
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "ir", wildcardMatchesIR))
|
||||
output["contracts"][sourceName][contractName]["ir"] = stack.print();
|
||||
|
||||
stack.optimize();
|
||||
@ -911,13 +949,14 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
|
||||
_inputsAndSettings.outputSelection,
|
||||
sourceName,
|
||||
contractName,
|
||||
{ "evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap", "evm.bytecode.linkReferences" }
|
||||
{ "evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap", "evm.bytecode.linkReferences" },
|
||||
wildcardMatchesIR
|
||||
))
|
||||
output["contracts"][sourceName][contractName]["evm"]["bytecode"] = collectEVMObject(*object.bytecode, nullptr);
|
||||
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "irOptimized"))
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "irOptimized", wildcardMatchesIR))
|
||||
output["contracts"][sourceName][contractName]["irOptimized"] = stack.print();
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "evm.assembly"))
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "evm.assembly", wildcardMatchesIR))
|
||||
output["contracts"][sourceName][contractName]["evm"]["assembly"] = object.assembly;
|
||||
|
||||
return output;
|
||||
|
@ -121,6 +121,7 @@ static string const g_strHelp = "help";
|
||||
static string const g_strInputFile = "input-file";
|
||||
static string const g_strInterface = "interface";
|
||||
static string const g_strYul = "yul";
|
||||
static string const g_strIR = "ir";
|
||||
static string const g_strLicense = "license";
|
||||
static string const g_strLibraries = "libraries";
|
||||
static string const g_strLink = "link";
|
||||
@ -166,6 +167,7 @@ static string const g_argGas = g_strGas;
|
||||
static string const g_argHelp = g_strHelp;
|
||||
static string const g_argInputFile = g_strInputFile;
|
||||
static string const g_argYul = g_strYul;
|
||||
static string const g_argIR = g_strIR;
|
||||
static string const g_argLibraries = g_strLibraries;
|
||||
static string const g_argLink = g_strLink;
|
||||
static string const g_argMachine = g_strMachine;
|
||||
@ -293,6 +295,20 @@ void CommandLineInterface::handleOpcode(string const& _contract)
|
||||
}
|
||||
}
|
||||
|
||||
void CommandLineInterface::handleIR(string const& _contractName)
|
||||
{
|
||||
if (m_args.count(g_argIR))
|
||||
{
|
||||
if (m_args.count(g_argOutputDir))
|
||||
createFile(m_compiler->filesystemFriendlyName(_contractName) + ".yul", m_compiler->yulIR(_contractName));
|
||||
else
|
||||
{
|
||||
sout() << "IR: " << endl;
|
||||
sout() << m_compiler->yulIR(_contractName) << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CommandLineInterface::handleBytecode(string const& _contract)
|
||||
{
|
||||
if (m_args.count(g_argOpcodes))
|
||||
@ -685,6 +701,7 @@ Allowed options)",
|
||||
(g_argBinary.c_str(), "Binary of the contracts in hex.")
|
||||
(g_argBinaryRuntime.c_str(), "Binary of the runtime part of the contracts in hex.")
|
||||
(g_argAbi.c_str(), "ABI specification of the contracts.")
|
||||
(g_argIR.c_str(), "Intermediate Representation (IR) of all contracts (EXPERIMENTAL).")
|
||||
(g_argSignatureHashes.c_str(), "Function signature hashes of the contracts.")
|
||||
(g_argNatspecUser.c_str(), "Natspec user documentation of all contracts.")
|
||||
(g_argNatspecDev.c_str(), "Natspec developer documentation of all contracts.")
|
||||
@ -907,6 +924,8 @@ bool CommandLineInterface::processInput()
|
||||
m_compiler->setEVMVersion(m_evmVersion);
|
||||
// TODO: Perhaps we should not compile unless requested
|
||||
|
||||
m_compiler->enableIRGeneration(m_args.count(g_argIR));
|
||||
|
||||
OptimiserSettings settings = m_args.count(g_argOptimize) ? OptimiserSettings::standard() : OptimiserSettings::minimal();
|
||||
settings.expectedExecutionsPerDeployment = m_args[g_argOptimizeRuns].as<unsigned>();
|
||||
settings.runYulOptimiser = m_args.count(g_strOptimizeYul);
|
||||
@ -1369,6 +1388,7 @@ void CommandLineInterface::outputCompilationResults()
|
||||
handleGasEstimation(contract);
|
||||
|
||||
handleBytecode(contract);
|
||||
handleIR(contract);
|
||||
handleSignatureHashes(contract);
|
||||
handleMetadata(contract);
|
||||
handleABI(contract);
|
||||
|
@ -65,6 +65,7 @@ private:
|
||||
void handleAst(std::string const& _argStr);
|
||||
void handleBinary(std::string const& _contract);
|
||||
void handleOpcode(std::string const& _contract);
|
||||
void handleIR(std::string const& _contract);
|
||||
void handleBytecode(std::string const& _contract);
|
||||
void handleSignatureHashes(std::string const& _contract);
|
||||
void handleMetadata(std::string const& _contract);
|
||||
|
17
test/cmdlineTests/standard_irOptimized_requested/input.json
Normal file
17
test/cmdlineTests/standard_irOptimized_requested/input.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "pragma solidity >=0.0; contract C { function f() public pure {} }"
|
||||
}
|
||||
},
|
||||
"settings":
|
||||
{
|
||||
"outputSelection":
|
||||
{
|
||||
"*": { "*": ["irOptimized"] }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
{"contracts":{"A":{"C":{"irOptimized":"/*******************************************************\n * WARNING *\n * Solidity to Yul compilation is still EXPERIMENTAL *\n * It can result in LOSS OF FUNDS or worse *\n * !USE AT YOUR OWN RISK! *\n *******************************************************/\n\nobject \"C_6\" {\n code {\n mstore(64, 128)\n codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))\n return(0, datasize(\"C_6_deployed\"))\n }\n object \"C_6_deployed\" {\n code {\n mstore(64, 128)\n if iszero(lt(calldatasize(), 4))\n {\n let selector := shift_right_224_unsigned(calldataload(0))\n switch selector\n case 0x26121ff0 {\n if callvalue()\n {\n revert(0, 0)\n }\n abi_decode_tuple_(4, calldatasize())\n fun_5_f()\n let memPos := allocateMemory(0)\n let memEnd := abi_encode_tuple__to__fromStack(memPos)\n return(memPos, sub(memEnd, memPos))\n }\n default {\n }\n }\n revert(0, 0)\n function abi_decode_tuple_(headStart, dataEnd)\n {\n if slt(sub(dataEnd, headStart), 0)\n {\n revert(0, 0)\n }\n }\n function abi_encode_tuple__to__fromStack(headStart) -> tail\n {\n tail := add(headStart, 0)\n }\n function allocateMemory(size) -> memPtr\n {\n memPtr := mload(64)\n let newFreePtr := add(memPtr, size)\n if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr))\n {\n revert(0, 0)\n }\n mstore(64, newFreePtr)\n }\n function fun_5_f()\n {\n }\n function shift_right_224_unsigned(value) -> newValue\n {\n newValue := shr(224, value)\n }\n }\n }\n}\n"}}},"sources":{"A":{"id":0}}}
|
17
test/cmdlineTests/standard_ir_requested/input.json
Normal file
17
test/cmdlineTests/standard_ir_requested/input.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "pragma solidity >=0.0; contract C { function f() public pure {} }"
|
||||
}
|
||||
},
|
||||
"settings":
|
||||
{
|
||||
"outputSelection":
|
||||
{
|
||||
"*": { "*": ["ir"] }
|
||||
}
|
||||
}
|
||||
}
|
1
test/cmdlineTests/standard_ir_requested/output.json
Normal file
1
test/cmdlineTests/standard_ir_requested/output.json
Normal file
@ -0,0 +1 @@
|
||||
{"contracts":{"A":{"C":{"ir":"/*******************************************************\n * WARNING *\n * Solidity to Yul compilation is still EXPERIMENTAL *\n * It can result in LOSS OF FUNDS or worse *\n * !USE AT YOUR OWN RISK! *\n *******************************************************/\n\n\n\t\tobject \"C_6\" {\n\t\t\tcode {\n\t\t\t\tmstore(64, 128)\n\t\t\t\t\n\t\t\t\t\n\t\tcodecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))\n\t\treturn(0, datasize(\"C_6_deployed\"))\n\t\n\t\t\t\t\n\t\t\t}\n\t\t\tobject \"C_6_deployed\" {\n\t\t\t\tcode {\n\t\t\t\t\tmstore(64, 128)\n\t\t\t\t\t\n\t\tif iszero(lt(calldatasize(), 4))\n\t\t{\n\t\t\tlet selector := shift_right_224_unsigned(calldataload(0))\n\t\t\tswitch selector\n\t\t\t\n\t\t\tcase 0x26121ff0\n\t\t\t{\n\t\t\t\t// f()\n\t\t\t\tif callvalue() { revert(0, 0) }\n\t\t\t\t abi_decode_tuple_(4, calldatasize())\n\t\t\t\t fun_5_f()\n\t\t\t\tlet memPos := allocateMemory(0)\n\t\t\t\tlet memEnd := abi_encode_tuple__to__fromStack(memPos )\n\t\t\t\treturn(memPos, sub(memEnd, memPos))\n\t\t\t}\n\t\t\t\n\t\t\tdefault {}\n\t\t}\n\t\trevert(0, 0)\n\t\n\t\t\t\t\t\n\t\t\tfunction abi_decode_tuple_(headStart, dataEnd) {\n\t\t\t\tif slt(sub(dataEnd, headStart), 0) { revert(0, 0) }\n\t\t\t\t\n\t\t\t}\n\t\t\n\t\t\tfunction abi_encode_tuple__to__fromStack(headStart ) -> tail {\n\t\t\t\ttail := add(headStart, 0)\n\t\t\t\t\n\t\t\t}\n\t\t\n\t\t\tfunction allocateMemory(size) -> memPtr {\n\t\t\t\tmemPtr := mload(64)\n\t\t\t\tlet newFreePtr := add(memPtr, size)\n\t\t\t\t// protect against overflow\n\t\t\t\tif or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) }\n\t\t\t\tmstore(64, newFreePtr)\n\t\t\t}\n\t\tfunction fun_5_f() {}\n\t\t\t\tfunction shift_right_224_unsigned(value) -> newValue {\n\t\t\t\t\tnewValue := shr(224, value)\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t"}}},"sources":{"A":{"id":0}}}
|
Loading…
Reference in New Issue
Block a user