Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Go] Port locking algorithm from C++ to Go #3571

Merged
merged 1 commit into from
Mar 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,7 @@ PositionAdjustingLexerDef() ::= ""
PositionAdjustingLexer() ::= <<
func (p *PositionAdjustingLexer) NextToken() antlr.Token {
if _, ok := p.Interpreter.(*PositionAdjustingLexerATNSimulator); !ok {
lexerDeserializer := antlr.NewATNDeserializer(nil)
lexerAtn := lexerDeserializer.DeserializeFromUInt16(serializedLexerAtn)
p.Interpreter = NewPositionAdjustingLexerATNSimulator(p, lexerAtn, p.Interpreter.DecisionToDFA(), p.Interpreter.SharedContextCache())
p.Interpreter = NewPositionAdjustingLexerATNSimulator(p, p.Interpreter.ATN(), p.Interpreter.DecisionToDFA(), p.Interpreter.SharedContextCache())
p.Virt = p
}

Expand Down
21 changes: 14 additions & 7 deletions runtime/Go/antlr/atn.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

package antlr

import "sync"

var ATNInvalidAltNumber int

type ATN struct {
Expand Down Expand Up @@ -37,6 +39,10 @@ type ATN struct {
ruleToTokenType []int

states []ATNState

mu sync.Mutex
stateMu sync.RWMutex
edgeMu sync.RWMutex
}

func NewATN(grammarType int, maxTokenType int) *ATN {
Expand All @@ -59,14 +65,15 @@ func (a *ATN) NextTokensInContext(s ATNState, ctx RuleContext) *IntervalSet {
// in s and staying in same rule. Token.EPSILON is in set if we reach end of
// rule.
func (a *ATN) NextTokensNoContext(s ATNState) *IntervalSet {
if s.GetNextTokenWithinRule() != nil {
return s.GetNextTokenWithinRule()
a.mu.Lock()
defer a.mu.Unlock()
iset := s.GetNextTokenWithinRule()
if iset == nil {
iset = a.NextTokensInContext(s, nil)
iset.readOnly = true
s.SetNextTokenWithinRule(iset)
}

s.SetNextTokenWithinRule(a.NextTokensInContext(s, nil))
s.GetNextTokenWithinRule().readOnly = true

return s.GetNextTokenWithinRule()
return iset
}

func (a *ATN) NextTokens(s ATNState, ctx RuleContext) *IntervalSet {
Expand Down
6 changes: 6 additions & 0 deletions runtime/Go/antlr/atn_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ func NewBasicBlockStartState() *BasicBlockStartState {
return &BasicBlockStartState{BaseBlockStartState: b}
}

var _ BlockStartState = &BasicBlockStartState{}

// BlockEndState is a terminal node of a simple (a|b|c) block.
type BlockEndState struct {
*BaseATNState
Expand Down Expand Up @@ -318,6 +320,8 @@ func NewPlusBlockStartState() *PlusBlockStartState {
return &PlusBlockStartState{BaseBlockStartState: b}
}

var _ BlockStartState = &PlusBlockStartState{}

// StarBlockStartState is the block that begins a closure loop.
type StarBlockStartState struct {
*BaseBlockStartState
Expand All @@ -331,6 +335,8 @@ func NewStarBlockStartState() *StarBlockStartState {
return &StarBlockStartState{BaseBlockStartState: b}
}

var _ BlockStartState = &StarBlockStartState{}

type StarLoopbackState struct {
*BaseATNState
}
Expand Down
34 changes: 12 additions & 22 deletions runtime/Go/antlr/dfa.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ package antlr

import (
"sort"
"sync"
"sync/atomic"
"unsafe"
)

type DFA struct {
Expand All @@ -19,23 +16,28 @@ 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
states map[int]*DFAState

s0 *DFAState

// precedenceDfa is the backing field for isPrecedenceDfa and setPrecedenceDfa.
// True if the DFA is for a precedence decision and false otherwise.
precedenceDfa bool
precedenceDfaMu sync.RWMutex
precedenceDfa bool
}

func NewDFA(atnStartState DecisionState, decision int) *DFA {
return &DFA{
dfa := &DFA{
atnStartState: atnStartState,
decision: decision,
states: make(map[int]*DFAState),
}
if s, ok := atnStartState.(*StarLoopEntryState); ok && s.precedenceRuleDecision {
dfa.precedenceDfa = true
dfa.s0 = NewDFAState(-1, NewBaseATNConfigSet(false))
dfa.s0.isAcceptState = false
dfa.s0.requiresFullContext = false
}
return dfa
}

// getPrecedenceStartState gets the start state for the current precedence and
Expand Down Expand Up @@ -80,8 +82,6 @@ func (d *DFA) setPrecedenceStartState(precedence int, startState *DFAState) {
}

func (d *DFA) getPrecedenceDfa() bool {
d.precedenceDfaMu.RLock()
defer d.precedenceDfaMu.RUnlock()
return d.precedenceDfa
}

Expand All @@ -105,42 +105,32 @@ func (d *DFA) setPrecedenceDfa(precedenceDfa bool) {
d.setS0(nil)
}

d.precedenceDfaMu.Lock()
defer d.precedenceDfaMu.Unlock()
d.precedenceDfa = precedenceDfa
}
}

func (d *DFA) getS0() *DFAState {
return (*DFAState)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.s0))))
return d.s0
}

func (d *DFA) setS0(s *DFAState) {
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.s0)), unsafe.Pointer(s))
d.s0 = s
}

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) setStates(states map[int]*DFAState) {
d.statesMu.Lock()
defer d.statesMu.Unlock()
d.states = states
}

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)
}

