caching more operations in mergeCache, updated comments, added null chk in front of mergeCache ops.
This commit is contained in:
parent
5455813145
commit
b160a3b14d
|
@ -103,10 +103,21 @@ import java.util.Set;
|
||||||
simple. By launching multiple threads, we can improve the speed of
|
simple. By launching multiple threads, we can improve the speed of
|
||||||
parsing across a large number of files.
|
parsing across a large number of files.
|
||||||
|
|
||||||
This strategy is complex because we bounce back and forth from
|
There is no strict ordering between the amount of input used by
|
||||||
the ATN to the DFA, simultaneously performing predictions and
|
SLL vs LL, which makes it really hard to build a cache for full
|
||||||
extending the DFA according to previously unseen input
|
context. Let's say that we have input A B C that leads to an SLL
|
||||||
sequences.
|
conflict with full context X. That implies that using X we
|
||||||
|
might only use A B but we could also use A B C D to resolve
|
||||||
|
conflict. Input A B C D could predict alternative 1 in one
|
||||||
|
position in the input and A B C E could predict alternative 2 in
|
||||||
|
another position in input. The conflicting SLL configurations
|
||||||
|
could still be non-unique in the full context prediction, which
|
||||||
|
would lead us to requiring more input than the original A B C. To
|
||||||
|
make a prediction cache work, we have to track the exact input used
|
||||||
|
during the previous prediction. That amounts to a cache that maps X
|
||||||
|
to a specific DFA for that context.
|
||||||
|
|
||||||
|
AVOIDING FULL CONTEXT PREDICTION
|
||||||
|
|
||||||
We avoid doing full context retry when the outer context is empty,
|
We avoid doing full context retry when the outer context is empty,
|
||||||
we did not dip into the outer context by falling off the end of the
|
we did not dip into the outer context by falling off the end of the
|
||||||
|
@ -263,6 +274,9 @@ public class ParserATNSimulator<Symbol extends Token> extends ATNSimulator {
|
||||||
* Don't keep around as it wastes huge amounts of memory. DoubleKeyMap
|
* Don't keep around as it wastes huge amounts of memory. DoubleKeyMap
|
||||||
* isn't synchronized but we're ok since two threads shouldn't reuse same
|
* isn't synchronized but we're ok since two threads shouldn't reuse same
|
||||||
* parser/atnsim object because it can only handle one input at a time.
|
* parser/atnsim object because it can only handle one input at a time.
|
||||||
|
* This maps graphs a and b to merged result c. (a,b)->c. We can avoid
|
||||||
|
* the merge if we ever see a and b again. Note that (b,a)->c should
|
||||||
|
* also be examined during cache lookup.
|
||||||
*/
|
*/
|
||||||
protected DoubleKeyMap<PredictionContext,PredictionContext,PredictionContext> mergeCache;
|
protected DoubleKeyMap<PredictionContext,PredictionContext,PredictionContext> mergeCache;
|
||||||
|
|
||||||
|
|
|
@ -156,8 +156,18 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
|
||||||
boolean rootIsWildcard,
|
boolean rootIsWildcard,
|
||||||
DoubleKeyMap<PredictionContext,PredictionContext,PredictionContext> mergeCache)
|
DoubleKeyMap<PredictionContext,PredictionContext,PredictionContext> mergeCache)
|
||||||
{
|
{
|
||||||
|
if ( mergeCache!=null ) {
|
||||||
|
PredictionContext previous = mergeCache.get(a,b);
|
||||||
|
if ( previous!=null ) return previous;
|
||||||
|
previous = mergeCache.get(b,a);
|
||||||
|
if ( previous!=null ) return previous;
|
||||||
|
}
|
||||||
|
|
||||||
PredictionContext rootMerge = mergeRoot(a, b, rootIsWildcard);
|
PredictionContext rootMerge = mergeRoot(a, b, rootIsWildcard);
|
||||||
if ( rootMerge!=null ) return rootMerge;
|
if ( rootMerge!=null ) {
|
||||||
|
if ( mergeCache!=null ) mergeCache.put(a, b, rootMerge);
|
||||||
|
return rootMerge;
|
||||||
|
}
|
||||||
|
|
||||||
if ( a.invokingState==b.invokingState ) { // a == b
|
if ( a.invokingState==b.invokingState ) { // a == b
|
||||||
PredictionContext parent = merge(a.parent, b.parent, rootIsWildcard, mergeCache);
|
PredictionContext parent = merge(a.parent, b.parent, rootIsWildcard, mergeCache);
|
||||||
|
@ -169,6 +179,7 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
|
||||||
// of those graphs. dup a, a' points at merged array
|
// of those graphs. dup a, a' points at merged array
|
||||||
// new joined parent so create new singleton pointing to it, a'
|
// new joined parent so create new singleton pointing to it, a'
|
||||||
PredictionContext a_ = new SingletonPredictionContext(parent, a.invokingState);
|
PredictionContext a_ = new SingletonPredictionContext(parent, a.invokingState);
|
||||||
|
if ( mergeCache!=null ) mergeCache.put(a, b, a_);
|
||||||
return a_;
|
return a_;
|
||||||
}
|
}
|
||||||
else { // a != b payloads differ
|
else { // a != b payloads differ
|
||||||
|
@ -190,6 +201,7 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
|
||||||
}
|
}
|
||||||
PredictionContext[] parents = {singleParent, singleParent};
|
PredictionContext[] parents = {singleParent, singleParent};
|
||||||
PredictionContext a_ = new ArrayPredictionContext(parents, payloads);
|
PredictionContext a_ = new ArrayPredictionContext(parents, payloads);
|
||||||
|
if ( mergeCache!=null ) mergeCache.put(a, b, a_);
|
||||||
return a_;
|
return a_;
|
||||||
}
|
}
|
||||||
// parents differ and can't merge them. Just pack together
|
// parents differ and can't merge them. Just pack together
|
||||||
|
@ -203,6 +215,7 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
|
||||||
parents = new PredictionContext[] {b.parent, a.parent};
|
parents = new PredictionContext[] {b.parent, a.parent};
|
||||||
}
|
}
|
||||||
PredictionContext a_ = new ArrayPredictionContext(parents, payloads);
|
PredictionContext a_ = new ArrayPredictionContext(parents, payloads);
|
||||||
|
if ( mergeCache!=null ) mergeCache.put(a, b, a_);
|
||||||
return a_;
|
return a_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,6 +261,8 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
|
||||||
if ( mergeCache!=null ) {
|
if ( mergeCache!=null ) {
|
||||||
PredictionContext previous = mergeCache.get(a,b);
|
PredictionContext previous = mergeCache.get(a,b);
|
||||||
if ( previous!=null ) return previous;
|
if ( previous!=null ) return previous;
|
||||||
|
previous = mergeCache.get(b,a);
|
||||||
|
if ( previous!=null ) return previous;
|
||||||
}
|
}
|
||||||
|
|
||||||
// merge sorted payloads a + b => M
|
// merge sorted payloads a + b => M
|
||||||
|
|
Loading…
Reference in New Issue