aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity')
-rw-r--r--libsolidity/analysis/NameAndTypeResolver.cpp22
-rw-r--r--libsolidity/analysis/NameAndTypeResolver.h3
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp16
-rw-r--r--libsolidity/analysis/ReferencesResolver.h7
-rw-r--r--libsolidity/analysis/TypeChecker.cpp3
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp19
-rw-r--r--libsolidity/ast/ASTJsonConverter.h1
-rw-r--r--libsolidity/codegen/ArrayUtils.cpp4
-rw-r--r--libsolidity/codegen/CompilerContext.cpp23
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp2
-rw-r--r--libsolidity/codegen/CompilerUtils.h2
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp23
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp8
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.cpp106
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.h21
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.cpp52
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.h14
-rw-r--r--libsolidity/inlineasm/AsmParser.cpp40
-rw-r--r--libsolidity/inlineasm/AsmParser.h3
-rw-r--r--libsolidity/inlineasm/AsmScope.cpp10
-rw-r--r--libsolidity/inlineasm/AsmScope.h21
-rw-r--r--libsolidity/inlineasm/AsmStack.cpp96
-rw-r--r--libsolidity/inlineasm/AsmStack.h79
-rw-r--r--libsolidity/interface/AssemblyStack.cpp46
-rw-r--r--libsolidity/interface/AssemblyStack.h16
-rw-r--r--libsolidity/interface/CompilerStack.cpp19
-rw-r--r--libsolidity/interface/CompilerStack.h20
27 files changed, 329 insertions, 347 deletions
diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp
index 2742dcf2..aac90311 100644
--- a/libsolidity/analysis/NameAndTypeResolver.cpp
+++ b/libsolidity/analysis/NameAndTypeResolver.cpp
@@ -26,6 +26,8 @@
#include <libsolidity/analysis/TypeChecker.h>
#include <libsolidity/interface/ErrorReporter.h>
+#include <boost/algorithm/string.hpp>
+
using namespace std;
namespace dev
@@ -232,6 +234,26 @@ vector<Declaration const*> NameAndTypeResolver::cleanedDeclarations(
return uniqueFunctions;
}
+void NameAndTypeResolver::warnVariablesNamedLikeInstructions()
+{
+ for (auto const& instruction: c_instructions)
+ {
+ string const instructionName{boost::algorithm::to_lower_copy(instruction.first)};
+ auto declarations = nameFromCurrentScope(instructionName);
+ for (Declaration const* const declaration: declarations)
+ {
+ solAssert(!!declaration, "");
+ if (dynamic_cast<MagicVariableDeclaration const* const>(declaration))
+ // Don't warn the user for what the user did not.
+ continue;
+ m_errorReporter.warning(
+ declaration->location(),
+ "Variable is shadowed in inline assembly by an instruction of the same name"
+ );
+ }
+ }
+}
+
bool NameAndTypeResolver::resolveNamesAndTypesInternal(ASTNode& _node, bool _resolveInsideCode)
{
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(&_node))
diff --git a/libsolidity/analysis/NameAndTypeResolver.h b/libsolidity/analysis/NameAndTypeResolver.h
index 0441867d..84628778 100644
--- a/libsolidity/analysis/NameAndTypeResolver.h
+++ b/libsolidity/analysis/NameAndTypeResolver.h
@@ -90,6 +90,9 @@ public:
std::vector<Declaration const*> const& _declarations
);
+ /// Generate and store warnings about variables that are named like instructions.
+ void warnVariablesNamedLikeInstructions();
+
private:
/// Internal version of @a resolveNamesAndTypes (called from there) throws exceptions on fatal errors.
bool resolveNamesAndTypesInternal(ASTNode& _node, bool _resolveInsideCode = true);
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index b70b0f0e..2a5f27df 100644
--- a/libsolidity/analysis/ReferencesResolver.cpp
+++ b/libsolidity/analysis/ReferencesResolver.cpp
@@ -162,6 +162,8 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
{
+ m_resolver.warnVariablesNamedLikeInstructions();
+
// Errors created in this stage are completely ignored because we do not yet know
// the type and size of external identifiers, which would result in false errors.
// The only purpose of this step is to fill the inline assembly annotation with
@@ -169,7 +171,7 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
ErrorList errors;
ErrorReporter errorsIgnored(errors);
julia::ExternalIdentifierAccess::Resolver resolver =
- [&](assembly::Identifier const& _identifier, julia::IdentifierContext) {
+ [&](assembly::Identifier const& _identifier, julia::IdentifierContext, bool _crossesFunctionBoundary) {
auto declarations = m_resolver.nameFromCurrentScope(_identifier.name);
bool isSlot = boost::algorithm::ends_with(_identifier.name, "_slot");
bool isOffset = boost::algorithm::ends_with(_identifier.name, "_offset");
@@ -188,6 +190,12 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
}
if (declarations.size() != 1)
return size_t(-1);
+ if (auto var = dynamic_cast<VariableDeclaration const*>(declarations.front()))
+ if (var->isLocalVariable() && _crossesFunctionBoundary)
+ {
+ declarationError(_identifier.location, "Cannot access local Solidity variables from inside an inline assembly function.");
+ return size_t(-1);
+ }
_inlineAssembly.annotation().externalReferences[&_identifier].isSlot = isSlot;
_inlineAssembly.annotation().externalReferences[&_identifier].isOffset = isOffset;
_inlineAssembly.annotation().externalReferences[&_identifier].declaration = declarations.front();
@@ -315,6 +323,12 @@ void ReferencesResolver::fatalTypeError(SourceLocation const& _location, string
m_errorReporter.fatalTypeError(_location, _description);
}
+void ReferencesResolver::declarationError(SourceLocation const& _location, string const& _description)
+{
+ m_errorOccurred = true;
+ m_errorReporter.declarationError(_location, _description);
+}
+
void ReferencesResolver::fatalDeclarationError(SourceLocation const& _location, string const& _description)
{
m_errorOccurred = true;
diff --git a/libsolidity/analysis/ReferencesResolver.h b/libsolidity/analysis/ReferencesResolver.h
index bbde19f9..fef2e73f 100644
--- a/libsolidity/analysis/ReferencesResolver.h
+++ b/libsolidity/analysis/ReferencesResolver.h
@@ -75,10 +75,13 @@ private:
/// Adds a new error to the list of errors.
void typeError(SourceLocation const& _location, std::string const& _description);
- /// Adds a new error to the list of errors and throws to abort type checking.
+ /// Adds a new error to the list of errors and throws to abort reference resolving.
void fatalTypeError(SourceLocation const& _location, std::string const& _description);
- /// Adds a new error to the list of errors and throws to abort type checking.
+ /// Adds a new error to the list of errors.
+ void declarationError(SourceLocation const& _location, std::string const& _description);
+
+ /// Adds a new error to the list of errors and throws to abort reference resolving.
void fatalDeclarationError(SourceLocation const& _location, std::string const& _description);
ErrorReporter& m_errorReporter;
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 0fb0d212..b1911ef0 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -632,7 +632,8 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
// We run the resolve step again regardless.
julia::ExternalIdentifierAccess::Resolver identifierAccess = [&](
assembly::Identifier const& _identifier,
- julia::IdentifierContext _context
+ julia::IdentifierContext _context,
+ bool
)
{
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp
index d2f27519..4ad1f962 100644
--- a/libsolidity/ast/ASTJsonConverter.cpp
+++ b/libsolidity/ast/ASTJsonConverter.cpp
@@ -705,13 +705,12 @@ bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node)
bool ASTJsonConverter::visit(Literal const& _node)
{
- char const* tokenString = Token::toString(_node.token());
Json::Value value{_node.value()};
if (!dev::validateUTF8(_node.value()))
value = Json::nullValue;
Token::Value subdenomination = Token::Value(_node.subDenomination());
std::vector<pair<string, Json::Value>> attributes = {
- make_pair("token", tokenString ? tokenString : Json::Value()),
+ make_pair(m_legacy ? "token" : "kind", literalTokenKind(_node.token())),
make_pair("value", value),
make_pair(m_legacy ? "hexvalue" : "hexValue", toHex(_node.value())),
make_pair(
@@ -794,6 +793,22 @@ string ASTJsonConverter::functionCallKind(FunctionCallKind _kind)
}
}
+string ASTJsonConverter::literalTokenKind(Token::Value _token)
+{
+ switch (_token)
+ {
+ case dev::solidity::Token::Number:
+ return "number";
+ case dev::solidity::Token::StringLiteral:
+ return "string";
+ case dev::solidity::Token::TrueLiteral:
+ case dev::solidity::Token::FalseLiteral:
+ return "bool";
+ default:
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of literal token."));
+ }
+}
+
string ASTJsonConverter::type(Expression const& _expression)
{
return _expression.annotation().type ? _expression.annotation().type->toString() : "Unknown";
diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h
index 5ee40536..c2de5c48 100644
--- a/libsolidity/ast/ASTJsonConverter.h
+++ b/libsolidity/ast/ASTJsonConverter.h
@@ -133,6 +133,7 @@ private:
std::string location(VariableDeclaration::Location _location);
std::string contractKind(ContractDefinition::ContractKind _kind);
std::string functionCallKind(FunctionCallKind _kind);
+ std::string literalTokenKind(Token::Value _token);
std::string type(Expression const& _expression);
std::string type(VariableDeclaration const& _varDecl);
int nodeId(ASTNode const& _node)
diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp
index bdd29abd..6a641b02 100644
--- a/libsolidity/codegen/ArrayUtils.cpp
+++ b/libsolidity/codegen/ArrayUtils.cpp
@@ -449,7 +449,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
m_context << Instruction::DUP3 << Instruction::ADD << Instruction::SWAP2;
if (_sourceType.isDynamicallySized())
{
- // actual array data is stored at SHA3(storage_offset)
+ // actual array data is stored at KECCAK256(storage_offset)
m_context << Instruction::SWAP1;
utils.computeHashStatic();
m_context << Instruction::SWAP1;
@@ -731,7 +731,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
_context << Instruction::POP;
}
- // Change of length for a regular array (i.e. length at location, data at sha3(location)).
+ // Change of length for a regular array (i.e. length at location, data at KECCAK256(location)).
// stack: ref new_length old_length
// store new length
_context << Instruction::DUP2;
diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp
index 404a3af6..d98efcad 100644
--- a/libsolidity/codegen/CompilerContext.cpp
+++ b/libsolidity/codegen/CompilerContext.cpp
@@ -25,8 +25,11 @@
#include <libsolidity/ast/AST.h>
#include <libsolidity/codegen/Compiler.h>
#include <libsolidity/interface/Version.h>
-#include <libsolidity/inlineasm/AsmData.h>
-#include <libsolidity/inlineasm/AsmStack.h>
+#include <libsolidity/interface/ErrorReporter.h>
+#include <libsolidity/inlineasm/AsmParser.h>
+#include <libsolidity/inlineasm/AsmCodeGen.h>
+#include <libsolidity/inlineasm/AsmAnalysis.h>
+#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
#include <boost/algorithm/string/replace.hpp>
@@ -269,7 +272,8 @@ void CompilerContext::appendInlineAssembly(
julia::ExternalIdentifierAccess identifierAccess;
identifierAccess.resolve = [&](
assembly::Identifier const& _identifier,
- julia::IdentifierContext
+ julia::IdentifierContext,
+ bool
)
{
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name);
@@ -301,7 +305,18 @@ void CompilerContext::appendInlineAssembly(
}
};
- solAssert(assembly::InlineAssemblyStack().parseAndAssemble(*assembly, *m_asm, identifierAccess), "Failed to assemble inline assembly block.");
+ ErrorList errors;
+ ErrorReporter errorReporter(errors);
+ auto scanner = make_shared<Scanner>(CharStream(*assembly), "--CODEGEN--");
+ auto parserResult = assembly::Parser(errorReporter).parse(scanner);
+ solAssert(parserResult, "Failed to parse inline assembly block.");
+ solAssert(errorReporter.errors().empty(), "Failed to parse inline assembly block.");
+
+ assembly::AsmAnalysisInfo analysisInfo;
+ assembly::AsmAnalyzer analyzer(analysisInfo, errorReporter, false, identifierAccess.resolve);
+ solAssert(analyzer.analyze(*parserResult), "Failed to analyze inline assembly block.");
+ solAssert(errorReporter.errors().empty(), "Failed to analyze inline assembly block.");
+ assembly::CodeGenerator::assemble(*parserResult, analysisInfo, *m_asm, identifierAccess);
}
FunctionDefinition const& CompilerContext::resolveVirtualFunction(
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index 4ae9a09a..3baaaddf 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -934,7 +934,7 @@ unsigned CompilerUtils::sizeOnStack(vector<shared_ptr<Type const>> const& _varia
void CompilerUtils::computeHashStatic()
{
storeInMemory(0);
- m_context << u256(32) << u256(0) << Instruction::SHA3;
+ m_context << u256(32) << u256(0) << Instruction::KECCAK256;
}
void CompilerUtils::storeStringData(bytesConstRef _data)
diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h
index 4140ce8b..a88951bc 100644
--- a/libsolidity/codegen/CompilerUtils.h
+++ b/libsolidity/codegen/CompilerUtils.h
@@ -166,7 +166,7 @@ public:
static unsigned sizeOnStack(std::vector<T> const& _variables);
static unsigned sizeOnStack(std::vector<std::shared_ptr<Type const>> const& _variableTypes);
- /// Appends code that computes tha SHA3 hash of the topmost stack element of 32 byte type.
+ /// Appends code that computes tha Keccak-256 hash of the topmost stack element of 32 byte type.
void computeHashStatic();
/// Bytes we need to the start of call data.
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp
index 1fc06333..dc090634 100644
--- a/libsolidity/codegen/ContractCompiler.cpp
+++ b/libsolidity/codegen/ContractCompiler.cpp
@@ -21,15 +21,20 @@
*/
#include <libsolidity/codegen/ContractCompiler.h>
-#include <algorithm>
-#include <boost/range/adaptor/reversed.hpp>
-#include <libevmasm/Instruction.h>
-#include <libevmasm/Assembly.h>
-#include <libevmasm/GasMeter.h>
#include <libsolidity/inlineasm/AsmCodeGen.h>
#include <libsolidity/ast/AST.h>
+#include <libsolidity/interface/ErrorReporter.h>
#include <libsolidity/codegen/ExpressionCompiler.h>
#include <libsolidity/codegen/CompilerUtils.h>
+
+#include <libevmasm/Instruction.h>
+#include <libevmasm/Assembly.h>
+#include <libevmasm/GasMeter.h>
+
+#include <boost/range/adaptor/reversed.hpp>
+
+#include <algorithm>
+
using namespace std;
using namespace dev;
using namespace dev::solidity;
@@ -519,12 +524,9 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
{
- ErrorList errors;
- ErrorReporter errorReporter(errors);
- assembly::CodeGenerator codeGen(errorReporter);
unsigned startStackHeight = m_context.stackHeight();
julia::ExternalIdentifierAccess identifierAccess;
- identifierAccess.resolve = [&](assembly::Identifier const& _identifier, julia::IdentifierContext)
+ identifierAccess.resolve = [&](assembly::Identifier const& _identifier, julia::IdentifierContext, bool)
{
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
if (ref == _inlineAssembly.annotation().externalReferences.end())
@@ -643,13 +645,12 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
}
};
solAssert(_inlineAssembly.annotation().analysisInfo, "");
- codeGen.assemble(
+ assembly::CodeGenerator::assemble(
_inlineAssembly.operations(),
*_inlineAssembly.annotation().analysisInfo,
m_context.nonConstAssembly(),
identifierAccess
);
- solAssert(Error::containsOnlyWarnings(errorReporter.errors()), "Code generation for inline assembly with errors requested.");
m_context.setStackOffset(startStackHeight);
return false;
}
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 0aa82ea8..25154bc0 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -110,7 +110,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
// move key to memory.
utils().copyToStackTop(paramTypes.size() - i, 1);
utils().storeInMemory(0);
- m_context << u256(64) << u256(0) << Instruction::SHA3;
+ m_context << u256(64) << u256(0) << Instruction::KECCAK256;
// push offset
m_context << u256(0);
returnType = mappingType->valueType();
@@ -674,7 +674,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
utils().fetchFreeMemoryPointer();
utils().encodeToMemory(argumentTypes, TypePointers(), function.padArguments(), true);
utils().toSizeAfterFreeMemoryPointer();
- m_context << Instruction::SHA3;
+ m_context << Instruction::KECCAK256;
break;
}
case FunctionType::Kind::Log0:
@@ -721,7 +721,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
true
);
utils().toSizeAfterFreeMemoryPointer();
- m_context << Instruction::SHA3;
+ m_context << Instruction::KECCAK256;
}
else
utils().convertType(
@@ -1214,7 +1214,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
utils().storeInMemoryDynamic(IntegerType(256));
m_context << u256(0);
}
- m_context << Instruction::SHA3;
+ m_context << Instruction::KECCAK256;
m_context << u256(0);
setLValueToStorageItem(_indexAccess);
}
diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp
index 22e43127..7bcbde91 100644
--- a/libsolidity/inlineasm/AsmAnalysis.cpp
+++ b/libsolidity/inlineasm/AsmAnalysis.cpp
@@ -25,7 +25,7 @@
#include <libsolidity/inlineasm/AsmScope.h>
#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
-#include <libsolidity/interface/Exceptions.h>
+#include <libsolidity/interface/ErrorReporter.h>
#include <libsolidity/interface/Utils.h>
#include <boost/range/adaptor/reversed.hpp>
@@ -65,6 +65,7 @@ bool AsmAnalyzer::operator()(assembly::Instruction const& _instruction)
auto const& info = instructionInfo(_instruction.instruction);
m_stackHeight += info.ret - info.args;
m_info.stackHeightInfo[&_instruction] = m_stackHeight;
+ warnOnFutureInstruction(_instruction.instruction, _instruction.location);
return true;
}
@@ -91,7 +92,7 @@ bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier)
if (m_currentScope->lookup(_identifier.name, Scope::Visitor(
[&](Scope::Variable const& _var)
{
- if (!_var.active)
+ if (!m_activeVariables.count(&_var))
{
m_errorReporter.declarationError(
_identifier.location,
@@ -120,7 +121,10 @@ bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier)
{
size_t stackSize(-1);
if (m_resolver)
- stackSize = m_resolver(_identifier, julia::IdentifierContext::RValue);
+ {
+ bool insideFunction = m_currentScope->insideFunction();
+ stackSize = m_resolver(_identifier, julia::IdentifierContext::RValue, insideFunction);
+ }
if (stackSize == size_t(-1))
{
// Only add an error message if the callback did not do it.
@@ -139,18 +143,14 @@ bool AsmAnalyzer::operator()(FunctionalInstruction const& _instr)
solAssert(!m_julia, "");
bool success = true;
for (auto const& arg: _instr.arguments | boost::adaptors::reversed)
- {
- int const stackHeight = m_stackHeight;
- if (!boost::apply_visitor(*this, arg))
+ if (!expectExpression(arg))
success = false;
- if (!expectDeposit(1, stackHeight, locationOf(arg)))
- success = false;
- }
// Parser already checks that the number of arguments is correct.
solAssert(instructionInfo(_instr.instruction.instruction).args == int(_instr.arguments.size()), "");
if (!(*this)(_instr.instruction))
success = false;
m_info.stackHeightInfo[&_instr] = m_stackHeight;
+ warnOnFutureInstruction(_instr.instruction.instruction, _instr.location);
return success;
}
@@ -187,7 +187,7 @@ bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl)
for (auto const& variable: _varDecl.variables)
{
expectValidType(variable.type, variable.location);
- boost::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name)).active = true;
+ m_activeVariables.insert(&boost::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name)));
}
m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
return success;
@@ -201,7 +201,7 @@ bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef)
for (auto const& var: _funDef.arguments + _funDef.returns)
{
expectValidType(var.type, var.location);
- boost::get<Scope::Variable>(varScope.identifiers.at(var.name)).active = true;
+ m_activeVariables.insert(&boost::get<Scope::Variable>(varScope.identifiers.at(var.name)));
}
int const stackHeight = m_stackHeight;
@@ -260,13 +260,8 @@ bool AsmAnalyzer::operator()(assembly::FunctionCall const& _funCall)
}
}
for (auto const& arg: _funCall.arguments | boost::adaptors::reversed)
- {
- int const stackHeight = m_stackHeight;
- if (!boost::apply_visitor(*this, arg))
+ if (!expectExpression(arg))
success = false;
- if (!expectDeposit(1, stackHeight, locationOf(arg)))
- success = false;
- }
m_stackHeight += int(returns) - int(arguments);
m_info.stackHeightInfo[&_funCall] = m_stackHeight;
return success;
@@ -276,10 +271,8 @@ bool AsmAnalyzer::operator()(Switch const& _switch)
{
bool success = true;
- int const initialStackHeight = m_stackHeight;
- if (!boost::apply_visitor(*this, *_switch.expression))
+ if (!expectExpression(*_switch.expression))
success = false;
- expectDeposit(1, initialStackHeight, locationOf(*_switch.expression));
set<tuple<LiteralKind, string>> cases;
for (auto const& _case: _switch.cases)
@@ -287,6 +280,8 @@ bool AsmAnalyzer::operator()(Switch const& _switch)
if (_case.value)
{
int const initialStackHeight = m_stackHeight;
+ // We cannot use "expectExpression" here because *_case.value is not a
+ // Statement and would be converted to a Statement otherwise.
if (!(*this)(*_case.value))
success = false;
expectDeposit(1, initialStackHeight, _case.value->location);
@@ -309,6 +304,7 @@ bool AsmAnalyzer::operator()(Switch const& _switch)
}
m_stackHeight--;
+ m_info.stackHeightInfo[&_switch] = m_stackHeight;
return success;
}
@@ -349,6 +345,32 @@ bool AsmAnalyzer::operator()(Block const& _block)
return success;
}
+bool AsmAnalyzer::expectExpression(Statement const& _statement)
+{
+ bool success = true;
+ int const initialHeight = m_stackHeight;
+ if (!boost::apply_visitor(*this, _statement))
+ success = false;
+ if (!expectDeposit(1, initialHeight, locationOf(_statement)))
+ success = false;
+ return success;
+}
+
+bool AsmAnalyzer::expectDeposit(int _deposit, int _oldHeight, SourceLocation const& _location)
+{
+ if (m_stackHeight - _oldHeight != _deposit)
+ {
+ m_errorReporter.typeError(
+ _location,
+ "Expected expression to return one item to the stack, but did return " +
+ boost::lexical_cast<string>(m_stackHeight - _oldHeight) +
+ " items."
+ );
+ return false;
+ }
+ return true;
+}
+
bool AsmAnalyzer::checkAssignment(assembly::Identifier const& _variable, size_t _valueSize)
{
bool success = true;
@@ -362,7 +384,7 @@ bool AsmAnalyzer::checkAssignment(assembly::Identifier const& _variable, size_t
m_errorReporter.typeError(_variable.location, "Assignment requires variable.");
success = false;
}
- else if (!boost::get<Scope::Variable>(*var).active)
+ else if (!m_activeVariables.count(&boost::get<Scope::Variable>(*var)))
{
m_errorReporter.declarationError(
_variable.location,
@@ -373,7 +395,10 @@ bool AsmAnalyzer::checkAssignment(assembly::Identifier const& _variable, size_t
variableSize = 1;
}
else if (m_resolver)
- variableSize = m_resolver(_variable, julia::IdentifierContext::LValue);
+ {
+ bool insideFunction = m_currentScope->insideFunction();
+ variableSize = m_resolver(_variable, julia::IdentifierContext::LValue, insideFunction);
+ }
if (variableSize == size_t(-1))
{
// Only add message if the callback did not.
@@ -401,25 +426,6 @@ bool AsmAnalyzer::checkAssignment(assembly::Identifier const& _variable, size_t
return success;
}
-bool AsmAnalyzer::expectDeposit(int const _deposit, int const _oldHeight, SourceLocation const& _location)
-{
- int stackDiff = m_stackHeight - _oldHeight;
- if (stackDiff != _deposit)
- {
- m_errorReporter.typeError(
- _location,
- "Expected instruction(s) to deposit " +
- boost::lexical_cast<string>(_deposit) +
- " item(s) to the stack, but did deposit " +
- boost::lexical_cast<string>(stackDiff) +
- " item(s)."
- );
- return false;
- }
- else
- return true;
-}
-
Scope& AsmAnalyzer::scope(Block const* _block)
{
solAssert(m_info.scopes.count(_block) == 1, "Scope requested but not present.");
@@ -427,7 +433,6 @@ Scope& AsmAnalyzer::scope(Block const* _block)
solAssert(scopePtr, "Scope requested but not present.");
return *scopePtr;
}
-
void AsmAnalyzer::expectValidType(string const& type, SourceLocation const& _location)
{
if (!m_julia)
@@ -439,3 +444,20 @@ void AsmAnalyzer::expectValidType(string const& type, SourceLocation const& _loc
"\"" + type + "\" is not a valid type (user defined types are not yet supported)."
);
}
+
+void AsmAnalyzer::warnOnFutureInstruction(solidity::Instruction _instr, SourceLocation const& _location)
+{
+ switch (_instr)
+ {
+ case solidity::Instruction::RETURNDATASIZE:
+ case solidity::Instruction::RETURNDATACOPY:
+ m_errorReporter.warning(
+ _location,
+ "The RETURNDATASIZE/RETURNDATACOPY instructions are only available after "
+ "the Metropolis hard fork. Before that they act as an invalid instruction."
+ );
+ break;
+ default:
+ break;
+ }
+}
diff --git a/libsolidity/inlineasm/AsmAnalysis.h b/libsolidity/inlineasm/AsmAnalysis.h
index 7e4d78df..2516722a 100644
--- a/libsolidity/inlineasm/AsmAnalysis.h
+++ b/libsolidity/inlineasm/AsmAnalysis.h
@@ -20,7 +20,11 @@
#pragma once
-#include <libsolidity/inlineasm/AsmStack.h>
+#include <libsolidity/interface/Exceptions.h>
+
+#include <libsolidity/inlineasm/AsmScope.h>
+
+#include <libjulia/backends/evm/AbstractAssembly.h>
#include <boost/variant.hpp>
@@ -47,8 +51,7 @@ struct StackAssignment;
struct FunctionDefinition;
struct FunctionCall;
struct Switch;
-
-struct Scope;
+using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, Block>;
struct AsmAnalysisInfo;
@@ -83,16 +86,24 @@ public:
bool operator()(assembly::Block const& _block);
private:
+ /// Visits the statement and expects it to deposit one item onto the stack.
+ bool expectExpression(Statement const& _statement);
+ bool expectDeposit(int _deposit, int _oldHeight, SourceLocation const& _location);
+
/// Verifies that a variable to be assigned to exists and has the same size
/// as the value, @a _valueSize, unless that is equal to -1.
bool checkAssignment(assembly::Identifier const& _assignment, size_t _valueSize = size_t(-1));
- bool expectDeposit(int _deposit, int _oldHeight, SourceLocation const& _location);
+
Scope& scope(assembly::Block const* _block);
void expectValidType(std::string const& type, SourceLocation const& _location);
+ void warnOnFutureInstruction(solidity::Instruction _instr, SourceLocation const& _location);
int m_stackHeight = 0;
- julia::ExternalIdentifierAccess::Resolver const& m_resolver;
+ julia::ExternalIdentifierAccess::Resolver m_resolver;
Scope* m_currentScope = nullptr;
+ /// Variables that are active at the current point in assembly (as opposed to
+ /// "part of the scope but not yet declared")
+ std::set<Scope::Variable const*> m_activeVariables;
AsmAnalysisInfo& m_info;
ErrorReporter& m_errorReporter;
bool m_julia = false;
diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libsolidity/inlineasm/AsmCodeGen.cpp
index 11494c2d..27750453 100644
--- a/libsolidity/inlineasm/AsmCodeGen.cpp
+++ b/libsolidity/inlineasm/AsmCodeGen.cpp
@@ -87,29 +87,51 @@ public:
{
m_assembly.appendLibraryAddress(_linkerSymbol);
}
+ virtual void appendJump(int _stackDiffAfter) override
+ {
+ appendInstruction(solidity::Instruction::JUMP);
+ m_assembly.adjustDeposit(_stackDiffAfter);
+ }
+ virtual void appendJumpTo(LabelID _labelId, int _stackDiffAfter) override
+ {
+ appendLabelReference(_labelId);
+ appendJump(_stackDiffAfter);
+ }
+ virtual void appendJumpToIf(LabelID _labelId) override
+ {
+ appendLabelReference(_labelId);
+ appendInstruction(solidity::Instruction::JUMPI);
+ }
+ virtual void appendBeginsub(LabelID, int) override
+ {
+ // TODO we could emulate that, though
+ solAssert(false, "BEGINSUB not implemented for EVM 1.0");
+ }
+ /// Call a subroutine.
+ virtual void appendJumpsub(LabelID, int, int) override
+ {
+ // TODO we could emulate that, though
+ solAssert(false, "JUMPSUB not implemented for EVM 1.0");
+ }
+
+ /// Return from a subroutine.
+ virtual void appendReturnsub(int, int) override
+ {
+ // TODO we could emulate that, though
+ solAssert(false, "RETURNSUB not implemented for EVM 1.0");
+ }
private:
- size_t assemblyTagToIdentifier(eth::AssemblyItem const& _tag) const
+ LabelID assemblyTagToIdentifier(eth::AssemblyItem const& _tag) const
{
u256 id = _tag.data();
- solAssert(id <= std::numeric_limits<size_t>::max(), "Tag id too large.");
- return size_t(id);
+ solAssert(id <= std::numeric_limits<LabelID>::max(), "Tag id too large.");
+ return LabelID(id);
}
eth::Assembly& m_assembly;
};
-eth::Assembly assembly::CodeGenerator::assemble(
- Block const& _parsedData,
- AsmAnalysisInfo& _analysisInfo,
- julia::ExternalIdentifierAccess const& _identifierAccess
-)
-{
- eth::Assembly assembly;
- EthAssemblyAdapter assemblyAdapter(assembly);
- julia::CodeTransform(m_errorReporter, assemblyAdapter, _parsedData, _analysisInfo, _identifierAccess);
- return assembly;
-}
void assembly::CodeGenerator::assemble(
Block const& _parsedData,
@@ -119,5 +141,5 @@ void assembly::CodeGenerator::assemble(
)
{
EthAssemblyAdapter assemblyAdapter(_assembly);
- julia::CodeTransform(m_errorReporter, assemblyAdapter, _parsedData, _analysisInfo, _identifierAccess);
+ julia::CodeTransform(assemblyAdapter, _analysisInfo, false, _identifierAccess).run(_parsedData);
}
diff --git a/libsolidity/inlineasm/AsmCodeGen.h b/libsolidity/inlineasm/AsmCodeGen.h
index f075fa93..2a36a590 100644
--- a/libsolidity/inlineasm/AsmCodeGen.h
+++ b/libsolidity/inlineasm/AsmCodeGen.h
@@ -34,7 +34,6 @@ class Assembly;
}
namespace solidity
{
-class ErrorReporter;
namespace assembly
{
struct Block;
@@ -42,24 +41,13 @@ struct Block;
class CodeGenerator
{
public:
- CodeGenerator(ErrorReporter& _errorReporter):
- m_errorReporter(_errorReporter) {}
- /// Performs code generation and @returns the result.
- eth::Assembly assemble(
- Block const& _parsedData,
- AsmAnalysisInfo& _analysisInfo,
- julia::ExternalIdentifierAccess const& _identifierAccess = julia::ExternalIdentifierAccess()
- );
/// Performs code generation and appends generated to to _assembly.
- void assemble(
+ static void assemble(
Block const& _parsedData,
AsmAnalysisInfo& _analysisInfo,
eth::Assembly& _assembly,
julia::ExternalIdentifierAccess const& _identifierAccess = julia::ExternalIdentifierAccess()
);
-
-private:
- ErrorReporter& m_errorReporter;
};
}
diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp
index 0f836406..68a9cb03 100644
--- a/libsolidity/inlineasm/AsmParser.cpp
+++ b/libsolidity/inlineasm/AsmParser.cpp
@@ -200,10 +200,26 @@ std::map<string, dev::solidity::Instruction> const& Parser::instructions()
// add alias for suicide
s_instructions["suicide"] = solidity::Instruction::SELFDESTRUCT;
+ // add alis for sha3
+ s_instructions["sha3"] = solidity::Instruction::KECCAK256;
}
return s_instructions;
}
+std::map<dev::solidity::Instruction, string> const& Parser::instructionNames()
+{
+ static map<dev::solidity::Instruction, string> s_instructionNames;
+ if (s_instructionNames.empty())
+ {
+ for (auto const& instr: instructions())
+ s_instructionNames[instr.second] = instr.first;
+ // set the ambiguous instructions to a clear default
+ s_instructionNames[solidity::Instruction::SELFDESTRUCT] = "selfdestruct";
+ s_instructionNames[solidity::Instruction::KECCAK256] = "keccak256";
+ }
+ return s_instructionNames;
+}
+
assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
{
Statement ret;
@@ -231,7 +247,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
{
InstructionInfo info = dev::solidity::instructionInfo(instr);
if (info.ret != 1)
- fatalParserError("Instruction " + info.name + " not allowed in this context.");
+ fatalParserError("Instruction \"" + literal + "\" not allowed in this context.");
}
ret = Instruction{location(), instr};
}
@@ -361,9 +377,9 @@ assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
/// check for premature closing parentheses
if (currentToken() == Token::RParen)
fatalParserError(string(
- "Expected expression (" +
- instrInfo.name +
- " expects " +
+ "Expected expression (\"" +
+ instructionNames().at(instr) +
+ "\" expects " +
boost::lexical_cast<string>(args) +
" arguments)"
));
@@ -373,9 +389,9 @@ assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
{
if (currentToken() != Token::Comma)
fatalParserError(string(
- "Expected comma (" +
- instrInfo.name +
- " expects " +
+ "Expected comma (\"" +
+ instructionNames().at(instr) +
+ "\" expects " +
boost::lexical_cast<string>(args) +
" arguments)"
));
@@ -385,9 +401,13 @@ assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
}
ret.location.end = endPosition();
if (currentToken() == Token::Comma)
- fatalParserError(
- string("Expected ')' (" + instrInfo.name + " expects " + boost::lexical_cast<string>(args) + " arguments)")
- );
+ fatalParserError(string(
+ "Expected ')' (\"" +
+ instructionNames().at(instr) +
+ "\" expects " +
+ boost::lexical_cast<string>(args) +
+ " arguments)"
+ ));
expectToken(Token::RParen);
return ret;
}
diff --git a/libsolidity/inlineasm/AsmParser.h b/libsolidity/inlineasm/AsmParser.h
index e32b1d25..5fafad23 100644
--- a/libsolidity/inlineasm/AsmParser.h
+++ b/libsolidity/inlineasm/AsmParser.h
@@ -65,7 +65,8 @@ protected:
Case parseCase();
/// Parses a functional expression that has to push exactly one stack element
Statement parseExpression();
- std::map<std::string, dev::solidity::Instruction> const& instructions();
+ static std::map<std::string, dev::solidity::Instruction> const& instructions();
+ static std::map<dev::solidity::Instruction, std::string> const& instructionNames();
Statement parseElementaryOperation(bool _onlySinglePusher = false);
VariableDeclaration parseVariableDeclaration();
FunctionDefinition parseFunctionDefinition();
diff --git a/libsolidity/inlineasm/AsmScope.cpp b/libsolidity/inlineasm/AsmScope.cpp
index e3f4615a..1db5ca41 100644
--- a/libsolidity/inlineasm/AsmScope.cpp
+++ b/libsolidity/inlineasm/AsmScope.cpp
@@ -46,7 +46,7 @@ bool Scope::registerFunction(string const& _name, std::vector<JuliaType> const&
{
if (exists(_name))
return false;
- identifiers[_name] = Function(_arguments, _returns);
+ identifiers[_name] = Function{_arguments, _returns};
return true;
}
@@ -79,3 +79,11 @@ bool Scope::exists(string const& _name)
else
return false;
}
+
+bool Scope::insideFunction() const
+{
+ for (Scope const* s = this; s; s = s->superScope)
+ if (s->functionScope)
+ return true;
+ return false;
+}
diff --git a/libsolidity/inlineasm/AsmScope.h b/libsolidity/inlineasm/AsmScope.h
index 498218b4..de9119e0 100644
--- a/libsolidity/inlineasm/AsmScope.h
+++ b/libsolidity/inlineasm/AsmScope.h
@@ -65,24 +65,10 @@ struct Scope
using JuliaType = std::string;
using LabelID = size_t;
- struct Variable
- {
- /// Used during code generation to store the stack height. @todo move there.
- int stackHeight = 0;
- /// Used during analysis to check whether we already passed the declaration inside the block.
- /// @todo move there.
- bool active = false;
- JuliaType type;
- };
-
- struct Label
- {
- boost::optional<LabelID> id;
- };
-
+ struct Variable { JuliaType type; };
+ struct Label { };
struct Function
{
- Function(std::vector<JuliaType> const& _arguments, std::vector<JuliaType> const& _returns): arguments(_arguments), returns(_returns) {}
std::vector<JuliaType> arguments;
std::vector<JuliaType> returns;
};
@@ -123,6 +109,9 @@ struct Scope
/// across function and assembly boundaries).
bool exists(std::string const& _name);
+ /// @returns true if this scope is inside a function.
+ bool insideFunction() const;
+
Scope* superScope = nullptr;
/// If true, variables from the super scope are not visible here (other identifiers are),
/// but they are still taken into account to prevent shadowing.
diff --git a/libsolidity/inlineasm/AsmStack.cpp b/libsolidity/inlineasm/AsmStack.cpp
deleted file mode 100644
index 73b1604d..00000000
--- a/libsolidity/inlineasm/AsmStack.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- 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 Christian <c@ethdev.com>
- * @date 2016
- * Full-stack Solidity inline assember.
- */
-
-#include <libsolidity/inlineasm/AsmStack.h>
-
-#include <libsolidity/inlineasm/AsmParser.h>
-#include <libsolidity/inlineasm/AsmCodeGen.h>
-#include <libsolidity/inlineasm/AsmPrinter.h>
-#include <libsolidity/inlineasm/AsmAnalysis.h>
-#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
-
-#include <libsolidity/parsing/Scanner.h>
-
-#include <libevmasm/Assembly.h>
-#include <libevmasm/SourceLocation.h>
-
-#include <memory>
-
-using namespace std;
-using namespace dev;
-using namespace dev::solidity;
-using namespace dev::solidity::assembly;
-
-bool InlineAssemblyStack::parse(
- shared_ptr<Scanner> const& _scanner,
- julia::ExternalIdentifierAccess::Resolver const& _resolver
-)
-{
- m_parserResult = make_shared<Block>();
- Parser parser(m_errorReporter);
- auto result = parser.parse(_scanner);
- if (!result)
- return false;
-
- *m_parserResult = std::move(*result);
- AsmAnalysisInfo analysisInfo;
- return (AsmAnalyzer(analysisInfo, m_errorReporter, false, _resolver)).analyze(*m_parserResult);
-}
-
-string InlineAssemblyStack::toString()
-{
- return AsmPrinter()(*m_parserResult);
-}
-
-eth::Assembly InlineAssemblyStack::assemble()
-{
- AsmAnalysisInfo analysisInfo;
- AsmAnalyzer analyzer(analysisInfo, m_errorReporter);
- solAssert(analyzer.analyze(*m_parserResult), "");
- CodeGenerator codeGen(m_errorReporter);
- return codeGen.assemble(*m_parserResult, analysisInfo);
-}
-
-bool InlineAssemblyStack::parseAndAssemble(
- string const& _input,
- eth::Assembly& _assembly,
- julia::ExternalIdentifierAccess const& _identifierAccess
-)
-{
- ErrorList errors;
- ErrorReporter errorReporter(errors);
- auto scanner = make_shared<Scanner>(CharStream(_input), "--CODEGEN--");
- auto parserResult = Parser(errorReporter).parse(scanner);
- if (!errorReporter.errors().empty())
- return false;
- solAssert(parserResult, "");
-
- AsmAnalysisInfo analysisInfo;
- AsmAnalyzer analyzer(analysisInfo, errorReporter, false, _identifierAccess.resolve);
- solAssert(analyzer.analyze(*parserResult), "");
- CodeGenerator(errorReporter).assemble(*parserResult, analysisInfo, _assembly, _identifierAccess);
-
- // At this point, the assembly might be messed up, but we should throw an
- // internal compiler error anyway.
- return errorReporter.errors().empty();
-}
-
diff --git a/libsolidity/inlineasm/AsmStack.h b/libsolidity/inlineasm/AsmStack.h
deleted file mode 100644
index 7452804d..00000000
--- a/libsolidity/inlineasm/AsmStack.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- 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 Christian <c@ethdev.com>
- * @date 2016
- * Full-stack Solidity inline assember.
- */
-
-#pragma once
-
-#include <libjulia/backends/evm/AbstractAssembly.h>
-#include <libsolidity/interface/ErrorReporter.h>
-
-#include <string>
-#include <functional>
-
-namespace dev
-{
-namespace eth
-{
-class Assembly;
-}
-namespace solidity
-{
-class Scanner;
-namespace assembly
-{
-struct Block;
-struct Identifier;
-
-class InlineAssemblyStack
-{
-public:
- InlineAssemblyStack():
- m_errorReporter(m_errorList) {}
- /// Parse the given inline assembly chunk starting with `{` and ending with the corresponding `}`.
- /// @return false or error.
- bool parse(
- std::shared_ptr<Scanner> const& _scanner,
- julia::ExternalIdentifierAccess::Resolver const& _externalIdentifierResolver = julia::ExternalIdentifierAccess::Resolver()
- );
- /// Converts the parser result back into a string form (not necessarily the same form
- /// as the source form, but it should parse into the same parsed form again).
- std::string toString();
-
- eth::Assembly assemble();
-
- /// Parse and assemble a string in one run - for use in Solidity code generation itself.
- bool parseAndAssemble(
- std::string const& _input,
- eth::Assembly& _assembly,
- julia::ExternalIdentifierAccess const& _identifierAccess = julia::ExternalIdentifierAccess()
- );
-
- ErrorList const& errors() const { return m_errorReporter.errors(); }
-
-private:
- std::shared_ptr<Block> m_parserResult;
- ErrorList m_errorList;
- ErrorReporter m_errorReporter;
-};
-
-}
-}
-}
diff --git a/libsolidity/interface/AssemblyStack.cpp b/libsolidity/interface/AssemblyStack.cpp
index b027ac3c..7dc1edc7 100644
--- a/libsolidity/interface/AssemblyStack.cpp
+++ b/libsolidity/interface/AssemblyStack.cpp
@@ -26,10 +26,14 @@
#include <libsolidity/inlineasm/AsmPrinter.h>
#include <libsolidity/inlineasm/AsmParser.h>
#include <libsolidity/inlineasm/AsmAnalysis.h>
+#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
#include <libsolidity/inlineasm/AsmCodeGen.h>
#include <libevmasm/Assembly.h>
+#include <libjulia/backends/evm/EVMCodeTransform.h>
+#include <libjulia/backends/evm/EVMAssembly.h>
+
using namespace std;
using namespace dev;
using namespace dev::solidity;
@@ -43,6 +47,7 @@ Scanner const& AssemblyStack::scanner() const
bool AssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string const& _source)
{
+ m_errors.clear();
m_analysisSuccessful = false;
m_scanner = make_shared<Scanner>(CharStream(_source), _sourceName);
m_parserResult = assembly::Parser(m_errorReporter, m_language == Language::JULIA).parse(m_scanner);
@@ -50,13 +55,29 @@ bool AssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string
return false;
solAssert(m_parserResult, "");
+ return analyzeParsed();
+}
+
+bool AssemblyStack::analyze(assembly::Block const& _block, Scanner const* _scanner)
+{
+ m_errors.clear();
+ m_analysisSuccessful = false;
+ if (_scanner)
+ m_scanner = make_shared<Scanner>(*_scanner);
+ m_parserResult = make_shared<assembly::Block>(_block);
+
+ return analyzeParsed();
+}
+
+bool AssemblyStack::analyzeParsed()
+{
m_analysisInfo = make_shared<assembly::AsmAnalysisInfo>();
assembly::AsmAnalyzer analyzer(*m_analysisInfo, m_errorReporter);
m_analysisSuccessful = analyzer.analyze(*m_parserResult);
return m_analysisSuccessful;
}
-eth::LinkerObject AssemblyStack::assemble(Machine _machine)
+MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
{
solAssert(m_analysisSuccessful, "");
solAssert(m_parserResult, "");
@@ -66,19 +87,32 @@ eth::LinkerObject AssemblyStack::assemble(Machine _machine)
{
case Machine::EVM:
{
- auto assembly = assembly::CodeGenerator(m_errorReporter).assemble(*m_parserResult, *m_analysisInfo);
- return assembly.assemble();
+ MachineAssemblyObject object;
+ eth::Assembly assembly;
+ assembly::CodeGenerator::assemble(*m_parserResult, *m_analysisInfo, assembly);
+ object.bytecode = make_shared<eth::LinkerObject>(assembly.assemble());
+ ostringstream tmp;
+ assembly.stream(tmp);
+ object.assembly = tmp.str();
+ return object;
}
case Machine::EVM15:
- solUnimplemented("EVM 1.5 backend is not yet implemented.");
+ {
+ MachineAssemblyObject object;
+ julia::EVMAssembly assembly(true);
+ julia::CodeTransform(assembly, *m_analysisInfo, true).run(*m_parserResult);
+ object.bytecode = make_shared<eth::LinkerObject>(assembly.finalize());
+ /// TOOD: fill out text representation
+ return object;
+ }
case Machine::eWasm:
solUnimplemented("eWasm backend is not yet implemented.");
}
// unreachable
- return eth::LinkerObject();
+ return MachineAssemblyObject();
}
-string AssemblyStack::print()
+string AssemblyStack::print() const
{
solAssert(m_parserResult, "");
return assembly::AsmPrinter(m_language == Language::JULIA)(*m_parserResult);
diff --git a/libsolidity/interface/AssemblyStack.h b/libsolidity/interface/AssemblyStack.h
index 62a5134a..2ae596ed 100644
--- a/libsolidity/interface/AssemblyStack.h
+++ b/libsolidity/interface/AssemblyStack.h
@@ -21,7 +21,6 @@
#pragma once
-#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
#include <libsolidity/interface/ErrorReporter.h>
#include <libevmasm/LinkerObject.h>
@@ -39,6 +38,12 @@ struct AsmAnalysisInfo;
struct Block;
}
+struct MachineAssemblyObject
+{
+ std::shared_ptr<eth::LinkerObject> bytecode;
+ std::string assembly;
+};
+
/*
* Full assembly stack that can support EVM-assembly and JULIA as input and EVM, EVM1.5 and
* eWasm as output.
@@ -60,16 +65,21 @@ public:
/// Multiple calls overwrite the previous state.
bool parseAndAnalyze(std::string const& _sourceName, std::string const& _source);
+ /// Runs analysis step on the supplied block, returns false if input cannot be assembled.
+ /// Multiple calls overwrite the previous state.
+ bool analyze(assembly::Block const& _block, Scanner const* _scanner = nullptr);
+
/// Run the assembly step (should only be called after parseAndAnalyze).
- eth::LinkerObject assemble(Machine _machine);
+ MachineAssemblyObject assemble(Machine _machine) const;
/// @returns the errors generated during parsing, analysis (and potentially assembly).
ErrorList const& errors() const { return m_errors; }
/// Pretty-print the input after having parsed it.
- std::string print();
+ std::string print() const;
private:
+ bool analyzeParsed();
Language m_language = Language::Assembly;
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index 44220402..aca9ce39 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -85,6 +85,7 @@ void CompilerStack::reset(bool _keepSources)
}
else
{
+ m_stackState = Empty;
m_sources.clear();
}
m_optimize = false;
@@ -94,7 +95,6 @@ void CompilerStack::reset(bool _keepSources)
m_sourceOrder.clear();
m_contracts.clear();
m_errorReporter.clear();
- m_stackState = Empty;
}
bool CompilerStack::addSource(string const& _name, string const& _content, bool _isLibrary)
@@ -400,15 +400,6 @@ eth::LinkerObject const& CompilerStack::cloneObject(string const& _contractName)
return contract(_contractName).cloneObject;
}
-dev::h256 CompilerStack::contractCodeHash(string const& _contractName) const
-{
- auto const& obj = runtimeObject(_contractName);
- if (obj.bytecode.empty() || !obj.linkReferences.empty())
- return dev::h256();
- else
- return dev::keccak256(obj.bytecode);
-}
-
Json::Value CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes, bool _inJsonFormat) const
{
Contract const& currentContract = contract(_contractName);
@@ -744,14 +735,6 @@ void CompilerStack::compileContract(
}
}
-std::string CompilerStack::defaultContractName() const
-{
- if (m_stackState != CompilationSuccessful)
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
-
- return contract("").contract->name();
-}
-
CompilerStack::Contract const& CompilerStack::contract(string const& _contractName) const
{
if (m_contracts.empty())
diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h
index 76d36c7b..bffdeabd 100644
--- a/libsolidity/interface/CompilerStack.h
+++ b/libsolidity/interface/CompilerStack.h
@@ -117,7 +117,6 @@ public:
bool parseAndAnalyze(std::string const& _sourceCode);
/// @returns a list of the contract names in the sources.
std::vector<std::string> contractNames() const;
- std::string defaultContractName() const;
/// Compiles the source units that were previously added and parsed.
/// @returns false on error.
@@ -159,11 +158,6 @@ 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 hash of the runtime bytecode for the contract, i.e. the code that is
- /// returned by the constructor or the zero-h256 if the contract still needs to be linked or
- /// does not have runtime code.
- dev::h256 contractCodeHash(std::string const& _contractName = "") const;
-
/// Streams a verbose version of the assembly to @a _outStream.
/// @arg _sourceCodes is the map of input files to source code strings
/// @arg _inJsonFromat shows whether the out should be in Json format
@@ -197,13 +191,6 @@ public:
/// does not exist.
ContractDefinition const& contractDefinition(std::string const& _contractName) const;
- /// @returns the offset of the entry point of the given function into the list of assembly items
- /// or zero if it is not found or does not exist.
- size_t functionEntryPoint(
- std::string const& _contractName,
- FunctionDefinition const& _function
- ) const;
-
/// Helper function for logs printing. Do only use in error cases, it's quite expensive.
/// line and columns are numbered starting from 1 with following order:
/// start line, start column, end line, end column
@@ -272,6 +259,13 @@ private:
Json::Value const& contractABI(Contract const&) const;
Json::Value const& natspec(Contract const&, DocumentationType _type) const;
+ /// @returns the offset of the entry point of the given function into the list of assembly items
+ /// or zero if it is not found or does not exist.
+ size_t functionEntryPoint(
+ std::string const& _contractName,
+ FunctionDefinition const& _function
+ ) const;
+
struct Remapping
{
std::string context;