Skip to content

Commit

Permalink
Reworked mutex handling + updated C++ template for a var init
Browse files Browse the repository at this point in the history
- Mutexes have been consolidated. Instead of one per DFA (which can easily get to hundreds of them) we only have one mutex in the Recognizer class and all other parties use this for serialization. It's only about protected the DFA anyway, which is stored in a recognizer (lexer/parser).
- ATNState::getStateType() returns a size_t value now (actually an enum).
- Replaced checks via RTTI for transitions by the (serialization) type of the transition, for simplicity.
- Added some missing initialization for fields in certain ATN state classes.
- Fixed mem leak in DFA by shadowing the s0 field. That way still have a ref to the self created instance, even is s0 was replaced later.
- Added variable init in code generation for a rule context declaration (e.g. for labels).
  • Loading branch information
mike-lischke committed Oct 29, 2016
1 parent c9f85f1 commit f794820
Show file tree
Hide file tree
Showing 43 changed files with 91 additions and 104 deletions.
4 changes: 2 additions & 2 deletions runtime/Cpp/demo/TParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ expr: expr Star expr
| <assoc = right> expr QuestionMark expr Colon expr
| <assoc = right> expr Equal expr
| identifier = id
| flowControl
| INT
| flowControl
| INT
| String
;

Expand Down
6 changes: 3 additions & 3 deletions runtime/Cpp/runtime/src/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ const atn::ATN& Parser::getATNWithBypassAlts() {
throw UnsupportedOperationException("The current parser does not support an ATN with bypass alternatives.");
}

std::lock_guard<std::recursive_mutex> lck(mtx);
std::lock_guard<std::recursive_mutex> lck(_mutex);

