aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity')
-rw-r--r--libsolidity/CMakeLists.txt1
-rw-r--r--libsolidity/analysis/ConstantEvaluator.cpp2
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp9
-rw-r--r--libsolidity/analysis/TypeChecker.cpp2
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp2
-rw-r--r--libsolidity/ast/Types.cpp103
-rw-r--r--libsolidity/ast/Types.h109
-rw-r--r--libsolidity/codegen/AsmCodeGen.cpp194
-rw-r--r--libsolidity/codegen/AsmCodeGen.h93
-rw-r--r--libsolidity/codegen/Compiler.cpp4
-rw-r--r--libsolidity/codegen/CompilerContext.cpp11
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp75
-rw-r--r--libsolidity/codegen/ContractCompiler.h12
-rw-r--r--libsolidity/formal/SMTChecker.cpp58
-rw-r--r--libsolidity/formal/SymbolicVariables.cpp26
-rw-r--r--libsolidity/formal/SymbolicVariables.h22
-rw-r--r--libsolidity/interface/AssemblyStack.cpp53
-rw-r--r--libsolidity/interface/AssemblyStack.h3
-rw-r--r--libsolidity/interface/CompilerStack.cpp2
-rw-r--r--libsolidity/interface/StandardCompiler.cpp22
20 files changed, 608 insertions, 195 deletions
diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt
index dc4c6d15..43d61c86 100644
--- a/libsolidity/CMakeLists.txt
+++ b/libsolidity/CMakeLists.txt
@@ -23,6 +23,7 @@ set(sources
ast/Types.cpp
codegen/ABIFunctions.cpp
codegen/ArrayUtils.cpp
+ codegen/AsmCodeGen.cpp
codegen/Compiler.cpp
codegen/CompilerContext.cpp
codegen/CompilerUtils.cpp
diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp
index 9d041ce5..26d9584b 100644
--- a/libsolidity/analysis/ConstantEvaluator.cpp
+++ b/libsolidity/analysis/ConstantEvaluator.cpp
@@ -41,7 +41,7 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
auto right = type(_operation.rightExpression());
if (left && right)
{
- auto commonType = left->binaryOperatorResult(_operation.getOperator(), right);
+ TypePointer commonType = left->binaryOperatorResult(_operation.getOperator(), right);
if (!commonType)
m_errorReporter.fatalTypeError(
_operation.location(),
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index c4931d98..ac88a052 100644
--- a/libsolidity/analysis/ReferencesResolver.cpp
+++ b/libsolidity/analysis/ReferencesResolver.cpp
@@ -316,7 +316,14 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
// We use the latest EVM version because we will re-run it anyway.
yul::AsmAnalysisInfo analysisInfo;
boost::optional<Error::Type> errorTypeForLoose = Error::Type::SyntaxError;
- yul::AsmAnalyzer(analysisInfo, errorsIgnored, EVMVersion(), errorTypeForLoose, yul::AsmFlavour::Loose, resolver).analyze(_inlineAssembly.operations());
+ yul::AsmAnalyzer(
+ analysisInfo,
+ errorsIgnored,
+ EVMVersion(),
+ errorTypeForLoose,
+ yul::Dialect::looseAssemblyForEVM(),
+ resolver
+ ).analyze(_inlineAssembly.operations());
return false;
}
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 9350df05..5c8e0c6c 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -658,7 +658,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
m_errorReporter,
m_evmVersion,
Error::Type::SyntaxError,
- yul::AsmFlavour::Loose,
+ yul::Dialect::looseAssemblyForEVM(),
identifierAccess
);
if (!analyzer.analyze(_inlineAssembly.operations()))
diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp
index cfb13271..e92134a8 100644
--- a/libsolidity/ast/ASTJsonConverter.cpp
+++ b/libsolidity/ast/ASTJsonConverter.cpp
@@ -724,7 +724,7 @@ bool ASTJsonConverter::visit(Literal const& _node)
std::vector<pair<string, Json::Value>> attributes = {
make_pair(m_legacy ? "token" : "kind", literalTokenKind(_node.token())),
make_pair("value", value),
- make_pair(m_legacy ? "hexvalue" : "hexValue", toHex(_node.value())),
+ make_pair(m_legacy ? "hexvalue" : "hexValue", toHex(asBytes(_node.value()))),
make_pair(
"subdenomination",
subdenomination == Token::Illegal ?
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 6cadb5f3..fd8839ca 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -466,7 +466,7 @@ string AddressType::richIdentifier() const
return "t_address";
}
-bool AddressType::isImplicitlyConvertibleTo(Type const& _other) const
+BoolResult AddressType::isImplicitlyConvertibleTo(Type const& _other) const
{
if (_other.category() != category())
return false;
@@ -475,7 +475,7 @@ bool AddressType::isImplicitlyConvertibleTo(Type const& _other) const
return other.m_stateMutability <= m_stateMutability;
}
-bool AddressType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+BoolResult AddressType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
if (auto const* contractType = dynamic_cast<ContractType const*>(&_convertTo))
return (m_stateMutability >= StateMutability::Payable) || !contractType->isPayable();
@@ -504,13 +504,13 @@ u256 AddressType::literalValue(Literal const* _literal) const
return u256(_literal->valueWithoutUnderscores());
}
-TypePointer AddressType::unaryOperatorResult(Token _operator) const
+TypeResult AddressType::unaryOperatorResult(Token _operator) const
{
return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer();
}
-TypePointer AddressType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
+TypeResult AddressType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
// Addresses can only be compared.
if (!TokenTraits::isCompareOp(_operator))
@@ -576,7 +576,7 @@ string IntegerType::richIdentifier() const
return "t_" + string(isSigned() ? "" : "u") + "int" + to_string(numBits());
}
-bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
+BoolResult IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
if (_convertTo.category() == category())
{
@@ -597,7 +597,7 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return false;
}
-bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+BoolResult IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
return _convertTo.category() == category() ||
_convertTo.category() == Category::Address ||
@@ -607,18 +607,17 @@ bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
_convertTo.category() == Category::FixedPoint;
}
-TypePointer IntegerType::unaryOperatorResult(Token _operator) const
+TypeResult IntegerType::unaryOperatorResult(Token _operator) const
{
// "delete" is ok for all integer types
if (_operator == Token::Delete)
- return make_shared<TupleType>();
- // we allow +, -, ++ and --
- else if (_operator == Token::Add || _operator == Token::Sub ||
- _operator == Token::Inc || _operator == Token::Dec ||
- _operator == Token::BitNot)
- return shared_from_this();
+ return TypeResult{make_shared<TupleType>()};
+ // we allow -, ++ and --
+ else if (_operator == Token::Sub || _operator == Token::Inc ||
+ _operator == Token::Dec || _operator == Token::BitNot)
+ return TypeResult{shared_from_this()};
else
- return TypePointer();
+ return TypeResult{""};
}
bool IntegerType::operator==(Type const& _other) const
@@ -651,7 +650,7 @@ bigint IntegerType::maxValue() const
return (bigint(1) << m_bits) - 1;
}
-TypePointer IntegerType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
+TypeResult IntegerType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
if (
_other->category() != Category::RationalNumber &&
@@ -704,7 +703,7 @@ string FixedPointType::richIdentifier() const
return "t_" + string(isSigned() ? "" : "u") + "fixed" + to_string(m_totalBits) + "x" + to_string(m_fractionalDigits);
}
-bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const
+BoolResult FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
if (_convertTo.category() == category())
{
@@ -717,18 +716,18 @@ bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return false;
}
-bool FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+BoolResult FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
return _convertTo.category() == category() || _convertTo.category() == Category::Integer;
}
-TypePointer FixedPointType::unaryOperatorResult(Token _operator) const
+TypeResult FixedPointType::unaryOperatorResult(Token _operator) const
{
switch(_operator)
{
case Token::Delete:
// "delete" is ok for all fixed types
- return make_shared<TupleType>();
+ return TypeResult(make_shared<TupleType>());
case Token::Add:
case Token::Sub:
case Token::Inc:
@@ -771,7 +770,7 @@ bigint FixedPointType::minIntegerValue() const
return bigint(0);
}
-TypePointer FixedPointType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
+TypeResult FixedPointType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
auto commonType = Type::commonType(shared_from_this(), _other);
@@ -957,7 +956,7 @@ tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal
return make_tuple(true, value);
}
-bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
+BoolResult RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
switch (_convertTo.category())
{
@@ -995,7 +994,7 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
}
}
-bool RationalNumberType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+BoolResult RationalNumberType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
if (isImplicitlyConvertibleTo(_convertTo))
return true;
@@ -1008,7 +1007,7 @@ bool RationalNumberType::isExplicitlyConvertibleTo(Type const& _convertTo) const
return false;
}
-TypePointer RationalNumberType::unaryOperatorResult(Token _operator) const
+TypeResult RationalNumberType::unaryOperatorResult(Token _operator) const
{
rational value;
switch (_operator)
@@ -1029,10 +1028,10 @@ TypePointer RationalNumberType::unaryOperatorResult(Token _operator) const
default:
return TypePointer();
}
- return make_shared<RationalNumberType>(value);
+ return TypeResult(make_shared<RationalNumberType>(value));
}
-TypePointer RationalNumberType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
+TypeResult RationalNumberType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
if (_other->category() == Category::Integer || _other->category() == Category::FixedPoint)
{
@@ -1214,7 +1213,7 @@ TypePointer RationalNumberType::binaryOperatorResult(Token _operator, TypePointe
if (value.numerator() != 0 && max(mostSignificantBit(abs(value.numerator())), mostSignificantBit(abs(value.denominator()))) > 4096)
return TypePointer();
- return make_shared<RationalNumberType>(value);
+ return TypeResult(make_shared<RationalNumberType>(value));
}
}
@@ -1354,7 +1353,7 @@ StringLiteralType::StringLiteralType(Literal const& _literal):
{
}
-bool StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const
+BoolResult StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
if (auto fixedBytes = dynamic_cast<FixedBytesType const*>(&_convertTo))
return size_t(fixedBytes->numBytes()) >= m_value.size();
@@ -1409,7 +1408,7 @@ FixedBytesType::FixedBytesType(unsigned _bytes): m_bytes(_bytes)
);
}
-bool FixedBytesType::isImplicitlyConvertibleTo(Type const& _convertTo) const
+BoolResult FixedBytesType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
if (_convertTo.category() != category())
return false;
@@ -1417,7 +1416,7 @@ bool FixedBytesType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return convertTo.m_bytes >= m_bytes;
}
-bool FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+BoolResult FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
return (_convertTo.category() == Category::Integer && numBytes() * 8 == dynamic_cast<IntegerType const&>(_convertTo).numBits()) ||
(_convertTo.category() == Category::Address && numBytes() == 20) ||
@@ -1425,18 +1424,18 @@ bool FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) const
_convertTo.category() == category();
}
-TypePointer FixedBytesType::unaryOperatorResult(Token _operator) const
+TypeResult FixedBytesType::unaryOperatorResult(Token _operator) const
{
// "delete" and "~" is okay for FixedBytesType
if (_operator == Token::Delete)
- return make_shared<TupleType>();
+ return TypeResult(make_shared<TupleType>());
else if (_operator == Token::BitNot)
return shared_from_this();
return TypePointer();
}
-TypePointer FixedBytesType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
+TypeResult FixedBytesType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
if (TokenTraits::isShiftOp(_operator))
{
@@ -1452,7 +1451,7 @@ TypePointer FixedBytesType::binaryOperatorResult(Token _operator, TypePointer co
// FixedBytes can be compared and have bitwise operators applied to them
if (TokenTraits::isCompareOp(_operator) || TokenTraits::isBitOp(_operator))
- return commonType;
+ return TypeResult(commonType);
return TypePointer();
}
@@ -1486,14 +1485,14 @@ u256 BoolType::literalValue(Literal const* _literal) const
solAssert(false, "Bool type constructed from non-boolean literal.");
}
-TypePointer BoolType::unaryOperatorResult(Token _operator) const
+TypeResult BoolType::unaryOperatorResult(Token _operator) const
{
if (_operator == Token::Delete)
- return make_shared<TupleType>();
+ return TypeResult(make_shared<TupleType>());
return (_operator == Token::Not) ? shared_from_this() : TypePointer();
}
-TypePointer BoolType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
+TypeResult BoolType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
if (category() != _other->category())
return TypePointer();
@@ -1503,7 +1502,7 @@ TypePointer BoolType::binaryOperatorResult(Token _operator, TypePointer const& _
return TypePointer();
}
-bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
+BoolResult ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
if (*this == _convertTo)
return true;
@@ -1520,7 +1519,7 @@ bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return false;
}
-bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+BoolResult ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
if (auto const* addressType = dynamic_cast<AddressType const*>(&_convertTo))
return isPayable() || (addressType->stateMutability() < StateMutability::Payable);
@@ -1533,14 +1532,14 @@ bool ContractType::isPayable() const
return fallbackFunction && fallbackFunction->isPayable();
}
-TypePointer ContractType::unaryOperatorResult(Token _operator) const
+TypeResult ContractType::unaryOperatorResult(Token _operator) const
{
if (isSuper())
return TypePointer{};
return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer();
}
-TypePointer ReferenceType::unaryOperatorResult(Token _operator) const
+TypeResult ReferenceType::unaryOperatorResult(Token _operator) const
{
if (_operator != Token::Delete)
return TypePointer();
@@ -1551,7 +1550,7 @@ TypePointer ReferenceType::unaryOperatorResult(Token _operator) const
case DataLocation::CallData:
return TypePointer();
case DataLocation::Memory:
- return make_shared<TupleType>();
+ return TypeResult(make_shared<TupleType>());
case DataLocation::Storage:
return m_isPointer ? TypePointer() : make_shared<TupleType>();
}
@@ -1605,7 +1604,7 @@ string ReferenceType::identifierLocationSuffix() const
return id;
}
-bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const
+BoolResult ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const
{
if (_convertTo.category() != category())
return false;
@@ -1645,7 +1644,7 @@ bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const
}
}
-bool ArrayType::isExplicitlyConvertibleTo(const Type& _convertTo) const
+BoolResult ArrayType::isExplicitlyConvertibleTo(const Type& _convertTo) const
{
if (isImplicitlyConvertibleTo(_convertTo))
return true;
@@ -2006,7 +2005,7 @@ vector<tuple<VariableDeclaration const*, u256, unsigned>> ContractType::stateVar
return variablesAndOffsets;
}
-bool StructType::isImplicitlyConvertibleTo(const Type& _convertTo) const
+BoolResult StructType::isImplicitlyConvertibleTo(const Type& _convertTo) const
{
if (_convertTo.category() != category())
return false;
@@ -2249,7 +2248,7 @@ bool StructType::recursive() const
return *m_recursive;
}
-TypePointer EnumType::unaryOperatorResult(Token _operator) const
+TypeResult EnumType::unaryOperatorResult(Token _operator) const
{
return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer();
}
@@ -2291,7 +2290,7 @@ size_t EnumType::numberOfMembers() const
return m_enum.members().size();
};
-bool EnumType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+BoolResult EnumType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
return _convertTo == *this || _convertTo.category() == Category::Integer;
}
@@ -2308,7 +2307,7 @@ unsigned EnumType::memberValue(ASTString const& _member) const
solAssert(false, "Requested unknown enum value " + _member);
}
-bool TupleType::isImplicitlyConvertibleTo(Type const& _other) const
+BoolResult TupleType::isImplicitlyConvertibleTo(Type const& _other) const
{
if (auto tupleType = dynamic_cast<TupleType const*>(&_other))
{
@@ -2648,14 +2647,14 @@ bool FunctionType::operator==(Type const& _other) const
return true;
}
-bool FunctionType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+BoolResult FunctionType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
if (m_kind == Kind::External && _convertTo == AddressType::address())
return true;
return _convertTo.category() == category();
}
-bool FunctionType::isImplicitlyConvertibleTo(Type const& _convertTo) const
+BoolResult FunctionType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
if (_convertTo.category() != category())
return false;
@@ -2680,14 +2679,14 @@ bool FunctionType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return true;
}
-TypePointer FunctionType::unaryOperatorResult(Token _operator) const
+TypeResult FunctionType::unaryOperatorResult(Token _operator) const
{
if (_operator == Token::Delete)
- return make_shared<TupleType>();
+ return TypeResult(make_shared<TupleType>());
return TypePointer();
}
-TypePointer FunctionType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
+TypeResult FunctionType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
if (_other->category() != category() || !(_operator == Token::Equal || _operator == Token::NotEqual))
return TypePointer();
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 0f0548d3..39157abe 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -29,6 +29,7 @@
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
+#include <libdevcore/Result.h>
#include <boost/noncopyable.hpp>
#include <boost/rational.hpp>
@@ -50,6 +51,8 @@ using TypePointer = std::shared_ptr<Type const>;
using FunctionTypePointer = std::shared_ptr<FunctionType const>;
using TypePointers = std::vector<TypePointer>;
using rational = boost::rational<dev::bigint>;
+using TypeResult = Result<TypePointer>;
+using BoolResult = Result<bool>;
inline rational makeRational(bigint const& _numerator, bigint const& _denominator)
{
@@ -63,6 +66,7 @@ inline rational makeRational(bigint const& _numerator, bigint const& _denominato
enum class DataLocation { Storage, CallData, Memory };
+
/**
* Helper class to compute storage offsets of members of structs and contracts.
*/
@@ -189,19 +193,19 @@ public:
/// @returns an escaped identifier (will not contain any parenthesis or commas)
static std::string escapeIdentifier(std::string const& _identifier);
- virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; }
- virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const
+ virtual BoolResult isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; }
+ virtual BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const
{
return isImplicitlyConvertibleTo(_convertTo);
}
/// @returns the resulting type of applying the given unary operator or an empty pointer if
/// this is not possible.
/// The default implementation does not allow any unary operator.
- virtual TypePointer unaryOperatorResult(Token) const { return TypePointer(); }
+ virtual TypeResult unaryOperatorResult(Token) const { return TypePointer(); }
/// @returns the resulting type of applying the given binary operator or an empty pointer if
/// this is not possible.
/// The default implementation allows comparison operators if a common type exists
- virtual TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const
+ virtual TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
return TokenTraits::isCompareOp(_operator) ? commonType(shared_from_this(), _other) : TypePointer();
}
@@ -336,10 +340,10 @@ public:
explicit AddressType(StateMutability _stateMutability);
std::string richIdentifier() const override;
- bool isImplicitlyConvertibleTo(Type const& _other) const override;
- bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- TypePointer unaryOperatorResult(Token _operator) const override;
- TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
+ BoolResult isImplicitlyConvertibleTo(Type const& _other) const override;
+ BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ TypeResult unaryOperatorResult(Token _operator) const override;
+ TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
bool operator==(Type const& _other) const override;
@@ -381,10 +385,10 @@ public:
explicit IntegerType(unsigned _bits, Modifier _modifier = Modifier::Unsigned);
std::string richIdentifier() const override;
- bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- TypePointer unaryOperatorResult(Token _operator) const override;
- TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
+ BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ TypeResult unaryOperatorResult(Token _operator) const override;
+ TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
bool operator==(Type const& _other) const override;
@@ -423,10 +427,10 @@ public:
explicit FixedPointType(unsigned _totalBits, unsigned _fractionalDigits, Modifier _modifier = Modifier::Unsigned);
std::string richIdentifier() const override;
- bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- TypePointer unaryOperatorResult(Token _operator) const override;
- TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
+ BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ TypeResult unaryOperatorResult(Token _operator) const override;
+ TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
bool operator==(Type const& _other) const override;
@@ -476,11 +480,10 @@ public:
explicit RationalNumberType(rational const& _value, TypePointer const& _compatibleBytesType = TypePointer()):
m_value(_value), m_compatibleBytesType(_compatibleBytesType)
{}
-
- bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- TypePointer unaryOperatorResult(Token _operator) const override;
- TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
+ BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ TypeResult unaryOperatorResult(Token _operator) const override;
+ TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
std::string richIdentifier() const override;
bool operator==(Type const& _other) const override;
@@ -536,8 +539,8 @@ public:
explicit StringLiteralType(Literal const& _literal);
- bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- TypePointer binaryOperatorResult(Token, TypePointer const&) const override
+ BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ TypeResult binaryOperatorResult(Token, TypePointer const&) const override
{
return TypePointer();
}
@@ -570,12 +573,12 @@ public:
explicit FixedBytesType(unsigned _bytes);
- bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
std::string richIdentifier() const override;
bool operator==(Type const& _other) const override;
- TypePointer unaryOperatorResult(Token _operator) const override;
- TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
+ TypeResult unaryOperatorResult(Token _operator) const override;
+ TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
unsigned calldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; }
unsigned storageBytes() const override { return m_bytes; }
@@ -601,8 +604,8 @@ public:
BoolType() {}
Category category() const override { return Category::Bool; }
std::string richIdentifier() const override { return "t_bool"; }
- TypePointer unaryOperatorResult(Token _operator) const override;
- TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
+ TypeResult unaryOperatorResult(Token _operator) const override;
+ TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
unsigned calldataEncodedSize(bool _padded) const override{ return _padded ? 32 : 1; }
unsigned storageBytes() const override { return 1; }
@@ -624,8 +627,8 @@ public:
explicit ReferenceType(DataLocation _location): m_location(_location) {}
DataLocation location() const { return m_location; }
- TypePointer unaryOperatorResult(Token _operator) const override;
- TypePointer binaryOperatorResult(Token, TypePointer const&) const override
+ TypeResult unaryOperatorResult(Token _operator) const override;
+ TypeResult binaryOperatorResult(Token, TypePointer const&) const override
{
return TypePointer();
}
@@ -702,8 +705,8 @@ public:
m_length(_length)
{}
- bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
std::string richIdentifier() const override;
bool operator==(const Type& _other) const override;
unsigned calldataEncodedSize(bool _padded) const override;
@@ -757,10 +760,10 @@ public:
explicit ContractType(ContractDefinition const& _contract, bool _super = false):
m_contract(_contract), m_super(_super) {}
/// Contracts can be implicitly converted only to base contracts.
- bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
/// Contracts can only be explicitly converted to address types and base contracts.
- bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- TypePointer unaryOperatorResult(Token _operator) const override;
+ BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ TypeResult unaryOperatorResult(Token _operator) const override;
std::string richIdentifier() const override;
bool operator==(Type const& _other) const override;
unsigned calldataEncodedSize(bool _padded ) const override
@@ -821,7 +824,7 @@ public:
Category category() const override { return Category::Struct; }
explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage):
ReferenceType(_location), m_struct(_struct) {}
- bool isImplicitlyConvertibleTo(const Type& _convertTo) const override;
+ BoolResult isImplicitlyConvertibleTo(const Type& _convertTo) const override;
std::string richIdentifier() const override;
bool operator==(Type const& _other) const override;
unsigned calldataEncodedSize(bool _padded) const override;
@@ -876,7 +879,7 @@ class EnumType: public Type
public:
Category category() const override { return Category::Enum; }
explicit EnumType(EnumDefinition const& _enum): m_enum(_enum) {}
- TypePointer unaryOperatorResult(Token _operator) const override;
+ TypeResult unaryOperatorResult(Token _operator) const override;
std::string richIdentifier() const override;
bool operator==(Type const& _other) const override;
unsigned calldataEncodedSize(bool _padded) const override
@@ -889,7 +892,7 @@ public:
std::string canonicalName() const override;
bool isValueType() const override { return true; }
- bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
TypePointer encodingType() const override
{
return std::make_shared<IntegerType>(8 * int(storageBytes()));
@@ -917,10 +920,10 @@ class TupleType: public Type
public:
Category category() const override { return Category::Tuple; }
explicit TupleType(std::vector<TypePointer> const& _types = std::vector<TypePointer>()): m_components(_types) {}
- bool isImplicitlyConvertibleTo(Type const& _other) const override;
+ BoolResult isImplicitlyConvertibleTo(Type const& _other) const override;
std::string richIdentifier() const override;
bool operator==(Type const& _other) const override;
- TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
+ TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
std::string toString(bool) const override;
bool canBeStored() const override { return false; }
u256 storageSize() const override;
@@ -1065,10 +1068,10 @@ public:
std::string richIdentifier() const override;
bool operator==(Type const& _other) const override;
- bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- TypePointer unaryOperatorResult(Token _operator) const override;
- TypePointer binaryOperatorResult(Token, TypePointer const&) const override;
+ BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ TypeResult unaryOperatorResult(Token _operator) const override;
+ TypeResult binaryOperatorResult(Token, TypePointer const&) const override;
std::string canonicalName() const override;
std::string toString(bool _short) const override;
unsigned calldataEncodedSize(bool _padded) const override;
@@ -1197,7 +1200,7 @@ public:
std::string toString(bool _short) const override;
std::string canonicalName() const override;
bool canLiveOutsideStorage() const override { return false; }
- TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
+ TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
TypePointer encodingType() const override
{
return std::make_shared<IntegerType>(256);
@@ -1230,7 +1233,7 @@ public:
explicit TypeType(TypePointer const& _actualType): m_actualType(_actualType) {}
TypePointer const& actualType() const { return m_actualType; }
- TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
+ TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
std::string richIdentifier() const override;
bool operator==(Type const& _other) const override;
bool canBeStored() const override { return false; }
@@ -1255,7 +1258,7 @@ public:
Category category() const override { return Category::Modifier; }
explicit ModifierType(ModifierDefinition const& _modifier);
- TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
+ TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
bool canBeStored() const override { return false; }
u256 storageSize() const override;
bool canLiveOutsideStorage() const override { return false; }
@@ -1281,7 +1284,7 @@ public:
explicit ModuleType(SourceUnit const& _source): m_sourceUnit(_source) {}
- TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
+ TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
std::string richIdentifier() const override;
bool operator==(Type const& _other) const override;
bool canBeStored() const override { return false; }
@@ -1308,7 +1311,7 @@ public:
explicit MagicType(Kind _kind): m_kind(_kind) {}
- TypePointer binaryOperatorResult(Token, TypePointer const&) const override
+ TypeResult binaryOperatorResult(Token, TypePointer const&) const override
{
return TypePointer();
}
@@ -1339,9 +1342,9 @@ public:
Category category() const override { return Category::InaccessibleDynamic; }
std::string richIdentifier() const override { return "t_inaccessible"; }
- bool isImplicitlyConvertibleTo(Type const&) const override { return false; }
- bool isExplicitlyConvertibleTo(Type const&) const override { return false; }
- TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
+ BoolResult isImplicitlyConvertibleTo(Type const&) const override { return false; }
+ BoolResult isExplicitlyConvertibleTo(Type const&) const override { return false; }
+ TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
unsigned calldataEncodedSize(bool _padded) const override { (void)_padded; return 32; }
bool canBeStored() const override { return false; }
bool canLiveOutsideStorage() const override { return false; }
diff --git a/libsolidity/codegen/AsmCodeGen.cpp b/libsolidity/codegen/AsmCodeGen.cpp
new file mode 100644
index 00000000..dfcc900b
--- /dev/null
+++ b/libsolidity/codegen/AsmCodeGen.cpp
@@ -0,0 +1,194 @@
+/*
+ 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/>.
+*/
+/**
+ * Adaptor between the abstract assembly and eth assembly.
+ */
+
+#include <libsolidity/codegen/AsmCodeGen.h>
+
+#include <libyul/AsmData.h>
+#include <libyul/AsmAnalysisInfo.h>
+
+#include <libyul/backends/evm/AbstractAssembly.h>
+#include <libyul/backends/evm/EVMCodeTransform.h>
+
+#include <libevmasm/Assembly.h>
+#include <libevmasm/AssemblyItem.h>
+#include <libevmasm/Instruction.h>
+
+#include <liblangutil/SourceLocation.h>
+
+#include <libdevcore/FixedHash.h>
+
+#include <memory>
+#include <functional>
+
+using namespace std;
+using namespace dev;
+using namespace langutil;
+using namespace yul;
+using namespace dev::solidity;
+
+EthAssemblyAdapter::EthAssemblyAdapter(eth::Assembly& _assembly):
+ m_assembly(_assembly)
+{
+}
+
+void EthAssemblyAdapter::setSourceLocation(SourceLocation const& _location)
+{
+ m_assembly.setSourceLocation(_location);
+}
+
+int EthAssemblyAdapter::stackHeight() const
+{
+ return m_assembly.deposit();
+}
+
+void EthAssemblyAdapter::appendInstruction(solidity::Instruction _instruction)
+{
+ m_assembly.append(_instruction);
+}
+
+void EthAssemblyAdapter::appendConstant(u256 const& _constant)
+{
+ m_assembly.append(_constant);
+}
+
+void EthAssemblyAdapter::appendLabel(LabelID _labelId)
+{
+ m_assembly.append(eth::AssemblyItem(eth::Tag, _labelId));
+}
+
+void EthAssemblyAdapter::appendLabelReference(LabelID _labelId)
+{
+ m_assembly.append(eth::AssemblyItem(eth::PushTag, _labelId));
+}
+
+size_t EthAssemblyAdapter::newLabelId()
+{
+ return assemblyTagToIdentifier(m_assembly.newTag());
+}
+
+size_t EthAssemblyAdapter::namedLabel(std::string const& _name)
+{
+ return assemblyTagToIdentifier(m_assembly.namedTag(_name));
+}
+
+void EthAssemblyAdapter::appendLinkerSymbol(std::string const& _linkerSymbol)
+{
+ m_assembly.appendLibraryAddress(_linkerSymbol);
+}
+
+void EthAssemblyAdapter::appendJump(int _stackDiffAfter)
+{
+ appendInstruction(solidity::Instruction::JUMP);
+ m_assembly.adjustDeposit(_stackDiffAfter);
+}
+
+void EthAssemblyAdapter::appendJumpTo(LabelID _labelId, int _stackDiffAfter)
+{
+ appendLabelReference(_labelId);
+ appendJump(_stackDiffAfter);
+}
+
+void EthAssemblyAdapter::appendJumpToIf(LabelID _labelId)
+{
+ appendLabelReference(_labelId);
+ appendInstruction(solidity::Instruction::JUMPI);
+}
+
+void EthAssemblyAdapter::appendBeginsub(LabelID, int)
+{
+ // TODO we could emulate that, though
+ solAssert(false, "BEGINSUB not implemented for EVM 1.0");
+}
+
+void EthAssemblyAdapter::appendJumpsub(LabelID, int, int)
+{
+ // TODO we could emulate that, though
+ solAssert(false, "JUMPSUB not implemented for EVM 1.0");
+}
+
+void EthAssemblyAdapter::appendReturnsub(int, int)
+{
+ // TODO we could emulate that, though
+ solAssert(false, "RETURNSUB not implemented for EVM 1.0");
+}
+
+void EthAssemblyAdapter::appendAssemblySize()
+{
+ m_assembly.appendProgramSize();
+}
+
+pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly()
+{
+ shared_ptr<eth::Assembly> assembly{make_shared<eth::Assembly>()};
+ auto sub = m_assembly.newSub(assembly);
+ return {make_shared<EthAssemblyAdapter>(*assembly), size_t(sub.data())};
+}
+
+void EthAssemblyAdapter::appendDataOffset(AbstractAssembly::SubID _sub)
+{
+ auto it = m_dataHashBySubId.find(_sub);
+ if (it == m_dataHashBySubId.end())
+ m_assembly.pushSubroutineOffset(size_t(_sub));
+ else
+ m_assembly << eth::AssemblyItem(eth::PushData, it->second);
+}
+
+void EthAssemblyAdapter::appendDataSize(AbstractAssembly::SubID _sub)
+{
+ auto it = m_dataHashBySubId.find(_sub);
+ if (it == m_dataHashBySubId.end())
+ m_assembly.pushSubroutineSize(size_t(_sub));
+ else
+ m_assembly << u256(m_assembly.data(h256(it->second)).size());
+}
+
+AbstractAssembly::SubID EthAssemblyAdapter::appendData(bytes const& _data)
+{
+ eth::AssemblyItem pushData = m_assembly.newData(_data);
+ SubID subID = m_nextDataCounter++;
+ m_dataHashBySubId[subID] = pushData.data();
+ return subID;
+}
+
+EthAssemblyAdapter::LabelID EthAssemblyAdapter::assemblyTagToIdentifier(eth::AssemblyItem const& _tag)
+{
+ u256 id = _tag.data();
+ solAssert(id <= std::numeric_limits<LabelID>::max(), "Tag id too large.");
+ return LabelID(id);
+}
+
+void CodeGenerator::assemble(
+ Block const& _parsedData,
+ AsmAnalysisInfo& _analysisInfo,
+ eth::Assembly& _assembly,
+ ExternalIdentifierAccess const& _identifierAccess,
+ bool _useNamedLabelsForFunctions
+)
+{
+ EthAssemblyAdapter assemblyAdapter(_assembly);
+ CodeTransform(
+ assemblyAdapter,
+ _analysisInfo,
+ false,
+ false,
+ _identifierAccess,
+ _useNamedLabelsForFunctions
+ )(_parsedData);
+}
diff --git a/libsolidity/codegen/AsmCodeGen.h b/libsolidity/codegen/AsmCodeGen.h
new file mode 100644
index 00000000..4c6d97f4
--- /dev/null
+++ b/libsolidity/codegen/AsmCodeGen.h
@@ -0,0 +1,93 @@
+/*
+ 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/>.
+*/
+/**
+ * Adaptor between the abstract assembly and eth assembly.
+ */
+
+#pragma once
+
+#include <libyul/AsmAnalysis.h>
+#include <libyul/backends/evm/AbstractAssembly.h>
+
+#include <liblangutil/SourceLocation.h>
+
+#include <functional>
+
+namespace yul
+{
+struct Block;
+}
+
+namespace dev
+{
+namespace eth
+{
+class Assembly;
+class AssemblyItem;
+}
+
+namespace solidity
+{
+
+class EthAssemblyAdapter: public yul::AbstractAssembly
+{
+public:
+ explicit EthAssemblyAdapter(eth::Assembly& _assembly);
+ void setSourceLocation(langutil::SourceLocation const& _location) override;
+ int stackHeight() const override;
+ void appendInstruction(solidity::Instruction _instruction) override;
+ void appendConstant(u256 const& _constant) override;
+ void appendLabel(LabelID _labelId) override;
+ void appendLabelReference(LabelID _labelId) override;
+ size_t newLabelId() override;
+ size_t namedLabel(std::string const& _name) override;
+ void appendLinkerSymbol(std::string const& _linkerSymbol) override;
+ void appendJump(int _stackDiffAfter) override;
+ void appendJumpTo(LabelID _labelId, int _stackDiffAfter) override;
+ void appendJumpToIf(LabelID _labelId) override;
+ void appendBeginsub(LabelID, int) override;
+ void appendJumpsub(LabelID, int, int) override;
+ void appendReturnsub(int, int) override;
+ void appendAssemblySize() override;
+ std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly() override;
+ void appendDataOffset(SubID _sub) override;
+ void appendDataSize(SubID _sub) override;
+ SubID appendData(dev::bytes const& _data) override;
+
+private:
+ static LabelID assemblyTagToIdentifier(eth::AssemblyItem const& _tag);
+
+ eth::Assembly& m_assembly;
+ std::map<SubID, dev::u256> m_dataHashBySubId;
+ size_t m_nextDataCounter = std::numeric_limits<size_t>::max() / 2;
+};
+
+class CodeGenerator
+{
+public:
+ /// Performs code generation and appends generated to _assembly.
+ static void assemble(
+ yul::Block const& _parsedData,
+ yul::AsmAnalysisInfo& _analysisInfo,
+ dev::eth::Assembly& _assembly,
+ yul::ExternalIdentifierAccess const& _identifierAccess = yul::ExternalIdentifierAccess(),
+ bool _useNamedLabelsForFunctions = false
+ );
+};
+
+}
+}
diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp
index 55f1d252..fe57cff6 100644
--- a/libsolidity/codegen/Compiler.cpp
+++ b/libsolidity/codegen/Compiler.cpp
@@ -34,13 +34,13 @@ void Compiler::compileContract(
bytes const& _metadata
)
{
- ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize);
+ ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize, m_optimizeRuns);
runtimeCompiler.compileContract(_contract, _contracts);
m_runtimeContext.appendAuxiliaryData(_metadata);
// This might modify m_runtimeContext because it can access runtime functions at
// creation time.
- ContractCompiler creationCompiler(&runtimeCompiler, m_context, m_optimize);
+ ContractCompiler creationCompiler(&runtimeCompiler, m_context, m_optimize, 1);
m_runtimeSub = creationCompiler.compileConstructor(_contract, _contracts);
m_context.optimise(m_optimize, m_optimizeRuns);
diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp
index 5a3a233c..dac09c2e 100644
--- a/libsolidity/codegen/CompilerContext.cpp
+++ b/libsolidity/codegen/CompilerContext.cpp
@@ -24,10 +24,10 @@
#include <libsolidity/codegen/CompilerUtils.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/codegen/Compiler.h>
+#include <libsolidity/codegen/AsmCodeGen.h>
#include <libsolidity/interface/Version.h>
#include <liblangutil/SourceReferenceFormatter.h>
#include <libyul/AsmParser.h>
-#include <libyul/AsmCodeGen.h>
#include <libyul/AsmAnalysis.h>
#include <libyul/AsmAnalysisInfo.h>
#include <libyul/YulString.h>
@@ -361,7 +361,7 @@ void CompilerContext::appendInlineAssembly(
ErrorList errors;
ErrorReporter errorReporter(errors);
auto scanner = make_shared<langutil::Scanner>(langutil::CharStream(_assembly, "--CODEGEN--"));
- auto parserResult = yul::Parser(errorReporter, yul::AsmFlavour::Strict).parse(scanner, false);
+ auto parserResult = yul::Parser(errorReporter, yul::Dialect::strictAssemblyForEVM()).parse(scanner, false);
#ifdef SOL_OUTPUT_ASM
cout << yul::AsmPrinter()(*parserResult) << endl;
#endif
@@ -373,7 +373,7 @@ void CompilerContext::appendInlineAssembly(
errorReporter,
m_evmVersion,
boost::none,
- yul::AsmFlavour::Strict,
+ yul::Dialect::strictAssemblyForEVM(),
identifierAccess.resolve
).analyze(*parserResult);
if (!parserResult || !errorReporter.errors().empty() || !analyzerResult)
@@ -386,8 +386,7 @@ void CompilerContext::appendInlineAssembly(
for (auto const& error: errorReporter.errors())
message += SourceReferenceFormatter::formatExceptionInformation(
*error,
- (error->type() == Error::Type::Warning) ? "Warning" : "Error",
- [&](string const&) -> Scanner const& { return *scanner; }
+ (error->type() == Error::Type::Warning) ? "Warning" : "Error"
);
message += "-------------------------------------------\n";
@@ -395,7 +394,7 @@ void CompilerContext::appendInlineAssembly(
}
solAssert(errorReporter.errors().empty(), "Failed to analyze inline assembly block.");
- yul::CodeGenerator::assemble(*parserResult, analysisInfo, *m_asm, identifierAccess, _system);
+ CodeGenerator::assemble(*parserResult, analysisInfo, *m_asm, identifierAccess, _system);
// Reset the source location to the one of the node (instead of the CODEGEN source location)
updateSourceLocation();
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp
index aabdbb79..79c53a1c 100644
--- a/libsolidity/codegen/ContractCompiler.cpp
+++ b/libsolidity/codegen/ContractCompiler.cpp
@@ -23,8 +23,8 @@
#include <libsolidity/codegen/ContractCompiler.h>
#include <libsolidity/codegen/ExpressionCompiler.h>
#include <libsolidity/codegen/CompilerUtils.h>
+#include <libsolidity/codegen/AsmCodeGen.h>
#include <libsolidity/ast/AST.h>
-#include <libyul/AsmCodeGen.h>
#include <liblangutil/ErrorReporter.h>
#include <libevmasm/Instruction.h>
@@ -268,6 +268,70 @@ void ContractCompiler::appendDelegatecallCheck()
// "We have not been called via DELEGATECALL".
}
+void ContractCompiler::appendInternalSelector(
+ map<FixedHash<4>, eth::AssemblyItem const> const& _entryPoints,
+ vector<FixedHash<4>> const& _ids,
+ eth::AssemblyItem const& _notFoundTag,
+ size_t _runs
+)
+{
+ // Code for selecting from n functions without split:
+ // n times: dup1, push4 <id_i>, eq, push2/3 <tag_i>, jumpi
+ // push2/3 <notfound> jump
+ // (called SELECT[n])
+ // Code for selecting from n functions with split:
+ // dup1, push4 <pivot>, gt, push2/3<tag_less>, jumpi
+ // SELECT[n/2]
+ // tag_less:
+ // SELECT[n/2]
+ //
+ // This means each split adds 16-18 bytes of additional code (note the additional jump out!)
+ // The average execution cost if we do not split at all are:
+ // (3 + 3 + 3 + 3 + 10) * n/2 = 24 * n/2 = 12 * n
+ // If we split once:
+ // (3 + 3 + 3 + 3 + 10) + 24 * n/4 = 24 * (n/4 + 1) = 6 * n + 24;
+ //
+ // We should split if
+ // _runs * 12 * n > _runs * (6 * n + 24) + 17 * createDataGas
+ // <=> _runs * 6 * (n - 4) > 17 * createDataGas
+ //
+ // Which also means that the execution itself is not profitable
+ // unless we have at least 5 functions.
+
+ // Start with some comparisons to avoid overflow, then do the actual comparison.
+ bool split = false;
+ if (_ids.size() <= 4)
+ split = false;
+ else if (_runs > (17 * eth::GasCosts::createDataGas) / 6)
+ split = true;
+ else
+ split = (_runs * 6 * (_ids.size() - 4) > 17 * eth::GasCosts::createDataGas);
+
+ if (split)
+ {
+ size_t pivotIndex = _ids.size() / 2;
+ FixedHash<4> pivot{_ids.at(pivotIndex)};
+ m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(pivot)) << Instruction::GT;
+ eth::AssemblyItem lessTag{m_context.appendConditionalJump()};
+ // Here, we have funid >= pivot
+ vector<FixedHash<4>> larger{_ids.begin() + pivotIndex, _ids.end()};
+ appendInternalSelector(_entryPoints, larger, _notFoundTag, _runs);
+ m_context << lessTag;
+ // Here, we have funid < pivot
+ vector<FixedHash<4>> smaller{_ids.begin(), _ids.begin() + pivotIndex};
+ appendInternalSelector(_entryPoints, smaller, _notFoundTag, _runs);
+ }
+ else
+ {
+ for (auto const& id: _ids)
+ {
+ m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(id)) << Instruction::EQ;
+ m_context.appendConditionalJumpTo(_entryPoints.at(id));
+ }
+ m_context.appendJumpTo(_notFoundTag);
+ }
+}
+
void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contract)
{
map<FixedHash<4>, FunctionTypePointer> interfaceFunctions = _contract.interfaceFunctions();
@@ -290,13 +354,14 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
CompilerUtils(m_context).loadFromMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8), true);
// stack now is: <can-call-non-view-functions>? <funhash>
+ vector<FixedHash<4>> sortedIDs;
for (auto const& it: interfaceFunctions)
{
callDataUnpackerEntryPoints.insert(std::make_pair(it.first, m_context.newTag()));
- m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(it.first)) << Instruction::EQ;
- m_context.appendConditionalJumpTo(callDataUnpackerEntryPoints.at(it.first));
+ sortedIDs.emplace_back(it.first);
}
- m_context.appendJumpTo(notFound);
+ std::sort(sortedIDs.begin(), sortedIDs.end());
+ appendInternalSelector(callDataUnpackerEntryPoints, sortedIDs, notFound, m_optimise_runs);
m_context << notFound;
if (fallback)
@@ -618,7 +683,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
}
};
solAssert(_inlineAssembly.annotation().analysisInfo, "");
- yul::CodeGenerator::assemble(
+ CodeGenerator::assemble(
_inlineAssembly.operations(),
*_inlineAssembly.annotation().analysisInfo,
m_context.nonConstAssembly(),
diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h
index 001aec7c..266ace0b 100644
--- a/libsolidity/codegen/ContractCompiler.h
+++ b/libsolidity/codegen/ContractCompiler.h
@@ -38,8 +38,9 @@ namespace solidity {
class ContractCompiler: private ASTConstVisitor
{
public:
- explicit ContractCompiler(ContractCompiler* _runtimeCompiler, CompilerContext& _context, bool _optimise):
+ explicit ContractCompiler(ContractCompiler* _runtimeCompiler, CompilerContext& _context, bool _optimise, size_t _optimise_runs = 200):
m_optimise(_optimise),
+ m_optimise_runs(_optimise_runs),
m_runtimeCompiler(_runtimeCompiler),
m_context(_context)
{
@@ -81,6 +82,14 @@ private:
/// This is done by inserting a specific push constant as the first instruction
/// whose data will be modified in memory at deploy time.
void appendDelegatecallCheck();
+ /// Appends the function selector. Is called recursively to create a binary search tree.
+ /// @a _runs the number of intended executions of the contract to tune the split point.
+ void appendInternalSelector(
+ std::map<FixedHash<4>, eth::AssemblyItem const> const& _entryPoints,
+ std::vector<FixedHash<4>> const& _ids,
+ eth::AssemblyItem const& _notFoundTag,
+ size_t _runs
+ );
void appendFunctionSelector(ContractDefinition const& _contract);
void appendCallValueCheck();
void appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary);
@@ -122,6 +131,7 @@ private:
void storeStackHeight(ASTNode const* _node);
bool const m_optimise;
+ size_t const m_optimise_runs = 200;
/// Pointer to the runtime compiler in case this is a creation compiler.
ContractCompiler* m_runtimeCompiler = nullptr;
CompilerContext& m_context;
diff --git a/libsolidity/formal/SMTChecker.cpp b/libsolidity/formal/SMTChecker.cpp
index ebb09f0a..17dc11ac 100644
--- a/libsolidity/formal/SMTChecker.cpp
+++ b/libsolidity/formal/SMTChecker.cpp
@@ -24,6 +24,8 @@
#include <liblangutil/ErrorReporter.h>
+#include <libdevcore/StringUtils.h>
+
#include <boost/range/adaptor/map.hpp>
#include <boost/algorithm/string/replace.hpp>
@@ -136,13 +138,24 @@ bool SMTChecker::visit(IfStatement const& _node)
return false;
}
+// Here we consider the execution of two branches:
+// Branch 1 assumes the loop condition to be true and executes the loop once,
+// after resetting touched variables.
+// Branch 2 assumes the loop condition to be false and skips the loop after
+// visiting the condition (it might contain side-effects, they need to be considered)
+// and does not erase knowledge.
+// If the loop is a do-while, condition side-effects are lost since the body,
+// executed once before the condition, might reassign variables.
+// Variables touched by the loop are merged with Branch 2.
bool SMTChecker::visit(WhileStatement const& _node)
{
+ auto indicesBeforeLoop = copyVariableIndices();
auto touchedVariables = m_variableUsage->touchedVariables(_node);
resetVariables(touchedVariables);
+ decltype(indicesBeforeLoop) indicesAfterLoop;
if (_node.isDoWhile())
{
- visitBranch(_node.body());
+ indicesAfterLoop = visitBranch(_node.body());
// TODO the assertions generated in the body should still be active in the condition
_node.condition().accept(*this);
if (isRootFunction())
@@ -154,19 +167,31 @@ bool SMTChecker::visit(WhileStatement const& _node)
if (isRootFunction())
checkBooleanNotConstant(_node.condition(), "While loop condition is always $VALUE.");
- visitBranch(_node.body(), expr(_node.condition()));
+ indicesAfterLoop = visitBranch(_node.body(), expr(_node.condition()));
}
- m_loopExecutionHappened = true;
- resetVariables(touchedVariables);
+ // We reset the execution to before the loop
+ // and visit the condition in case it's not a do-while.
+ // A do-while's body might have non-precise information
+ // in its first run about variables that are touched.
+ resetVariableIndices(indicesBeforeLoop);
+ if (!_node.isDoWhile())
+ _node.condition().accept(*this);
+
+ mergeVariables(touchedVariables, expr(_node.condition()), indicesAfterLoop, copyVariableIndices());
+
+ m_loopExecutionHappened = true;
return false;
}
+// Here we consider the execution of two branches similar to WhileStatement.
bool SMTChecker::visit(ForStatement const& _node)
{
if (_node.initializationExpression())
_node.initializationExpression()->accept(*this);
+ auto indicesBeforeLoop = copyVariableIndices();
+
// Do not reset the init expression part.
auto touchedVariables =
m_variableUsage->touchedVariables(_node.body());
@@ -193,13 +218,19 @@ bool SMTChecker::visit(ForStatement const& _node)
_node.body().accept(*this);
if (_node.loopExpression())
_node.loopExpression()->accept(*this);
-
m_interface->pop();
- m_loopExecutionHappened = true;
+ auto indicesAfterLoop = copyVariableIndices();
+ // We reset the execution to before the loop
+ // and visit the condition.
+ resetVariableIndices(indicesBeforeLoop);
+ if (_node.condition())
+ _node.condition()->accept(*this);
- resetVariables(touchedVariables);
+ auto forCondition = _node.condition() ? expr(*_node.condition()) : smt::Expression(true);
+ mergeVariables(touchedVariables, forCondition, indicesAfterLoop, copyVariableIndices());
+ m_loopExecutionHappened = true;
return false;
}
@@ -271,14 +302,14 @@ void SMTChecker::checkUnderOverflow(smt::Expression _value, IntegerType const& _
checkCondition(
_value < minValue(_type),
_location,
- "Underflow (resulting value less than " + formatNumber(_type.minValue()) + ")",
+ "Underflow (resulting value less than " + formatNumberReadable(_type.minValue()) + ")",
"<result>",
&_value
);
checkCondition(
_value > maxValue(_type),
_location,
- "Overflow (resulting value larger than " + formatNumber(_type.maxValue()) + ")",
+ "Overflow (resulting value larger than " + formatNumberReadable(_type.maxValue()) + ")",
"<result>",
&_value
);
@@ -820,6 +851,7 @@ void SMTChecker::checkCondition(
loopComment =
"\nNote that some information is erased after the execution of loops.\n"
"You can re-introduce information using require().";
+
switch (result)
{
case smt::CheckResult::SATISFIABLE:
@@ -838,19 +870,19 @@ void SMTChecker::checkCondition(
for (auto const& eval: sortedModel)
modelMessage << " " << eval.first << " = " << eval.second << "\n";
- m_errorReporter.warning(_location, message.str() + loopComment, SecondarySourceLocation().append(modelMessage.str(), SourceLocation()));
+ m_errorReporter.warning(_location, message.str(), SecondarySourceLocation().append(modelMessage.str(), SourceLocation()).append(loopComment, SourceLocation()));
}
else
{
message << ".";
- m_errorReporter.warning(_location, message.str() + loopComment);
+ m_errorReporter.warning(_location, message.str(), SecondarySourceLocation().append(loopComment, SourceLocation()));
}
break;
}
case smt::CheckResult::UNSATISFIABLE:
break;
case smt::CheckResult::UNKNOWN:
- m_errorReporter.warning(_location, _description + " might happen here." + loopComment);
+ m_errorReporter.warning(_location, _description + " might happen here.", SecondarySourceLocation().append(loopComment, SourceLocation()));
break;
case smt::CheckResult::CONFLICTING:
m_errorReporter.warning(_location, "At least two SMT solvers provided conflicting answers. Results might not be sound.");
@@ -933,7 +965,7 @@ SMTChecker::checkSatisfiableAndGenerateModel(vector<smt::Expression> const& _exp
try
{
// Parse and re-format nicely
- value = formatNumber(bigint(value));
+ value = formatNumberReadable(bigint(value));
}
catch (...) { }
}
diff --git a/libsolidity/formal/SymbolicVariables.cpp b/libsolidity/formal/SymbolicVariables.cpp
index efaeb97a..f7d2a119 100644
--- a/libsolidity/formal/SymbolicVariables.cpp
+++ b/libsolidity/formal/SymbolicVariables.cpp
@@ -37,16 +37,32 @@ SymbolicVariable::SymbolicVariable(
{
}
+smt::Expression SymbolicVariable::currentValue() const
+{
+ return valueAtIndex(m_ssa->index());
+}
+
string SymbolicVariable::currentName() const
{
return uniqueSymbol(m_ssa->index());
}
+smt::Expression SymbolicVariable::valueAtIndex(int _index) const
+{
+ return m_interface.newVariable(uniqueSymbol(_index), smtSort(*m_type));
+}
+
string SymbolicVariable::uniqueSymbol(unsigned _index) const
{
return m_uniqueName + "_" + to_string(_index);
}
+smt::Expression SymbolicVariable::increaseIndex()
+{
+ ++(*m_ssa);
+ return currentValue();
+}
+
SymbolicBoolVariable::SymbolicBoolVariable(
TypePointer _type,
string const& _uniqueName,
@@ -57,11 +73,6 @@ SymbolicBoolVariable::SymbolicBoolVariable(
solAssert(m_type->category() == Type::Category::Bool, "");
}
-smt::Expression SymbolicBoolVariable::valueAtIndex(int _index) const
-{
- return m_interface.newVariable(uniqueSymbol(_index), make_shared<smt::Sort>(smt::Kind::Bool));
-}
-
SymbolicIntVariable::SymbolicIntVariable(
TypePointer _type,
string const& _uniqueName,
@@ -72,11 +83,6 @@ SymbolicIntVariable::SymbolicIntVariable(
solAssert(isNumber(m_type->category()), "");
}
-smt::Expression SymbolicIntVariable::valueAtIndex(int _index) const
-{
- return m_interface.newVariable(uniqueSymbol(_index), make_shared<smt::Sort>(smt::Kind::Int));
-}
-
SymbolicAddressVariable::SymbolicAddressVariable(
string const& _uniqueName,
smt::SolverInterface& _interface
diff --git a/libsolidity/formal/SymbolicVariables.h b/libsolidity/formal/SymbolicVariables.h
index fcf32760..ef40944c 100644
--- a/libsolidity/formal/SymbolicVariables.h
+++ b/libsolidity/formal/SymbolicVariables.h
@@ -46,20 +46,10 @@ public:
virtual ~SymbolicVariable() = default;
- smt::Expression currentValue() const
- {
- return valueAtIndex(m_ssa->index());
- }
-
+ smt::Expression currentValue() const;
std::string currentName() const;
-
- virtual smt::Expression valueAtIndex(int _index) const = 0;
-
- smt::Expression increaseIndex()
- {
- ++(*m_ssa);
- return currentValue();
- }
+ virtual smt::Expression valueAtIndex(int _index) const;
+ smt::Expression increaseIndex();
unsigned index() const { return m_ssa->index(); }
unsigned& index() { return m_ssa->index(); }
@@ -86,9 +76,6 @@ public:
std::string const& _uniqueName,
smt::SolverInterface& _interface
);
-
-protected:
- smt::Expression valueAtIndex(int _index) const;
};
/**
@@ -102,9 +89,6 @@ public:
std::string const& _uniqueName,
smt::SolverInterface& _interface
);
-
-protected:
- smt::Expression valueAtIndex(int _index) const;
};
/**
diff --git a/libsolidity/interface/AssemblyStack.cpp b/libsolidity/interface/AssemblyStack.cpp
index f5eb7e41..fbfb3472 100644
--- a/libsolidity/interface/AssemblyStack.cpp
+++ b/libsolidity/interface/AssemblyStack.cpp
@@ -22,12 +22,14 @@
#include <libsolidity/interface/AssemblyStack.h>
+#include <libsolidity/codegen/AsmCodeGen.h>
+
#include <liblangutil/Scanner.h>
#include <libyul/AsmPrinter.h>
#include <libyul/AsmParser.h>
#include <libyul/AsmAnalysis.h>
#include <libyul/AsmAnalysisInfo.h>
-#include <libyul/AsmCodeGen.h>
+#include <libyul/backends/evm/EVMObjectCompiler.h>
#include <libyul/backends/evm/EVMCodeTransform.h>
#include <libyul/backends/evm/EVMAssembly.h>
#include <libyul/ObjectParser.h>
@@ -43,19 +45,19 @@ using namespace dev::solidity;
namespace
{
-yul::AsmFlavour languageToAsmFlavour(AssemblyStack::Language _language)
+yul::Dialect languageToDialect(AssemblyStack::Language _language)
{
switch (_language)
{
case AssemblyStack::Language::Assembly:
- return yul::AsmFlavour::Loose;
+ return yul::Dialect::looseAssemblyForEVM();
case AssemblyStack::Language::StrictAssembly:
- return yul::AsmFlavour::Strict;
+ return yul::Dialect::strictAssemblyForEVMObjects();
case AssemblyStack::Language::Yul:
- return yul::AsmFlavour::Yul;
+ return yul::Dialect::yul();
}
solAssert(false, "");
- return yul::AsmFlavour::Yul;
+ return yul::Dialect::yul();
}
}
@@ -72,7 +74,7 @@ bool AssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string
m_errors.clear();
m_analysisSuccessful = false;
m_scanner = make_shared<Scanner>(CharStream(_source, _sourceName));
- m_parserResult = yul::ObjectParser(m_errorReporter, languageToAsmFlavour(m_language)).parse(m_scanner, false);
+ m_parserResult = yul::ObjectParser(m_errorReporter, languageToDialect(m_language)).parse(m_scanner, false);
if (!m_errorReporter.errors().empty())
return false;
solAssert(m_parserResult, "");
@@ -84,20 +86,42 @@ bool AssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string
void AssemblyStack::optimize()
{
solAssert(m_language != Language::Assembly, "Optimization requested for loose assembly.");
- yul::OptimiserSuite::run(*m_parserResult->code, *m_parserResult->analysisInfo);
+ solAssert(m_analysisSuccessful, "Analysis was not successful.");
+ m_analysisSuccessful = false;
+ optimize(*m_parserResult);
solAssert(analyzeParsed(), "Invalid source code after optimization.");
}
bool AssemblyStack::analyzeParsed()
{
solAssert(m_parserResult, "");
- solAssert(m_parserResult->code, "");
- m_parserResult->analysisInfo = make_shared<yul::AsmAnalysisInfo>();
- yul::AsmAnalyzer analyzer(*m_parserResult->analysisInfo, m_errorReporter, m_evmVersion, boost::none, languageToAsmFlavour(m_language));
- m_analysisSuccessful = analyzer.analyze(*m_parserResult->code);
+ m_analysisSuccessful = analyzeParsed(*m_parserResult);
return m_analysisSuccessful;
}
+bool AssemblyStack::analyzeParsed(yul::Object& _object)
+{
+ solAssert(_object.code, "");
+ _object.analysisInfo = make_shared<yul::AsmAnalysisInfo>();
+ yul::AsmAnalyzer analyzer(*_object.analysisInfo, m_errorReporter, m_evmVersion, boost::none, languageToDialect(m_language));
+ bool success = analyzer.analyze(*_object.code);
+ for (auto& subNode: _object.subObjects)
+ if (auto subObject = dynamic_cast<yul::Object*>(subNode.get()))
+ if (!analyzeParsed(*subObject))
+ success = false;
+ return success;
+}
+
+void AssemblyStack::optimize(yul::Object& _object)
+{
+ solAssert(_object.code, "");
+ solAssert(_object.analysisInfo, "");
+ for (auto& subNode: _object.subObjects)
+ if (auto subObject = dynamic_cast<yul::Object*>(subNode.get()))
+ optimize(*subObject);
+ yul::OptimiserSuite::run(*_object.code, *_object.analysisInfo);
+}
+
MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
{
solAssert(m_analysisSuccessful, "");
@@ -111,7 +135,8 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
{
MachineAssemblyObject object;
eth::Assembly assembly;
- yul::CodeGenerator::assemble(*m_parserResult->code, *m_parserResult->analysisInfo, assembly);
+ EthAssemblyAdapter adapter(assembly);
+ yul::EVMObjectCompiler::compile(*m_parserResult, adapter, m_language == Language::Yul, false);
object.bytecode = make_shared<eth::LinkerObject>(assembly.assemble());
object.assembly = assembly.assemblyString();
return object;
@@ -120,7 +145,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
{
MachineAssemblyObject object;
yul::EVMAssembly assembly(true);
- yul::CodeTransform(assembly, *m_parserResult->analysisInfo, m_language == Language::Yul, true)(*m_parserResult->code);
+ yul::EVMObjectCompiler::compile(*m_parserResult, assembly, m_language == Language::Yul, true);
object.bytecode = make_shared<eth::LinkerObject>(assembly.finalize());
/// TODO: fill out text representation
return object;
diff --git a/libsolidity/interface/AssemblyStack.h b/libsolidity/interface/AssemblyStack.h
index 0d04ffec..485ec1e7 100644
--- a/libsolidity/interface/AssemblyStack.h
+++ b/libsolidity/interface/AssemblyStack.h
@@ -83,6 +83,9 @@ public:
private:
bool analyzeParsed();
+ bool analyzeParsed(yul::Object& _object);
+
+ void optimize(yul::Object& _object);
Language m_language = Language::Assembly;
EVMVersion m_evmVersion;
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index 610caea1..1e6e2330 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -552,7 +552,7 @@ Json::Value CompilerStack::methodIdentifiers(string const& _contractName) const
{
Json::Value methodIdentifiers(Json::objectValue);
for (auto const& it: contractDefinition(_contractName).interfaceFunctions())
- methodIdentifiers[it.second->externalSignature()] = toHex(it.first.ref());
+ methodIdentifiers[it.second->externalSignature()] = it.first.hex();
return methodIdentifiers;
}
diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp
index 0eef50d2..862b6633 100644
--- a/libsolidity/interface/StandardCompiler.cpp
+++ b/libsolidity/interface/StandardCompiler.cpp
@@ -69,12 +69,11 @@ Json::Value formatErrorWithException(
bool const& _warning,
string const& _type,
string const& _component,
- string const& _message,
- function<Scanner const&(string const&)> const& _scannerFromSourceName
+ string const& _message
)
{
string message;
- string formattedMessage = SourceReferenceFormatter::formatExceptionInformation(_exception, _type, _scannerFromSourceName);
+ string formattedMessage = SourceReferenceFormatter::formatExceptionInformation(_exception, _type);
// NOTE: the below is partially a copy from SourceReferenceFormatter
SourceLocation const* location = boost::get_error_info<errinfo_sourceLocation>(_exception);
@@ -433,8 +432,6 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
Json::Value outputSelection = settings.get("outputSelection", Json::Value());
m_compilerStack.setRequestedContractNames(requestedContractNames(outputSelection));
- auto scannerFromSourceName = [&](string const& _sourceName) -> Scanner const& { return m_compilerStack.scanner(_sourceName); };
-
try
{
m_compilerStack.compile();
@@ -448,8 +445,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
err.type() == Error::Type::Warning,
err.typeName(),
"general",
- "",
- scannerFromSourceName
+ ""
));
}
}
@@ -461,8 +457,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
false,
_error.typeName(),
"general",
- "Uncaught error: ",
- scannerFromSourceName
+ "Uncaught error: "
));
}
/// This should not be leaked from compile().
@@ -482,8 +477,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
false,
"CompilerError",
"general",
- "Compiler error (" + _exception.lineInfo() + ")",
- scannerFromSourceName
+ "Compiler error (" + _exception.lineInfo() + ")"
));
}
catch (InternalCompilerError const& _exception)
@@ -493,8 +487,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
false,
"InternalCompilerError",
"general",
- "Internal compiler error (" + _exception.lineInfo() + ")",
- scannerFromSourceName
+ "Internal compiler error (" + _exception.lineInfo() + ")"
));
}
catch (UnimplementedFeatureError const& _exception)
@@ -504,8 +497,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
false,
"UnimplementedFeatureError",
"general",
- "Unimplemented feature (" + _exception.lineInfo() + ")",
- scannerFromSourceName
+ "Unimplemented feature (" + _exception.lineInfo() + ")"
));
}
catch (Exception const& _exception)