Protect shared DFA state with mutexes
This commit is contained in:
parent
ae3aadce3f
commit
11b4ee61f0
|
@ -4,7 +4,10 @@
|
|||
|
||||
package antlr
|
||||
|
||||
import "sort"
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type DFA struct {
|
||||
// atnStartState is the ATN state in which this was created
|
||||
|
@ -15,8 +18,10 @@ type DFA struct {
|
|||
// states is all the DFA states. Use Map to get the old state back; Set can only
|
||||
// indicate whether it is there.
|
||||
states map[int]*DFAState
|
||||
statesMu sync.RWMutex
|
||||
|
||||
s0 *DFAState
|
||||
s0Mu sync.RWMutex
|
||||
|
||||
// precedenceDfa is the backing field for isPrecedenceDfa and setPrecedenceDfa.
|
||||
// True if the DFA is for a precedence decision and false otherwise.
|
||||
|
@ -40,6 +45,9 @@ func (d *DFA) getPrecedenceStartState(precedence int) *DFAState {
|
|||
panic("only precedence DFAs may contain a precedence start state")
|
||||
}
|
||||
|
||||
d.s0Mu.RLock()
|
||||
defer d.s0Mu.RUnlock()
|
||||
|
||||
// s0.edges is never nil for a precedence DFA
|
||||
if precedence < 0 || precedence >= len(d.s0.edges) {
|
||||
return nil
|
||||
|
@ -59,6 +67,9 @@ func (d *DFA) setPrecedenceStartState(precedence int, startState *DFAState) {
|
|||
return
|
||||
}
|
||||
|
||||
d.s0Mu.Lock()
|
||||
defer d.s0Mu.Unlock()
|
||||
|
||||
// Synchronization on s0 here is ok. When the DFA is turned into a
|
||||
// precedence DFA, s0 will be initialized once and not updated again. s0.edges
|
||||
// is never nil for a precedence DFA.
|
||||
|
@ -93,15 +104,42 @@ func (d *DFA) setPrecedenceDfa(precedenceDfa bool) {
|
|||
}
|
||||
}
|
||||
|
||||
func (d *DFA) GetStates() map[int]*DFAState {
|
||||
return d.states
|
||||
func (d *DFA) getS0() *DFAState {
|
||||
d.s0Mu.RLock()
|
||||
defer d.s0Mu.RUnlock()
|
||||
return d.s0
|
||||
}
|
||||
|
||||
type DFAStateList []*DFAState
|
||||
func (d *DFA) setS0(s *DFAState) {
|
||||
d.s0Mu.Lock()
|
||||
defer d.s0Mu.Unlock()
|
||||
d.s0 = s
|
||||
}
|
||||
|
||||
func (d DFAStateList) Len() int { return len(d) }
|
||||
func (d DFAStateList) Less(i, j int) bool { return d[i].stateNumber < d[j].stateNumber }
|
||||
func (d DFAStateList) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
|
||||
func (d *DFA) getState(hash int) (*DFAState, bool) {
|
||||
d.statesMu.RLock()
|
||||
defer d.statesMu.RUnlock()
|
||||
s, ok := d.states[hash]
|
||||
return s, ok
|
||||
}
|
||||
|
||||
func (d *DFA) setState(hash int, state *DFAState) {
|
||||
d.statesMu.Lock()
|
||||
defer d.statesMu.Unlock()
|
||||
d.states[hash] = state
|
||||
}
|
||||
|
||||
func (d *DFA) numStates() int {
|
||||
d.statesMu.RLock()
|
||||
defer d.statesMu.RUnlock()
|
||||
return len(d.states)
|
||||
}
|
||||
|
||||
type dfaStateList []*DFAState
|
||||
|
||||
func (d dfaStateList) Len() int { return len(d) }
|
||||
func (d dfaStateList) Less(i, j int) bool { return d[i].stateNumber < d[j].stateNumber }
|
||||
func (d dfaStateList) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
|
||||
|
||||
// sortedStates returns the states in d sorted by their state number.
|
||||
func (d *DFA) sortedStates() []*DFAState {
|
||||
|
@ -111,7 +149,7 @@ func (d *DFA) sortedStates() []*DFAState {
|
|||
vs = append(vs, v)
|
||||
}
|
||||
|
||||
sort.Sort(DFAStateList(vs))
|
||||
sort.Sort(dfaStateList(vs))
|
||||
|
||||
return vs
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ func (l *LexerATNSimulator) MatchATN(input CharStream) int {
|
|||
next := l.addDFAState(s0Closure)
|
||||
|
||||
if !suppressEdge {
|
||||
l.decisionToDFA[l.mode].s0 = next
|
||||
l.decisionToDFA[l.mode].setS0(next)
|
||||
}
|
||||
|
||||
predict := l.execATN(input, next)
|
||||
|
@ -584,15 +584,15 @@ func (l *LexerATNSimulator) addDFAState(configs ATNConfigSet) *DFAState {
|
|||
}
|
||||
hash := proposed.hash()
|
||||
dfa := l.decisionToDFA[l.mode]
|
||||
existing := dfa.GetStates()[hash]
|
||||
if existing != nil {
|
||||
existing, ok := dfa.getState(hash)
|
||||
if ok {
|
||||
return existing
|
||||
}
|
||||
newState := proposed
|
||||
newState.stateNumber = len(dfa.GetStates())
|
||||
newState.stateNumber = dfa.numStates()
|
||||
configs.SetReadOnly(true)
|
||||
newState.configs = configs
|
||||
dfa.GetStates()[hash] = newState
|
||||
dfa.setState(hash, newState)
|
||||
return newState
|
||||
}
|
||||
|
||||
|
|
|
@ -686,7 +686,7 @@ func (p *BaseParser) GetDFAStrings() string {
|
|||
func (p *BaseParser) DumpDFA() {
|
||||
seenOne := false
|
||||
for _, dfa := range p.Interpreter.decisionToDFA {
|
||||
if len(dfa.GetStates()) > 0 {
|
||||
if dfa.numStates() > 0 {
|
||||
if seenOne {
|
||||
fmt.Println()
|
||||
}
|
||||
|
|
|
@ -1416,25 +1416,25 @@ func (p *ParserATNSimulator) addDFAEdge(dfa *DFA, from *DFAState, t int, to *DFA
|
|||
// state if {@code D} is already in the DFA, or {@code D} itself if the
|
||||
// state was not already present.
|
||||
//
|
||||
func (p *ParserATNSimulator) addDFAState(dfa *DFA, D *DFAState) *DFAState {
|
||||
if D == ATNSimulatorError {
|
||||
return D
|
||||
func (p *ParserATNSimulator) addDFAState(dfa *DFA, d *DFAState) *DFAState {
|
||||
if d == ATNSimulatorError {
|
||||
return d
|
||||
}
|
||||
hash := D.hash()
|
||||
var existing, ok = dfa.GetStates()[hash]
|
||||
hash := d.hash()
|
||||
existing, ok := dfa.getState(hash)
|
||||
if ok {
|
||||
return existing
|
||||
}
|
||||
D.stateNumber = len(dfa.GetStates())
|
||||
if !D.configs.ReadOnly() {
|
||||
D.configs.OptimizeConfigs(p.BaseATNSimulator)
|
||||
D.configs.SetReadOnly(true)
|
||||
d.stateNumber = dfa.numStates()
|
||||
if !d.configs.ReadOnly() {
|
||||
d.configs.OptimizeConfigs(p.BaseATNSimulator)
|
||||
d.configs.SetReadOnly(true)
|
||||
}
|
||||
dfa.GetStates()[hash] = D
|
||||
dfa.setState(hash, d)
|
||||
if ParserATNSimulatorDebug {
|
||||
fmt.Println("adding NewDFA state: " + D.String())
|
||||
fmt.Println("adding NewDFA state: " + d.String())
|
||||
}
|
||||
return D
|
||||
return d
|
||||
}
|
||||
|
||||
func (p *ParserATNSimulator) ReportAttemptingFullContext(dfa *DFA, conflictingAlts *BitSet, configs ATNConfigSet, startIndex, stopIndex int) {
|
||||
|
|
Loading…
Reference in New Issue