Expand Down
14 changes: 1 addition & 13 deletions runtime/Go/antlr/dfa_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package antlr

import (
"fmt"
"sync"
)

// PredPrediction maps a predicate to a predicted alternative.
Expand Down Expand Up @@ -50,8 +49,7 @@ type DFAState struct {

// edges elements point to the target of the symbol. Shift up by 1 so (-1)
// Token.EOF maps to the first element.
edges []*DFAState
edgesMu sync.RWMutex
edges []*DFAState

isAcceptState bool

Expand Down Expand Up @@ -109,32 +107,22 @@ func (d *DFAState) GetAltSet() Set {
}

func (d *DFAState) getEdges() []*DFAState {
d.edgesMu.RLock()
defer d.edgesMu.RUnlock()
return d.edges
}

func (d *DFAState) numEdges() int {
d.edgesMu.RLock()
defer d.edgesMu.RUnlock()
return len(d.edges)
}

func (d *DFAState) getIthEdge(i int) *DFAState {
d.edgesMu.RLock()
defer d.edgesMu.RUnlock()
return d.edges[i]
}

func (d *DFAState) setEdges(newEdges []*DFAState) {
d.edgesMu.Lock()
defer d.edgesMu.Unlock()
d.edges = newEdges
}

func (d *DFAState) setIthEdge(i int, edge *DFAState) {
d.edgesMu.Lock()
defer d.edgesMu.Unlock()
d.edges[i] = edge
}

Expand Down
50 changes: 32 additions & 18 deletions runtime/Go/antlr/lexer_atn_simulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,16 @@ func (l *LexerATNSimulator) Match(input CharStream, mode int) int {

dfa := l.decisionToDFA[mode]

if dfa.getS0() == nil {
var s0 *DFAState
l.atn.stateMu.RLock()
s0 = dfa.getS0()
l.atn.stateMu.RUnlock()

if s0 == nil {
return l.MatchATN(input)
}

return l.execATN(input, dfa.getS0())
return l.execATN(input, s0)
}

func (l *LexerATNSimulator) reset() {
Expand All @@ -117,11 +122,7 @@ func (l *LexerATNSimulator) MatchATN(input CharStream) int {
suppressEdge := s0Closure.hasSemanticContext
s0Closure.hasSemanticContext = false

next := l.addDFAState(s0Closure)

if !suppressEdge {
l.decisionToDFA[l.mode].setS0(next)
}
next := l.addDFAState(s0Closure, suppressEdge)

predict := l.execATN(input, next)

Expand Down Expand Up @@ -203,10 +204,15 @@ func (l *LexerATNSimulator) execATN(input CharStream, ds0 *DFAState) int {
// {@code t}, or {@code nil} if the target state for l edge is not
// already cached
func (l *LexerATNSimulator) getExistingTargetState(s *DFAState, t int) *DFAState {
if s.getEdges() == nil || t < LexerATNSimulatorMinDFAEdge || t > LexerATNSimulatorMaxDFAEdge {
if t < LexerATNSimulatorMinDFAEdge || t > LexerATNSimulatorMaxDFAEdge {
return nil
}

l.atn.edgeMu.RLock()
defer l.atn.edgeMu.RUnlock()
if s.getEdges() == nil {
return nil
}
target := s.getIthEdge(t - LexerATNSimulatorMinDFAEdge)
if LexerATNSimulatorDebug && target != nil {
fmt.Println("reuse state " + strconv.Itoa(s.stateNumber) + " edge to " + strconv.Itoa(target.stateNumber))
Expand Down Expand Up @@ -537,7 +543,7 @@ func (l *LexerATNSimulator) addDFAEdge(from *DFAState, tk int, to *DFAState, cfg
suppressEdge := cfgs.HasSemanticContext()
cfgs.SetHasSemanticContext(false)

to = l.addDFAState(cfgs)
to = l.addDFAState(cfgs, true)

if suppressEdge {
return to
Expand All @@ -551,6 +557,8 @@ func (l *LexerATNSimulator) addDFAEdge(from *DFAState, tk int, to *DFAState, cfg
if LexerATNSimulatorDebug {
fmt.Println("EDGE " + from.String() + " -> " + to.String() + " upon " + strconv.Itoa(tk))
}
l.atn.edgeMu.Lock()
defer l.atn.edgeMu.Unlock()
if from.getEdges() == nil {
// make room for tokens 1..n and -1 masquerading as index 0
from.setEdges(make([]*DFAState, LexerATNSimulatorMaxDFAEdge-LexerATNSimulatorMinDFAEdge+1))
Expand All @@ -564,7 +572,7 @@ func (l *LexerATNSimulator) addDFAEdge(from *DFAState, tk int, to *DFAState, cfg
// configurations already. This method also detects the first
// configuration containing an ATN rule stop state. Later, when
// traversing the DFA, we will know which rule to accept.
func (l *LexerATNSimulator) addDFAState(configs ATNConfigSet) *DFAState {
func (l *LexerATNSimulator) addDFAState(configs ATNConfigSet, suppressEdge bool) *DFAState {

proposed := NewDFAState(-1, configs)
var firstConfigWithRuleStopState ATNConfig
Expand All @@ -585,16 +593,22 @@ func (l *LexerATNSimulator) addDFAState(configs ATNConfigSet) *DFAState {
}
hash := proposed.hash()
dfa := l.decisionToDFA[l.mode]

l.atn.stateMu.Lock()
defer l.atn.stateMu.Unlock()
existing, ok := dfa.getState(hash)
if ok {
return existing
}
newState := proposed
newState.stateNumber = dfa.numStates()
configs.SetReadOnly(true)
newState.configs = configs
dfa.setState(hash, newState)
return newState
proposed = existing
} else {
proposed.stateNumber = dfa.numStates()
configs.SetReadOnly(true)
proposed.configs = configs
dfa.setState(hash, proposed)
}
if !suppressEdge {
dfa.setS0(proposed)
}
return proposed
}

func (l *LexerATNSimulator) getDFA(mode int) *DFA {
Expand Down
Loading