// XXX: using the entire serialized ATN as key into the map is a big resource waste.
// How large can that thing become?
Expand Down Expand Up @@ -570,7 +570,7 @@ std::vector<std::string> Parser::getRuleInvocationStack(RuleContext *p) {
std::vector<std::string> Parser::getDFAStrings() {
atn::ParserATNSimulator *simulator = getInterpreter<atn::ParserATNSimulator>();
if (!simulator->decisionToDFA.empty()) {
std::lock_guard<std::recursive_mutex> lck(mtx);
std::lock_guard<std::recursive_mutex> lck(_mutex);

std::vector<std::string> s;
for (size_t d = 0; d < simulator->decisionToDFA.size(); d++) {
Expand All @@ -585,7 +585,7 @@ std::vector<std::string> Parser::getDFAStrings() {
void Parser::dumpDFA() {
atn::ParserATNSimulator *simulator = getInterpreter<atn::ParserATNSimulator>();
if (!simulator->decisionToDFA.empty()) {
std::lock_guard<std::recursive_mutex> lck(mtx);
std::lock_guard<std::recursive_mutex> lck(_mutex);
bool seenOne = false;
for (size_t d = 0; d < simulator->decisionToDFA.size(); d++) {
dfa::DFA &dfa = simulator->decisionToDFA[d];
Expand Down
3 changes: 0 additions & 3 deletions runtime/Cpp/runtime/src/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -421,9 +421,6 @@ namespace antlr4 {

std::vector<int> _precedenceStack;

// Mutex to manage synchronized access for multithreading in the parser
std::recursive_mutex mtx;

/// <summary>
/// Specifies whether or not the parser should construct a parse tree during
/// the parsing process. The default value is {@code true}.
Expand Down
4 changes: 2 additions & 2 deletions runtime/Cpp/runtime/src/Recognizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ dfa::Vocabulary const& Recognizer::getVocabulary() const {
std::map<std::string, size_t> Recognizer::getTokenTypeMap() {
const dfa::Vocabulary& vocabulary = getVocabulary();

std::lock_guard<std::recursive_mutex> lck(mtx);
std::lock_guard<std::recursive_mutex> lck(_mutex);
std::map<std::string, size_t> result;
auto iterator = _tokenTypeMapCache.find(&vocabulary);
if (iterator != _tokenTypeMapCache.end()) {
Expand Down Expand Up @@ -91,7 +91,7 @@ std::map<std::string, size_t> Recognizer::getRuleIndexMap() {
throw "The current recognizer does not provide a list of rule names.";
}

std::lock_guard<std::recursive_mutex> lck(mtx);
std::lock_guard<std::recursive_mutex> lck(_mutex);
std::map<std::string, size_t> result;
auto iterator = _ruleIndexMapCache.find(ruleNames);
if (iterator != _ruleIndexMapCache.end()) {
Expand Down
6 changes: 3 additions & 3 deletions runtime/Cpp/runtime/src/Recognizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,15 @@ namespace antlr4 {
protected:
atn::ATNSimulator *_interpreter; // Set and deleted in descendants (or the profiler).

// Mutex to manage synchronized access for multithreading.
std::recursive_mutex _mutex;

private:
static std::map<const dfa::Vocabulary*, std::map<std::string, size_t>> _tokenTypeMapCache;
static std::map<std::vector<std::string>, std::map<std::string, size_t>> _ruleIndexMapCache;

ProxyErrorListener _proxListener; // Manages a collection of listeners.

// Mutex to manage synchronized access for multithreading.
std::recursive_mutex mtx;

size_t _stateNumber;

void InitializeInstanceFields();
Expand Down
2 changes: 2 additions & 0 deletions runtime/Cpp/runtime/src/atn/ATN.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ ATN::ATN() : ATN(ATNType::LEXER, 0) {
}

ATN::ATN(ATN &&other) {
// All source vectors are implicitly cleared by the moves.
states = std::move(other.states);
decisionToState = std::move(other.decisionToState);
ruleToStartState = std::move(other.ruleToStartState);
Expand Down Expand Up @@ -92,6 +93,7 @@ ATN& ATN::operator = (ATN &other) NOEXCEPT {
* operators it seems the copy operator is preferred causing trouble when releasing the allocated ATNState instances.
*/
ATN& ATN::operator = (ATN &&other) NOEXCEPT {
// All source vectors are implicitly cleared by the moves.
states = std::move(other.states);
decisionToState = std::move(other.decisionToState);
ruleToStartState = std::move(other.ruleToStartState);
Expand Down
2 changes: 1 addition & 1 deletion runtime/Cpp/runtime/src/atn/ATNSimulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ PredictionContextCache& ATNSimulator::getSharedContextCache() {
}

Ref<PredictionContext> ATNSimulator::getCachedContext(Ref<PredictionContext> const& context) {
std::lock_guard<std::recursive_mutex> lck(mtx);
std::lock_guard<std::recursive_mutex> lck(_mutex);
std::map<Ref<PredictionContext>, Ref<PredictionContext>> visited;
return PredictionContext::getCachedContext(context, _sharedContextCache, visited);
}
Expand Down
5 changes: 2 additions & 3 deletions runtime/Cpp/runtime/src/atn/ATNSimulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ namespace atn {
static ATNState *stateFactory(int type, int ruleIndex);

protected:
// Mutex to manage synchronized access for multithreading
std::recursive_mutex mtx;
// Mutex to manage synchronized access for multithreading.
std::recursive_mutex _mutex;

/// <summary>
/// The context cache maps all PredictionContext objects that are equals()
Expand All @@ -106,7 +106,6 @@ namespace atn {
/// so it's not worth the complexity.
/// </summary>
PredictionContextCache &_sharedContextCache;

};

} // namespace atn
Expand Down
3 changes: 1 addition & 2 deletions runtime/Cpp/runtime/src/atn/ATNState.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ namespace atn {

static const std::vector<std::string> serializationNames;

/// Which ATN are we in?
size_t stateNumber = INVALID_STATE_NUMBER;
size_t ruleIndex = 0; // at runtime, we don't have Rule objects
bool epsilonOnlyTransitions = false;
Expand All @@ -143,7 +142,7 @@ namespace atn {
virtual void addTransition(Transition *e);
virtual void addTransition(size_t index, Transition *e);
virtual Transition* removeTransition(size_t index);
virtual int getStateType() = 0;
virtual size_t getStateType() = 0;
};

} // namespace atn
Expand Down
2 changes: 1 addition & 1 deletion runtime/Cpp/runtime/src/atn/BasicBlockStartState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@

using namespace antlr4::atn;

int BasicBlockStartState::getStateType() {
size_t BasicBlockStartState::getStateType() {
return BLOCK_START;
}
2 changes: 1 addition & 1 deletion runtime/Cpp/runtime/src/atn/BasicBlockStartState.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ namespace atn {
class ANTLR4CPP_PUBLIC BasicBlockStartState final : public BlockStartState {

public:
virtual int getStateType() override;
virtual size_t getStateType() override;

};

Expand Down
2 changes: 1 addition & 1 deletion runtime/Cpp/runtime/src/atn/BasicState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@

using namespace antlr4::atn;

int BasicState::getStateType() {
size_t BasicState::getStateType() {
return BASIC;
}
2 changes: 1 addition & 1 deletion runtime/Cpp/runtime/src/atn/BasicState.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace atn {
class ANTLR4CPP_PUBLIC BasicState final : public ATNState {

public:
virtual int getStateType() override;
virtual size_t getStateType() override;

};

Expand Down
2 changes: 1 addition & 1 deletion runtime/Cpp/runtime/src/atn/BlockEndState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ using namespace antlr4::atn;
BlockEndState::BlockEndState() : startState(nullptr) {
}

int BlockEndState::getStateType() {
size_t BlockEndState::getStateType() {
return BLOCK_END;
}
7 changes: 3 additions & 4 deletions runtime/Cpp/runtime/src/atn/BlockEndState.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,14 @@
namespace antlr4 {
namespace atn {

/// <summary>
/// Terminal node of a simple {@code (a|b|c)} block. </summary>
/// Terminal node of a simple {@code (a|b|c)} block.
class ANTLR4CPP_PUBLIC BlockEndState final : public ATNState {
public:
BlockStartState *startState;
BlockStartState *startState = nullptr;

BlockEndState();

virtual int getStateType() override;
virtual size_t getStateType() override;
};

} // namespace atn
Expand Down
5 changes: 2 additions & 3 deletions runtime/Cpp/runtime/src/atn/BlockStartState.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,10 @@
namespace antlr4 {
namespace atn {

/// <summary>
/// The start of a regular {@code (...)} block. </summary>
/// The start of a regular {@code (...)} block.
class ANTLR4CPP_PUBLIC BlockStartState : public DecisionState {
public:
BlockEndState *endState;
BlockEndState *endState = nullptr;
};

} // namespace atn
Expand Down
2 changes: 1 addition & 1 deletion runtime/Cpp/runtime/src/atn/EpsilonTransition.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ namespace atn {

/**
* @return the rule index of a precedence rule for which this transition is
* returning from, where the precedence value is 0; otherwise, -1.
* returning from, where the precedence value is 0; otherwise, INVALID_INDEX.
*
* @see ATNConfig#isPrecedenceFilterSuppressed()
* @see ParserATNSimulator#applyPrecedenceFilter(ATNConfigSet)
Expand Down
13 changes: 7 additions & 6 deletions runtime/Cpp/runtime/src/atn/LL1Analyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ void LL1Analyzer::_LOOK(ATNState *s, ATNState *stopState, Ref<PredictionContext>

lookBusy.insert(c);

if (stopState != nullptr && s == stopState) {
// ml: s can never be null, hence no need to check if stopState is != null.
if (s == stopState) {
if (ctx == nullptr) {
look.add(Token::EPSILON);
return;
Expand All @@ -112,7 +113,7 @@ void LL1Analyzer::_LOOK(ATNState *s, ATNState *stopState, Ref<PredictionContext>
}
}

if (is<RuleStopState *>(s)) {
if (s->getStateType() == ATNState::RULE_STOP) {
if (ctx == nullptr) {
look.add(Token::EPSILON);
return;
Expand Down Expand Up @@ -144,7 +145,7 @@ void LL1Analyzer::_LOOK(ATNState *s, ATNState *stopState, Ref<PredictionContext>
for (size_t i = 0; i < n; i++) {
Transition *t = s->transitions[i];

if (is<RuleTransition *>(t)) {
if (t->getSerializationType() == Transition::RULE) {
if (calledRuleStack[(static_cast<RuleTransition*>(t))->target->ruleIndex]) {
continue;
}
Expand All @@ -165,13 +166,13 @@ void LL1Analyzer::_LOOK(ATNState *s, ATNState *stopState, Ref<PredictionContext>
}
} else if (t->isEpsilon()) {
_LOOK(t->target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF);
} else if (is<WildcardTransition *>(t)) {
look.addAll(misc::IntervalSet::of(Token::MIN_USER_TOKEN_TYPE, (int)_atn.maxTokenType));
} else if (t->getSerializationType() == Transition::WILDCARD) {
look.addAll(misc::IntervalSet::of(Token::MIN_USER_TOKEN_TYPE, (ssize_t)_atn.maxTokenType));
} else {
misc::IntervalSet set = t->label();
if (!set.isEmpty()) {
if (is<NotSetTransition*>(t)) {
set = set.complement(misc::IntervalSet::of(Token::MIN_USER_TOKEN_TYPE, (int)_atn.maxTokenType));
set = set.complement(misc::IntervalSet::of(Token::MIN_USER_TOKEN_TYPE, (ssize_t)_atn.maxTokenType));
}
look.addAll(set);
}
Expand Down
4 changes: 2 additions & 2 deletions runtime/Cpp/runtime/src/atn/LexerATNSimulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ void LexerATNSimulator::addDFAEdge(dfa::DFAState *p, size_t t, dfa::DFAState *q)
return;
}

std::lock_guard<std::recursive_mutex> lck(mtx);
std::lock_guard<std::recursive_mutex> lck(_mutex);
p->edges[t - MIN_DFA_EDGE] = q; // connect
}

Expand Down Expand Up @@ -579,7 +579,7 @@ dfa::DFAState *LexerATNSimulator::addDFAState(ATNConfigSet *configs) {
dfa::DFA &dfa = _decisionToDFA[_mode];

{
std::lock_guard<std::recursive_mutex> lck(mtx);
std::lock_guard<std::recursive_mutex> lck(_mutex);

if (!dfa.states.empty()) {
auto iterator = dfa.states.find(proposed);
Expand Down
2 changes: 1 addition & 1 deletion runtime/Cpp/runtime/src/atn/LoopEndState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@

using namespace antlr4::atn;

int LoopEndState::getStateType() {
size_t LoopEndState::getStateType() {
return LOOP_END;
}
7 changes: 3 additions & 4 deletions runtime/Cpp/runtime/src/atn/LoopEndState.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,12 @@
namespace antlr4 {
namespace atn {

/// <summary>
/// Mark the end of a * or + loop. </summary>
/// Mark the end of a * or + loop.
class ANTLR4CPP_PUBLIC LoopEndState final : public ATNState {
public:
ATNState *loopBackState;
ATNState *loopBackState = nullptr;

virtual int getStateType() override;
virtual size_t getStateType() override;
};

} // namespace atn
Expand Down
6 changes: 3 additions & 3 deletions runtime/Cpp/runtime/src/atn/ParserATNSimulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ size_t ParserATNSimulator::adaptivePredict(TokenStream *input, size_t decision,
dfa.s0->configs = std::move(s0_closure); // not used for prediction but useful to know start configs anyway
dfa::DFAState *newState = new dfa::DFAState(applyPrecedenceFilter(dfa.s0->configs.get())); /* mem-check: managed by the DFA or deleted below */
s0 = addDFAState(dfa, newState);
dfa.setPrecedenceStartState(parser->getPrecedence(), s0);
dfa.setPrecedenceStartState(parser->getPrecedence(), s0, _mutex);
if (s0 != newState) {
delete newState; // If there was already a state with this config set we don't need the new one.
}
Expand Down Expand Up @@ -1182,7 +1182,7 @@ dfa::DFAState *ParserATNSimulator::addDFAEdge(dfa::DFA &dfa, dfa::DFAState *from
}

{
std::lock_guard<std::recursive_mutex> lck(mtx);
std::lock_guard<std::recursive_mutex> lck(_mutex);
from->edges[t] = to; // connect
}

Expand All @@ -1205,7 +1205,7 @@ dfa::DFAState *ParserATNSimulator::addDFAState(dfa::DFA &dfa, dfa::DFAState *D)
}

{
std::lock_guard<std::recursive_mutex> lck(mtx);
std::lock_guard<std::recursive_mutex> lck(_mutex);

auto existing = dfa.states.find(D);
if (existing != dfa.states.end()) {
Expand Down
3 changes: 0 additions & 3 deletions runtime/Cpp/runtime/src/atn/ParserATNSimulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,6 @@ namespace atn {
private:
PredictionMode mode;

// Mutex to manage synchronized access for multithreading in the parser atn simulator.
std::recursive_mutex _lock;

/// <summary>
/// Each prediction operation uses a cache for merge of prediction contexts.
/// Don't keep around as it wastes huge amounts of memory. The merge cache
Expand Down
2 changes: 1 addition & 1 deletion runtime/Cpp/runtime/src/atn/PlusBlockStartState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@

using namespace antlr4::atn;

int PlusBlockStartState::getStateType() {
size_t PlusBlockStartState::getStateType() {
return PLUS_BLOCK_START;
}
12 changes: 5 additions & 7 deletions runtime/Cpp/runtime/src/atn/PlusBlockStartState.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,15 @@
namespace antlr4 {
namespace atn {

/// <summary>
/// Start of {@code (A|B|...)+} loop. Technically a decision state, but
/// we don't use for code generation; somebody might need it, so I'm defining
/// it for completeness. In reality, the <seealso cref="PlusLoopbackState"/> node is the
/// real decision-making note for {@code A+}.
/// </summary>
/// we don't use for code generation; somebody might need it, so I'm defining
/// it for completeness. In reality, the <seealso cref="PlusLoopbackState"/> node is the
/// real decision-making note for {@code A+}.
class ANTLR4CPP_PUBLIC PlusBlockStartState final : public BlockStartState {
public:
PlusLoopbackState *loopBackState;
PlusLoopbackState *loopBackState = nullptr;

virtual int getStateType() override;
virtual size_t getStateType() override;
};

} // namespace atn
Expand Down
2 changes: 1 addition & 1 deletion runtime/Cpp/runtime/src/atn/PlusLoopbackState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@

using namespace antlr4::atn;

int PlusLoopbackState::getStateType() {
size_t PlusLoopbackState::getStateType() {
return PLUS_LOOP_BACK;
}
Loading

0 comments on commit f794820

Please sign in to comment.