mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Reset Yul string repository before each compilation.
This commit is contained in:
parent
b95eebee1c
commit
dbae0fa939
@ -22,6 +22,7 @@ Compiler Features:
|
||||
Bugfixes:
|
||||
* Code Generator: Explicitly turn uninitialized internal function pointers into invalid functions when loaded from storage.
|
||||
* Code Generator: Fix assertion failure when assigning structs containing array of mapping.
|
||||
* Compiler Internals: Reset the Yul string repository before each compilation, freeing up memory.
|
||||
* SMTChecker: Fix bad cast in base constructor modifier.
|
||||
* SMTChecker: Fix internal error when visiting state variable inherited from base class.
|
||||
* SMTChecker: Fix internal error in fixed point operations.
|
||||
|
@ -21,10 +21,11 @@
|
||||
*/
|
||||
|
||||
#include <libsolc/libsolc.h>
|
||||
#include <libdevcore/Common.h>
|
||||
#include <libdevcore/JSON.h>
|
||||
#include <libsolidity/interface/StandardCompiler.h>
|
||||
#include <libsolidity/interface/Version.h>
|
||||
#include <libyul/YulString.h>
|
||||
#include <libdevcore/Common.h>
|
||||
#include <libdevcore/JSON.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
@ -100,6 +101,9 @@ extern char const* solidity_compile(char const* _input, CStyleReadFileCallback _
|
||||
}
|
||||
extern void solidity_free() noexcept
|
||||
{
|
||||
// This is called right before each compilation, but not at the end, so additional memory
|
||||
// can be freed here.
|
||||
yul::YulStringRepository::reset();
|
||||
s_outputBuffer.clear();
|
||||
}
|
||||
}
|
||||
|
@ -965,6 +965,8 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
|
||||
|
||||
Json::Value StandardCompiler::compile(Json::Value const& _input) noexcept
|
||||
{
|
||||
YulStringRepository::reset();
|
||||
|
||||
try
|
||||
{
|
||||
auto parsed = parseInput(_input);
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
namespace yul
|
||||
{
|
||||
@ -34,7 +35,7 @@ namespace yul
|
||||
/// Owns the string data for all YulStrings, which can be referenced by a Handle.
|
||||
/// A Handle consists of an ID (that depends on the insertion order of YulStrings and is potentially
|
||||
/// non-deterministic) and a deterministic string hash.
|
||||
class YulStringRepository: boost::noncopyable
|
||||
class YulStringRepository
|
||||
{
|
||||
public:
|
||||
struct Handle
|
||||
@ -43,13 +44,12 @@ public:
|
||||
std::uint64_t hash;
|
||||
};
|
||||
|
||||
YulStringRepository() = default;
|
||||
|
||||
static YulStringRepository& instance()
|
||||
{
|
||||
static YulStringRepository inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
Handle stringToHandle(std::string const& _string)
|
||||
{
|
||||
if (_string.empty())
|
||||
@ -62,6 +62,7 @@ public:
|
||||
m_strings.emplace_back(std::make_shared<std::string>(_string));
|
||||
size_t id = m_strings.size() - 1;
|
||||
m_hashToID.emplace_hint(range.second, std::make_pair(h, id));
|
||||
|
||||
return Handle{id, h};
|
||||
}
|
||||
std::string const& idToString(size_t _id) const { return *m_strings.at(_id); }
|
||||
@ -79,8 +80,39 @@ public:
|
||||
return hash;
|
||||
}
|
||||
static constexpr std::uint64_t emptyHash() { return 14695981039346656037u; }
|
||||
/// Clear the repository.
|
||||
/// Use with care - there cannot be any dangling YulString references.
|
||||
/// If references need to be cleared manually, register the callback via
|
||||
/// resetCallback.
|
||||
static void reset()
|
||||
{
|
||||
for (auto const& cb: resetCallbacks())
|
||||
cb();
|
||||
instance() = YulStringRepository{};
|
||||
}
|
||||
/// Struct that registers a reset callback as a side-effect of its construction.
|
||||
/// Useful as static local variable to register a reset callback once.
|
||||
struct ResetCallback
|
||||
{
|
||||
ResetCallback(std::function<void()> _fun)
|
||||
{
|
||||
YulStringRepository::resetCallbacks().emplace_back(std::move(_fun));
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
YulStringRepository() = default;
|
||||
YulStringRepository(YulStringRepository const&) = delete;
|
||||
YulStringRepository(YulStringRepository&&) = default;
|
||||
YulStringRepository& operator=(YulStringRepository const& _rhs) = delete;
|
||||
YulStringRepository& operator=(YulStringRepository&& _rhs) = default;
|
||||
|
||||
static std::vector<std::function<void()>>& resetCallbacks()
|
||||
{
|
||||
static std::vector<std::function<void()>> callbacks;
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<std::string>> m_strings = {std::make_shared<std::string>()};
|
||||
std::unordered_multimap<std::uint64_t, size_t> m_hashToID = {{emptyHash(), 0}};
|
||||
};
|
||||
|
@ -182,6 +182,7 @@ BuiltinFunctionForEVM const* EVMDialect::builtin(YulString _name) const
|
||||
EVMDialect const& EVMDialect::looseAssemblyForEVM(langutil::EVMVersion _version)
|
||||
{
|
||||
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
||||
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
||||
if (!dialects[_version])
|
||||
dialects[_version] = make_unique<EVMDialect>(AsmFlavour::Loose, false, _version);
|
||||
return *dialects[_version];
|
||||
@ -190,6 +191,7 @@ EVMDialect const& EVMDialect::looseAssemblyForEVM(langutil::EVMVersion _version)
|
||||
EVMDialect const& EVMDialect::strictAssemblyForEVM(langutil::EVMVersion _version)
|
||||
{
|
||||
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
||||
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
||||
if (!dialects[_version])
|
||||
dialects[_version] = make_unique<EVMDialect>(AsmFlavour::Strict, false, _version);
|
||||
return *dialects[_version];
|
||||
@ -198,6 +200,7 @@ EVMDialect const& EVMDialect::strictAssemblyForEVM(langutil::EVMVersion _version
|
||||
EVMDialect const& EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion _version)
|
||||
{
|
||||
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
||||
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
||||
if (!dialects[_version])
|
||||
dialects[_version] = make_unique<EVMDialect>(AsmFlavour::Strict, true, _version);
|
||||
return *dialects[_version];
|
||||
@ -206,6 +209,7 @@ EVMDialect const& EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion _
|
||||
EVMDialect const& EVMDialect::yulForEVM(langutil::EVMVersion _version)
|
||||
{
|
||||
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
||||
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
||||
if (!dialects[_version])
|
||||
dialects[_version] = make_unique<EVMDialect>(AsmFlavour::Yul, false, _version);
|
||||
return *dialects[_version];
|
||||
|
@ -63,6 +63,15 @@ BuiltinFunction const* WasmDialect::builtin(YulString _name) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WasmDialect const& WasmDialect::instance()
|
||||
{
|
||||
static std::unique_ptr<WasmDialect> dialect;
|
||||
static YulStringRepository::ResetCallback callback{[&] { dialect.reset(); }};
|
||||
if (!dialect)
|
||||
dialect = make_unique<WasmDialect>();
|
||||
return *dialect;
|
||||
}
|
||||
|
||||
void WasmDialect::addFunction(string _name, size_t _params, size_t _returns)
|
||||
{
|
||||
YulString name{move(_name)};
|
||||
|
@ -42,17 +42,13 @@ struct Object;
|
||||
*/
|
||||
struct WasmDialect: public Dialect
|
||||
{
|
||||
BuiltinFunction const* builtin(YulString _name) const override;
|
||||
|
||||
static WasmDialect const& instance()
|
||||
{
|
||||
static WasmDialect dialect;
|
||||
return dialect;
|
||||
}
|
||||
|
||||
protected:
|
||||
WasmDialect();
|
||||
|
||||
BuiltinFunction const* builtin(YulString _name) const override;
|
||||
|
||||
static WasmDialect const& instance();
|
||||
|
||||
private:
|
||||
void addFunction(std::string _name, size_t _params, size_t _returns);
|
||||
|
||||
std::map<YulString, BuiltinFunction> m_functions;
|
||||
|
@ -142,7 +142,6 @@ void DataFlowAnalyzer::operator()(Block& _block)
|
||||
|
||||
void DataFlowAnalyzer::handleAssignment(set<YulString> const& _variables, Expression* _value)
|
||||
{
|
||||
static Expression const zero{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}};
|
||||
clearValues(_variables);
|
||||
|
||||
MovableChecker movableChecker{m_dialect};
|
||||
@ -150,7 +149,7 @@ void DataFlowAnalyzer::handleAssignment(set<YulString> const& _variables, Expres
|
||||
movableChecker.visit(*_value);
|
||||
else
|
||||
for (auto const& var: _variables)
|
||||
m_value[var] = &zero;
|
||||
m_value[var] = &m_zero;
|
||||
|
||||
if (_value && _variables.size() == 1)
|
||||
{
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <libyul/optimiser/ASTWalker.h>
|
||||
#include <libyul/YulString.h>
|
||||
#include <libyul/AsmData.h>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
@ -85,6 +86,9 @@ protected:
|
||||
std::set<YulString> variables;
|
||||
bool isFunction;
|
||||
};
|
||||
/// Special expression whose address will be used in m_value.
|
||||
/// YulString does not need to be reset because DataFlowAnalyzer is short-lived.
|
||||
Expression const m_zero{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}};
|
||||
/// List of scopes.
|
||||
std::vector<Scope> m_variableScopes;
|
||||
Dialect const& m_dialect;
|
||||
|
@ -179,8 +179,6 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC
|
||||
|
||||
m_driver.tentativelyUpdateCodeSize(function->name, m_currentFunction);
|
||||
|
||||
static Expression const zero{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}};
|
||||
|
||||
// helper function to create a new variable that is supposed to model
|
||||
// an existing variable.
|
||||
auto newVariable = [&](TypedName const& _existingVariable, Expression* _value) {
|
||||
@ -190,7 +188,7 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC
|
||||
if (_value)
|
||||
varDecl.value = make_unique<Expression>(std::move(*_value));
|
||||
else
|
||||
varDecl.value = make_unique<Expression>(zero);
|
||||
varDecl.value = make_unique<Expression>(Literal{{}, LiteralKind::Number, YulString{"0"}, {}});
|
||||
newStatements.emplace_back(std::move(varDecl));
|
||||
};
|
||||
|
||||
|
@ -56,8 +56,7 @@ void SSAValueTracker::setValue(YulString _name, Expression const* _value)
|
||||
OptimizerException,
|
||||
"Source needs to be disambiguated."
|
||||
);
|
||||
static Expression const zero{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}};
|
||||
if (!_value)
|
||||
_value = &zero;
|
||||
_value = &m_zero;
|
||||
m_values[_name] = _value;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <libyul/optimiser/ASTWalker.h>
|
||||
#include <libyul/AsmData.h>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
@ -51,6 +52,9 @@ public:
|
||||
private:
|
||||
void setValue(YulString _name, Expression const* _value);
|
||||
|
||||
/// Special expression whose address will be used in m_values.
|
||||
/// YulString does not need to be reset because SSAValueTracker is short-lived.
|
||||
Expression const m_zero{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}};
|
||||
std::map<YulString, Expression const*> m_values;
|
||||
};
|
||||
|
||||
|
@ -131,9 +131,8 @@ bool StructuralSimplifier::expressionAlwaysTrue(Expression const& _expression)
|
||||
return false;
|
||||
},
|
||||
[](Literal const& _literal) -> bool {
|
||||
static YulString const trueString("true");
|
||||
return
|
||||
(_literal.kind == LiteralKind::Boolean && _literal.value == trueString) ||
|
||||
(_literal.kind == LiteralKind::Boolean && _literal.value == "true"_yulstring) ||
|
||||
(_literal.kind == LiteralKind::Number && valueOfNumberLiteral(_literal) != u256(0))
|
||||
;
|
||||
}
|
||||
@ -149,9 +148,8 @@ bool StructuralSimplifier::expressionAlwaysFalse(Expression const& _expression)
|
||||
return false;
|
||||
},
|
||||
[](Literal const& _literal) -> bool {
|
||||
static YulString const falseString("false");
|
||||
return
|
||||
(_literal.kind == LiteralKind::Boolean && _literal.value == falseString) ||
|
||||
(_literal.kind == LiteralKind::Boolean && _literal.value == "false"_yulstring) ||
|
||||
(_literal.kind == LiteralKind::Number && valueOfNumberLiteral(_literal) == u256(0))
|
||||
;
|
||||
}
|
||||
|
@ -29,17 +29,16 @@ void VarDeclInitializer::operator()(Block& _block)
|
||||
{
|
||||
ASTModifier::operator()(_block);
|
||||
|
||||
static Expression const zero{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}};
|
||||
|
||||
using OptionalStatements = boost::optional<vector<Statement>>;
|
||||
GenericFallbackReturnsVisitor<OptionalStatements, VariableDeclaration> visitor{
|
||||
[](VariableDeclaration& _varDecl) -> OptionalStatements
|
||||
{
|
||||
if (_varDecl.value)
|
||||
return {};
|
||||
else if (_varDecl.variables.size() == 1)
|
||||
Literal zero{{}, LiteralKind::Number, YulString{"0"}, {}};
|
||||
if (_varDecl.variables.size() == 1)
|
||||
{
|
||||
_varDecl.value = make_unique<Expression>(zero);
|
||||
_varDecl.value = make_unique<Expression>(std::move(zero));
|
||||
return {};
|
||||
}
|
||||
else
|
||||
@ -47,7 +46,7 @@ void VarDeclInitializer::operator()(Block& _block)
|
||||
OptionalStatements ret{vector<Statement>{}};
|
||||
langutil::SourceLocation loc{std::move(_varDecl.location)};
|
||||
for (auto& var: _varDecl.variables)
|
||||
ret->push_back(VariableDeclaration{loc, {std::move(var)}, make_unique<Expression>(zero)});
|
||||
ret->emplace_back(VariableDeclaration{loc, {std::move(var)}, make_unique<Expression>(zero)});
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,8 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size)
|
||||
if (_size > 600)
|
||||
return 0;
|
||||
|
||||
YulStringRepository::reset();
|
||||
|
||||
string input(reinterpret_cast<char const*>(_data), _size);
|
||||
AssemblyStack stack(
|
||||
langutil::EVMVersion(),
|
||||
|
@ -55,6 +55,8 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size)
|
||||
}))
|
||||
return 0;
|
||||
|
||||
YulStringRepository::reset();
|
||||
|
||||
AssemblyStack stack(
|
||||
langutil::EVMVersion(),
|
||||
AssemblyStack::Language::StrictAssembly,
|
||||
|
@ -26,6 +26,8 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size)
|
||||
if (_size > 600)
|
||||
return 0;
|
||||
|
||||
YulStringRepository::reset();
|
||||
|
||||
string input(reinterpret_cast<char const*>(_data), _size);
|
||||
AssemblyStack stack(
|
||||
langutil::EVMVersion(),
|
||||
|
@ -46,6 +46,8 @@ DEFINE_PROTO_FUZZER(Program const& _input)
|
||||
if (yul_source.size() > 1200)
|
||||
return;
|
||||
|
||||
YulStringRepository::reset();
|
||||
|
||||
// AssemblyStack entry point
|
||||
AssemblyStack stack(
|
||||
langutil::EVMVersion(),
|
||||
|
@ -53,6 +53,8 @@ DEFINE_PROTO_FUZZER(Program const& _input)
|
||||
if (yul_source.size() > 1200)
|
||||
return;
|
||||
|
||||
YulStringRepository::reset();
|
||||
|
||||
// AssemblyStack entry point
|
||||
AssemblyStack stack(
|
||||
langutil::EVMVersion(),
|
||||
|
Loading…
Reference in New Issue
Block a user