From a1d73a7befd2f3d72c18d4cb539edab5111c681f Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Fri, 14 Sep 2018 15:49:55 +0200 Subject: Split simplification rules into two functions. --- Changelog.md | 1 + libevmasm/ExpressionClasses.cpp | 1 + libevmasm/RuleList.h | 47 +++++++++++++++++++++++++----- libevmasm/SimplificationRules.cpp | 21 +++++++++---- libevmasm/SimplificationRules.h | 6 ++++ libjulia/optimiser/SimplificationRules.cpp | 7 +++++ libjulia/optimiser/SimplificationRules.h | 3 ++ 7 files changed, 73 insertions(+), 13 deletions(-) diff --git a/Changelog.md b/Changelog.md index 95197e04..4e8b4ee3 100644 --- a/Changelog.md +++ b/Changelog.md @@ -102,6 +102,7 @@ Bugfixes: * Commandline Interface: Correctly handle paths with backslashes on windows. * Fix NatSpec json output for `@notice` and `@dev` tags on contract definitions. * Optimizer: Correctly estimate gas costs of constants for special cases. + * Optimizer: Fix simplification rule initialization bug that appeared on some emscripten platforms. * References Resolver: Do not crash on using ``_slot`` and ``_offset`` suffixes on their own. * References Resolver: Enforce ``storage`` as data location for mappings. * References Resolver: Properly handle invalid references used together with ``_slot`` and ``_offset``. diff --git a/libevmasm/ExpressionClasses.cpp b/libevmasm/ExpressionClasses.cpp index 69b33ec5..42a1819a 100644 --- a/libevmasm/ExpressionClasses.cpp +++ b/libevmasm/ExpressionClasses.cpp @@ -184,6 +184,7 @@ string ExpressionClasses::fullDAGToString(ExpressionClasses::Id _id) const ExpressionClasses::Id ExpressionClasses::tryToSimplify(Expression const& _expr) { static Rules rules; + assertThrow(rules.isInitialized(), OptimizerException, "Rule list not properly initialized."); if ( !_expr.item || diff --git a/libevmasm/RuleList.h b/libevmasm/RuleList.h index 0573856b..874a8929 100644 --- a/libevmasm/RuleList.h +++ b/libevmasm/RuleList.h @@ -44,12 +44,11 @@ template S modWorkaround(S const& _a, S const& _b) return (S)(bigint(_a) % bigint(_b)); } -/// @returns a list of simplification rules given certain match placeholders. -/// A, B and C should represent constants, X and Y arbitrary expressions. -/// The simplifications should never change the order of evaluation of -/// arbitrary operations. +// This part of simplificationRuleList below was split out to prevent +// stack overflows in the JavaScript optimizer for emscripten builds +// that affected certain browser versions. template -std::vector> simplificationRuleList( +std::vector> simplificationRuleListPart1( Pattern A, Pattern B, Pattern C, @@ -57,8 +56,7 @@ std::vector> simplificationRuleList( Pattern Y ) { - std::vector> rules; - rules += std::vector>{ + return std::vector> { // arithmetic on constants {{Instruction::ADD, {A, B}}, [=]{ return A.d() + B.d(); }, false}, {{Instruction::MUL, {A, B}}, [=]{ return A.d() * B.d(); }, false}, @@ -162,6 +160,22 @@ std::vector> simplificationRuleList( {{Instruction::OR, {X, {Instruction::NOT, {X}}}}, [=]{ return ~u256(0); }, true}, {{Instruction::OR, {{Instruction::NOT, {X}}, X}}, [=]{ return ~u256(0); }, true}, }; +} + + +// This part of simplificationRuleList below was split out to prevent +// stack overflows in the JavaScript optimizer for emscripten builds +// that affected certain browser versions. +template +std::vector> simplificationRuleListPart2( + Pattern A, + Pattern B, + Pattern, + Pattern X, + Pattern Y +) +{ + std::vector> rules; // Replace MOD X, with AND X, - 1 for (size_t i = 0; i < 256; ++i) @@ -292,5 +306,24 @@ std::vector> simplificationRuleList( return rules; } +/// @returns a list of simplification rules given certain match placeholders. +/// A, B and C should represent constants, X and Y arbitrary expressions. +/// The simplifications should never change the order of evaluation of +/// arbitrary operations. +template +std::vector> simplificationRuleList( + Pattern A, + Pattern B, + Pattern C, + Pattern X, + Pattern Y +) +{ + std::vector> rules; + rules += simplificationRuleListPart1(A, B, C, X, Y); + rules += simplificationRuleListPart2(A, B, C, X, Y); + return rules; +} + } } diff --git a/libevmasm/SimplificationRules.cpp b/libevmasm/SimplificationRules.cpp index 504dbc24..ba13a611 100644 --- a/libevmasm/SimplificationRules.cpp +++ b/libevmasm/SimplificationRules.cpp @@ -21,16 +21,19 @@ * Container for equivalence classes of expressions for use in common subexpression elimination. */ +#include + #include -#include -#include -#include -#include #include #include -#include - #include +#include + +#include +#include + +#include +#include using namespace std; using namespace dev; @@ -54,6 +57,11 @@ SimplificationRule const* Rules::findFirstMatch( return nullptr; } +bool Rules::isInitialized() const +{ + return !m_rules[byte(Instruction::ADD)].empty(); +} + void Rules::addRules(std::vector> const& _rules) { for (auto const& r: _rules) @@ -82,6 +90,7 @@ Rules::Rules() Y.setMatchGroup(5, m_matchGroups); addRules(simplificationRuleList(A, B, C, X, Y)); + assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized."); } Pattern::Pattern(Instruction _instruction, std::vector const& _arguments): diff --git a/libevmasm/SimplificationRules.h b/libevmasm/SimplificationRules.h index 53f7e595..fbe5a2b0 100644 --- a/libevmasm/SimplificationRules.h +++ b/libevmasm/SimplificationRules.h @@ -26,6 +26,8 @@ #include #include +#include + #include #include @@ -53,6 +55,10 @@ public: ExpressionClasses const& _classes ); + /// Checks whether the rulelist is non-empty. This is usually enforced + /// by the constructor, but we had some issues with static initialization. + bool isInitialized() const; + private: void addRules(std::vector> const& _rules); void addRule(SimplificationRule const& _rule); diff --git a/libjulia/optimiser/SimplificationRules.cpp b/libjulia/optimiser/SimplificationRules.cpp index a5e296c3..56cb96ac 100644 --- a/libjulia/optimiser/SimplificationRules.cpp +++ b/libjulia/optimiser/SimplificationRules.cpp @@ -40,6 +40,7 @@ SimplificationRule const* SimplificationRules::findFirstMatch(Expressio return nullptr; static SimplificationRules rules; + assertThrow(rules.isInitialized(), OptimizerException, "Rule list not properly initialized."); FunctionalInstruction const& instruction = boost::get(_expr); for (auto const& rule: rules.m_rules[byte(instruction.instruction)]) @@ -51,6 +52,11 @@ SimplificationRule const* SimplificationRules::findFirstMatch(Expressio return nullptr; } +bool SimplificationRules::isInitialized() const +{ + return !m_rules[byte(solidity::Instruction::ADD)].empty(); +} + void SimplificationRules::addRules(vector> const& _rules) { for (auto const& r: _rules) @@ -79,6 +85,7 @@ SimplificationRules::SimplificationRules() Y.setMatchGroup(5, m_matchGroups); addRules(simplificationRuleList(A, B, C, X, Y)); + assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized."); } Pattern::Pattern(solidity::Instruction _instruction, vector const& _arguments): diff --git a/libjulia/optimiser/SimplificationRules.h b/libjulia/optimiser/SimplificationRules.h index 68b640b1..e35e6466 100644 --- a/libjulia/optimiser/SimplificationRules.h +++ b/libjulia/optimiser/SimplificationRules.h @@ -51,6 +51,9 @@ public: /// groups accordingly. static SimplificationRule const* findFirstMatch(Expression const& _expr); + /// Checks whether the rulelist is non-empty. This is usually enforced + /// by the constructor, but we had some issues with static initialization. + bool isInitialized() const; private: void addRules(std::vector> const& _rules); void addRule(SimplificationRule const& _rule); -- cgit