diff options
author | chriseth <chris@ethereum.org> | 2017-12-13 21:40:54 +0800 |
---|---|---|
committer | Alex Beregszaszi <alex@rtfs.hu> | 2018-01-06 09:23:38 +0800 |
commit | 124190336b0a70ea32d5f8ca0c4b364f1fc774d0 (patch) | |
tree | 6be4f7815f417c9343ed57a85ec51f77f0c53aff | |
parent | 2548228b365d56612e2f039f735be0fdf6ce0807 (diff) | |
download | dexon-solidity-124190336b0a70ea32d5f8ca0c4b364f1fc774d0.tar.gz dexon-solidity-124190336b0a70ea32d5f8ca0c4b364f1fc774d0.tar.zst dexon-solidity-124190336b0a70ea32d5f8ca0c4b364f1fc774d0.zip |
Split inline assembly into loose and strict flavours.
-rw-r--r-- | libsolidity/analysis/ReferencesResolver.cpp | 2 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 2 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.cpp | 9 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.h | 4 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmAnalysis.cpp | 17 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmAnalysis.h | 6 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmDataForward.h | 7 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmParser.cpp | 31 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmParser.h | 8 | ||||
-rw-r--r-- | libsolidity/interface/AssemblyStack.cpp | 21 | ||||
-rw-r--r-- | test/libjulia/Common.cpp | 5 | ||||
-rw-r--r-- | test/libjulia/Parser.cpp | 4 |
12 files changed, 78 insertions, 38 deletions
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 9eee16af..540ffaf5 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -207,7 +207,7 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) // Will be re-generated later with correct information assembly::AsmAnalysisInfo analysisInfo; - assembly::AsmAnalyzer(analysisInfo, errorsIgnored, false, resolver).analyze(_inlineAssembly.operations()); + assembly::AsmAnalyzer(analysisInfo, errorsIgnored, assembly::AsmFlavour::Loose, resolver).analyze(_inlineAssembly.operations()); return false; } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 75d71925..191f78e9 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -873,7 +873,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) assembly::AsmAnalyzer analyzer( *_inlineAssembly.annotation().analysisInfo, m_errorReporter, - false, + assembly::AsmFlavour::Loose, identifierAccess ); if (!analyzer.analyze(_inlineAssembly.operations())) diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index ab10d7dd..7a88475a 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -319,14 +319,19 @@ void CompilerContext::appendInlineAssembly( ErrorList errors; ErrorReporter errorReporter(errors); auto scanner = make_shared<Scanner>(CharStream(_assembly), "--CODEGEN--"); - auto parserResult = assembly::Parser(errorReporter).parse(scanner); + auto parserResult = assembly::Parser(errorReporter, assembly::AsmFlavour::Strict).parse(scanner); #ifdef SOL_OUTPUT_ASM cout << assembly::AsmPrinter()(*parserResult) << endl; #endif assembly::AsmAnalysisInfo analysisInfo; bool analyzerResult = false; if (parserResult) - analyzerResult = assembly::AsmAnalyzer(analysisInfo, errorReporter, false, identifierAccess.resolve).analyze(*parserResult); + analyzerResult = assembly::AsmAnalyzer( + analysisInfo, + errorReporter, + assembly::AsmFlavour::Strict, + identifierAccess.resolve + ).analyze(*parserResult); if (!parserResult || !errorReporter.errors().empty() || !analyzerResult) { string message = diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 7743fd3f..0e8b639c 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -187,8 +187,8 @@ public: CompilerContext& operator<<(u256 const& _value) { m_asm->append(_value); return *this; } CompilerContext& operator<<(bytes const& _data) { m_asm->append(_data); return *this; } - /// Appends inline assembly. @a _replacements are string-matching replacements that are performed - /// prior to parsing the inline assembly. + /// Appends inline assembly (strict mode). + /// @a _replacements are string-matching replacements that are performed prior to parsing the inline assembly. /// @param _localVariables assigns stack positions to variables with the last one being the stack top /// @param _system if true, this is a "system-level" assembly where all functions use named labels. void appendInlineAssembly( diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp index 17b7cce0..2d6e58de 100644 --- a/libsolidity/inlineasm/AsmAnalysis.cpp +++ b/libsolidity/inlineasm/AsmAnalysis.cpp @@ -54,7 +54,7 @@ bool AsmAnalyzer::analyze(Block const& _block) bool AsmAnalyzer::operator()(Label const& _label) { - solAssert(!m_julia, ""); + solAssert(m_flavour == AsmFlavour::Loose, ""); m_info.stackHeightInfo[&_label] = m_stackHeight; warnOnInstructions(solidity::Instruction::JUMPDEST, _label.location); return true; @@ -62,7 +62,7 @@ bool AsmAnalyzer::operator()(Label const& _label) bool AsmAnalyzer::operator()(assembly::Instruction const& _instruction) { - solAssert(!m_julia, ""); + solAssert(m_flavour == AsmFlavour::Loose, ""); auto const& info = instructionInfo(_instruction.instruction); m_stackHeight += info.ret - info.args; m_info.stackHeightInfo[&_instruction] = m_stackHeight; @@ -141,7 +141,7 @@ bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier) bool AsmAnalyzer::operator()(FunctionalInstruction const& _instr) { - solAssert(!m_julia, ""); + solAssert(m_flavour != AsmFlavour::IULIA, ""); bool success = true; for (auto const& arg: _instr.arguments | boost::adaptors::reversed) if (!expectExpression(arg)) @@ -157,17 +157,18 @@ bool AsmAnalyzer::operator()(FunctionalInstruction const& _instr) bool AsmAnalyzer::operator()(assembly::ExpressionStatement const& _statement) { -// size_t initialStackHeight = m_stackHeight; + size_t initialStackHeight = m_stackHeight; bool success = boost::apply_visitor(*this, _statement.expression); -// if (!expectDeposit(0, initialStackHeight, _statement.location)) -// success = false; + if (m_flavour != AsmFlavour::Loose) + if (!expectDeposit(0, initialStackHeight, _statement.location)) + success = false; m_info.stackHeightInfo[&_statement] = m_stackHeight; return success; } bool AsmAnalyzer::operator()(assembly::StackAssignment const& _assignment) { - solAssert(!m_julia, ""); + solAssert(m_flavour == AsmFlavour::Loose, ""); bool success = checkAssignment(_assignment.variableName, size_t(-1)); m_info.stackHeightInfo[&_assignment] = m_stackHeight; return success; @@ -507,7 +508,7 @@ Scope& AsmAnalyzer::scope(Block const* _block) } void AsmAnalyzer::expectValidType(string const& type, SourceLocation const& _location) { - if (!m_julia) + if (m_flavour != AsmFlavour::IULIA) return; if (!builtinTypes.count(type)) diff --git a/libsolidity/inlineasm/AsmAnalysis.h b/libsolidity/inlineasm/AsmAnalysis.h index 00a33db3..7a81dbf8 100644 --- a/libsolidity/inlineasm/AsmAnalysis.h +++ b/libsolidity/inlineasm/AsmAnalysis.h @@ -54,9 +54,9 @@ public: explicit AsmAnalyzer( AsmAnalysisInfo& _analysisInfo, ErrorReporter& _errorReporter, - bool _julia = false, + AsmFlavour _flavour = AsmFlavour::Loose, julia::ExternalIdentifierAccess::Resolver const& _resolver = julia::ExternalIdentifierAccess::Resolver() - ): m_resolver(_resolver), m_info(_analysisInfo), m_errorReporter(_errorReporter), m_julia(_julia) {} + ): m_resolver(_resolver), m_info(_analysisInfo), m_errorReporter(_errorReporter), m_flavour(_flavour) {} bool analyze(assembly::Block const& _block); @@ -97,7 +97,7 @@ private: std::set<Scope::Variable const*> m_activeVariables; AsmAnalysisInfo& m_info; ErrorReporter& m_errorReporter; - bool m_julia = false; + AsmFlavour m_flavour = AsmFlavour::Loose; }; } diff --git a/libsolidity/inlineasm/AsmDataForward.h b/libsolidity/inlineasm/AsmDataForward.h index 317e257c..3a9600fe 100644 --- a/libsolidity/inlineasm/AsmDataForward.h +++ b/libsolidity/inlineasm/AsmDataForward.h @@ -53,6 +53,13 @@ struct TypedName; using Expression = boost::variant<FunctionalInstruction, FunctionCall, Identifier, Literal>; using Statement = boost::variant<ExpressionStatement, Instruction, Label, StackAssignment, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Block>; +enum class AsmFlavour +{ + Loose, // no types, EVM instructions as function, jumps and direct stack manipulations + Strict, // no types, EVM instructions as functions, but no jumps and no direct stack manipulations + IULIA // same as Strict mode with types +}; + } } } diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp index 20c7b2a5..5983d7ff 100644 --- a/libsolidity/inlineasm/AsmParser.cpp +++ b/libsolidity/inlineasm/AsmParser.cpp @@ -103,14 +103,14 @@ assembly::Statement Parser::parseStatement() return parseForLoop(); case Token::Assign: { - if (m_julia) + if (m_flavour != AsmFlavour::Loose) break; assembly::StackAssignment assignment = createWithLocation<assembly::StackAssignment>(); advance(); expectToken(Token::Colon); assignment.variableName.location = location(); assignment.variableName.name = currentLiteral(); - if (!m_julia && instructions().count(assignment.variableName.name)) + if (instructions().count(assignment.variableName.name)) fatalParserError("Identifier expected, got instruction name."); assignment.location.end = endPosition(); expectToken(Token::Identifier); @@ -170,7 +170,7 @@ assembly::Statement Parser::parseStatement() if (currentToken() == Token::Assign && peekNextToken() != Token::Colon) { assembly::Assignment assignment = createWithLocation<assembly::Assignment>(identifier.location); - if (!m_julia && instructions().count(identifier.name)) + if (m_flavour != AsmFlavour::IULIA && instructions().count(identifier.name)) fatalParserError("Cannot use instruction names for identifier names."); advance(); assignment.variableNames.emplace_back(identifier); @@ -181,7 +181,7 @@ assembly::Statement Parser::parseStatement() else { // label - if (m_julia) + if (m_flavour != AsmFlavour::Loose) fatalParserError("Labels are not supported."); Label label = createWithLocation<Label>(identifier.location); label.name = identifier.name; @@ -189,7 +189,7 @@ assembly::Statement Parser::parseStatement() } } default: - if (m_julia) + if (m_flavour != AsmFlavour::Loose) fatalParserError("Call or assignment expected."); break; } @@ -247,13 +247,17 @@ assembly::ForLoop Parser::parseForLoop() assembly::Expression Parser::parseExpression() { RecursionGuard recursionGuard(*this); + // In strict mode, this might parse a plain Instruction, but + // it will be converted to a FunctionalInstruction inside + // parseCall below. ElementaryOperation operation = parseElementaryOperation(); if (operation.type() == typeid(Instruction)) { Instruction const& instr = boost::get<Instruction>(operation); // Enforce functional notation for instructions requiring multiple arguments. int args = instructionInfo(instr.instruction).args; - if (args > 0 && currentToken() != Token::LParen) + bool requireFunctionalNotation = (args > 0 || m_flavour != AsmFlavour::Loose); + if (requireFunctionalNotation && currentToken() != Token::LParen) fatalParserError(string( "Expected token \"(\" (\"" + instructionNames().at(instr.instruction) + @@ -278,6 +282,7 @@ assembly::Expression Parser::parseExpression() else if (operation.type() == typeid(Instruction)) { // Instructions not taking arguments are allowed as expressions. + solAssert(m_flavour == AsmFlavour::Loose, ""); Instruction& instr = boost::get<Instruction>(operation); return FunctionalInstruction{std::move(instr.location), instr.instruction, {}}; } @@ -351,7 +356,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() else literal = currentLiteral(); // first search the set of instructions. - if (!m_julia && instructions().count(literal)) + if (m_flavour != AsmFlavour::IULIA && instructions().count(literal)) { dev::solidity::Instruction const& instr = instructions().at(literal); ret = Instruction{location(), instr}; @@ -392,7 +397,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() "" }; advance(); - if (m_julia) + if (m_flavour == AsmFlavour::IULIA) { expectToken(Token::Colon); literal.location.end = endPosition(); @@ -405,7 +410,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() } default: fatalParserError( - m_julia ? + m_flavour == AsmFlavour::IULIA ? "Literal or identifier expected." : "Literal, identifier or instruction expected." ); @@ -475,7 +480,7 @@ assembly::Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp) RecursionGuard recursionGuard(*this); if (_initialOp.type() == typeid(Instruction)) { - solAssert(!m_julia, "Instructions are invalid in JULIA"); + solAssert(m_flavour != AsmFlavour::IULIA, "Instructions are invalid in JULIA"); Instruction& instruction = boost::get<Instruction>(_initialOp); FunctionalInstruction ret; ret.instruction = instruction.instruction; @@ -546,7 +551,7 @@ assembly::Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp) } else fatalParserError( - m_julia ? + m_flavour == AsmFlavour::IULIA ? "Function name expected." : "Assembly instruction or function name required in front of \"(\")" ); @@ -559,7 +564,7 @@ TypedName Parser::parseTypedName() RecursionGuard recursionGuard(*this); TypedName typedName = createWithLocation<TypedName>(); typedName.name = expectAsmIdentifier(); - if (m_julia) + if (m_flavour == AsmFlavour::IULIA) { expectToken(Token::Colon); typedName.location.end = endPosition(); @@ -571,7 +576,7 @@ TypedName Parser::parseTypedName() string Parser::expectAsmIdentifier() { string name = currentLiteral(); - if (m_julia) + if (m_flavour == AsmFlavour::IULIA) { switch (currentToken()) { diff --git a/libsolidity/inlineasm/AsmParser.h b/libsolidity/inlineasm/AsmParser.h index bd90bb43..015aeef3 100644 --- a/libsolidity/inlineasm/AsmParser.h +++ b/libsolidity/inlineasm/AsmParser.h @@ -37,7 +37,8 @@ namespace assembly class Parser: public ParserBase { public: - explicit Parser(ErrorReporter& _errorReporter, bool _julia = false): ParserBase(_errorReporter), m_julia(_julia) {} + explicit Parser(ErrorReporter& _errorReporter, AsmFlavour _flavour = AsmFlavour::Loose): + ParserBase(_errorReporter), m_flavour(_flavour) {} /// Parses an inline assembly block starting with `{` and ending with `}`. /// @returns an empty shared pointer on error. @@ -70,6 +71,9 @@ protected: assembly::Expression parseExpression(); static std::map<std::string, dev::solidity::Instruction> const& instructions(); static std::map<dev::solidity::Instruction, std::string> const& instructionNames(); + /// Parses an elementary operation, i.e. a literal, identifier or instruction. + /// This will parse instructions even in strict mode as part of the full parser + /// for FunctionalInstruction. ElementaryOperation parseElementaryOperation(); VariableDeclaration parseVariableDeclaration(); FunctionDefinition parseFunctionDefinition(); @@ -80,7 +84,7 @@ protected: static bool isValidNumberLiteral(std::string const& _literal); private: - bool m_julia = false; + AsmFlavour m_flavour = AsmFlavour::Loose; }; } diff --git a/libsolidity/interface/AssemblyStack.cpp b/libsolidity/interface/AssemblyStack.cpp index 504ad92c..7cec2798 100644 --- a/libsolidity/interface/AssemblyStack.cpp +++ b/libsolidity/interface/AssemblyStack.cpp @@ -38,6 +38,23 @@ using namespace std; using namespace dev; using namespace dev::solidity; +namespace +{ +assembly::AsmFlavour languageToAsmFlavour(AssemblyStack::Language _language) +{ + switch (_language) + { + case AssemblyStack::Language::Assembly: + return assembly::AsmFlavour::Loose; + case AssemblyStack::Language::JULIA: + return assembly::AsmFlavour::IULIA; + } + solAssert(false, ""); + return assembly::AsmFlavour::IULIA; +} + +} + Scanner const& AssemblyStack::scanner() const { @@ -50,7 +67,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 = assembly::Parser(m_errorReporter, m_language == Language::JULIA).parse(m_scanner); + m_parserResult = assembly::Parser(m_errorReporter, languageToAsmFlavour(m_language)).parse(m_scanner); if (!m_errorReporter.errors().empty()) return false; solAssert(m_parserResult, ""); @@ -72,7 +89,7 @@ bool AssemblyStack::analyze(assembly::Block const& _block, Scanner const* _scann bool AssemblyStack::analyzeParsed() { m_analysisInfo = make_shared<assembly::AsmAnalysisInfo>(); - assembly::AsmAnalyzer analyzer(*m_analysisInfo, m_errorReporter, m_language == Language::JULIA); + assembly::AsmAnalyzer analyzer(*m_analysisInfo, m_errorReporter, languageToAsmFlavour(m_language)); m_analysisSuccessful = analyzer.analyze(*m_parserResult); return m_analysisSuccessful; } diff --git a/test/libjulia/Common.cpp b/test/libjulia/Common.cpp index da1538f3..e1ab8215 100644 --- a/test/libjulia/Common.cpp +++ b/test/libjulia/Common.cpp @@ -52,15 +52,16 @@ void dev::julia::test::printErrors(ErrorList const& _errors, Scanner const& _sca pair<shared_ptr<Block>, shared_ptr<assembly::AsmAnalysisInfo>> dev::julia::test::parse(string const& _source, bool _julia) { + auto flavour = _julia ? assembly::AsmFlavour::IULIA : assembly::AsmFlavour::Strict; ErrorList errors; ErrorReporter errorReporter(errors); auto scanner = make_shared<Scanner>(CharStream(_source), ""); - auto parserResult = assembly::Parser(errorReporter, _julia).parse(scanner); + auto parserResult = assembly::Parser(errorReporter, flavour).parse(scanner); if (parserResult) { BOOST_REQUIRE(errorReporter.errors().empty()); auto analysisInfo = make_shared<assembly::AsmAnalysisInfo>(); - assembly::AsmAnalyzer analyzer(*analysisInfo, errorReporter, _julia); + assembly::AsmAnalyzer analyzer(*analysisInfo, errorReporter, flavour); if (analyzer.analyze(*parserResult)) { BOOST_REQUIRE(errorReporter.errors().empty()); diff --git a/test/libjulia/Parser.cpp b/test/libjulia/Parser.cpp index 3ca62a90..a8a41b3c 100644 --- a/test/libjulia/Parser.cpp +++ b/test/libjulia/Parser.cpp @@ -52,11 +52,11 @@ bool parse(string const& _source, ErrorReporter& errorReporter) try { auto scanner = make_shared<Scanner>(CharStream(_source)); - auto parserResult = assembly::Parser(errorReporter, true).parse(scanner); + auto parserResult = assembly::Parser(errorReporter, assembly::AsmFlavour::IULIA).parse(scanner); if (parserResult) { assembly::AsmAnalysisInfo analysisInfo; - return (assembly::AsmAnalyzer(analysisInfo, errorReporter, true)).analyze(*parserResult); + return (assembly::AsmAnalyzer(analysisInfo, errorReporter, assembly::AsmFlavour::IULIA)).analyze(*parserResult); } } catch (FatalError const&) |