Skip to content

[C# runtime] Parser.Profile = true causes crash, v4.7.2. #2693

@kaby76

Description

@kaby76

I've been looking at the three Java grammars, and tested each of them on 40k+ Java files (it took weeks to run). In order to figure out where some of the performance problems are, I decided to turn on the Parser.Profile option to get some diagnostics. Unfortunately, the parse crashed on a null ptr deref. I traced it down to a version skew between the Java runtime and the C# runtime. It looks like the last time the C# code was generated from the Java code by Sharpen was prior to 2014, and it seemed to have included this problem. I updated the C# runtime to correspond to what the Java runtime code is currently, and Profile=true works great now.

Here are the diffs. The file ProfilingATNSimulator.cs had evil tabs in it, so I converted them to spaces, which git diff doesn't diff very well. I'm going to make a pull request for this change.

diff --git a/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/AmbiguityInfo.cs b/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/AmbiguityInfo.cs
index fbe0bd7e8..7433c6d52 100644
--- a/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/AmbiguityInfo.cs
+++ b/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/AmbiguityInfo.cs
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+/* Copyright (c) 2012-2019 The ANTLR Project. All rights reserved.
  * Use of this file is governed by the BSD 3-clause license that
  * can be found in the LICENSE.txt file in the project root.
  */
@@ -41,6 +41,9 @@ namespace Antlr4.Runtime.Atn
     /// <since>4.3</since>
     public class AmbiguityInfo : DecisionEventInfo
     {
+        /** The set of alternative numbers for this decision event that lead to a valid parse. */
+        public BitSet ambigAlts;
+
     /// <summary>
     /// Constructs a new instance of the
     /// <see cref="AmbiguityInfo"/>
@@ -48,19 +51,31 @@ namespace Antlr4.Runtime.Atn
     /// specified detailed ambiguity information.
     /// </summary>
     /// <param name="decision">The decision number</param>
-        /// <param name="state">
-        /// The final simulator state identifying the ambiguous
+        /// <param name="configs">The final configuration set identifying the ambiguous
     /// alternatives for the current input
     /// </param>
+        /// <param name="ambigAlts">The set of alternatives in the decision that lead to a valid parse.
+        /// </param>
+        /// The predicted alt is the min(ambigAlts)
+        /// </param>
     /// <param name="input">The input token stream</param>
     /// <param name="startIndex">The start index for the current prediction</param>
     /// <param name="stopIndex">
     /// The index at which the ambiguity was identified during
     /// prediction
     /// </param>
-        public AmbiguityInfo(int decision, SimulatorState state, ITokenStream input, int startIndex, int stopIndex)
-            : base(decision, state, input, startIndex, stopIndex, state.useContext)
+        /// <param name="fullCtx">@code true} if the ambiguity was identified during LL
+        /// prediction; otherwise, {@code false} if the ambiguity was identified
+        /// during SLL prediction
+        /// </param>
+        public AmbiguityInfo(int decision,
+                 ATNConfigSet configs,
+                 BitSet ambigAlts,
+                 ITokenStream input, int startIndex, int stopIndex,
+                 bool fullCtx)
+        : base(decision, configs, input, startIndex, stopIndex, fullCtx)
     {
+            this.ambigAlts = ambigAlts;
     }
     }
 }
diff --git a/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/ContextSensitivityInfo.cs b/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/ContextSensitivityInfo.cs
index b978c6786..454a72ef5 100644
--- a/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/ContextSensitivityInfo.cs
+++ b/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/ContextSensitivityInfo.cs
@@ -35,9 +35,8 @@ namespace Antlr4.Runtime.Atn
     /// with the specified detailed context sensitivity information.
     /// </summary>
     /// <param name="decision">The decision number</param>
-        /// <param name="state">
-        /// The final simulator state containing the unique
-        /// alternative identified by full-context prediction
+        /// <param name="configs">The final configuration set identifying the ambiguous
+        /// alternatives for the current input
     /// </param>
     /// <param name="input">The input token stream</param>
     /// <param name="startIndex">The start index for the current prediction</param>
@@ -45,8 +44,8 @@ namespace Antlr4.Runtime.Atn
     /// The index at which the context sensitivity was
     /// identified during full-context prediction
     /// </param>
-        public ContextSensitivityInfo(int decision, SimulatorState state, ITokenStream input, int startIndex, int stopIndex)
-            : base(decision, state, input, startIndex, stopIndex, true)
+        public ContextSensitivityInfo(int decision, ATNConfigSet configs, ITokenStream input, int startIndex, int stopIndex)
+            : base(decision, configs, input, startIndex, stopIndex, true)
     {
     }
     }
diff --git a/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/DecisionEventInfo.cs b/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/DecisionEventInfo.cs
index ee2098cb7..c77629dd1 100644
--- a/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/DecisionEventInfo.cs
+++ b/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/DecisionEventInfo.cs
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+/* Copyright (c) 2012-2019 The ANTLR Project. All rights reserved.
  * Use of this file is governed by the BSD 3-clause license that
  * can be found in the LICENSE.txt file in the project root.
  */
@@ -25,15 +25,13 @@ namespace Antlr4.Runtime.Atn
     /// <seealso cref="ATN.decisionToState"/>
     public readonly int decision;

-        /// <summary>
-        /// The simulator state containing additional information relevant to the
-        /// prediction state when the current event occurred, or
-        /// <see langword="null"/>
-        /// if no
-        /// additional information is relevant or available.
-        /// </summary>
-        [Nullable]
-        public readonly SimulatorState state;
+        /// <summary>The configuration set containing additional information relevant to the
+        /// prediction state when the current event occurred, or {@code null} if no
+        /// additional information is relevant or available.</summary>
+        /// <remarks>The configuration set containing additional information relevant to the
+        /// prediction state when the current event occurred, or {@code null} if no
+        /// additional information is relevant or available.</remarks>
+        public readonly ATNConfigSet configs;

     /// <summary>The input token stream which is being parsed.</summary>
     /// <remarks>The input token stream which is being parsed.</remarks>
@@ -63,14 +61,17 @@ namespace Antlr4.Runtime.Atn
     /// </summary>
     public readonly bool fullCtx;

-        public DecisionEventInfo(int decision, SimulatorState state, ITokenStream input, int startIndex, int stopIndex, bool fullCtx)
+        public DecisionEventInfo(int decision,
+            ATNConfigSet configs,
+            ITokenStream input, int startIndex, int stopIndex,
+            bool fullCtx)
     {
         this.decision = decision;
         this.fullCtx = fullCtx;
         this.stopIndex = stopIndex;
         this.input = input;
         this.startIndex = startIndex;
-            this.state = state;
+            this.configs = configs;
     }
     }
 }
diff --git a/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/ErrorInfo.cs b/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/ErrorInfo.cs
index 91466fa55..ce8bdfcd3 100644
--- a/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/ErrorInfo.cs
+++ b/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/ErrorInfo.cs
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+/* Copyright (c) 2012-2019 The ANTLR Project. All rights reserved.
  * Use of this file is governed by the BSD 3-clause license that
  * can be found in the LICENSE.txt file in the project root.
  */
@@ -30,17 +30,18 @@ namespace Antlr4.Runtime.Atn
     /// specified detailed syntax error information.
     /// </summary>
     /// <param name="decision">The decision number</param>
-        /// <param name="state">
-        /// The final simulator state reached during prediction
-        /// prior to reaching the
-        /// <see cref="ATNSimulator.ERROR"/>
-        /// state
+        /// <param name="configs">The final configuration set reached during prediction
+        /// prior to reaching the {@link ATNSimulator#ERROR} state
     /// </param>
     /// <param name="input">The input token stream</param>
     /// <param name="startIndex">The start index for the current prediction</param>
     /// <param name="stopIndex">The index at which the syntax error was identified</param>
-        public ErrorInfo(int decision, SimulatorState state, ITokenStream input, int startIndex, int stopIndex)
-            : base(decision, state, input, startIndex, stopIndex, state.useContext)
+        /// <param name="fullCtx">{@code true} if the syntax error was identified during LL
+        /// prediction; otherwise, {@code false} if the syntax error was identified
+        /// during SLL prediction
+        /// </param>
+        public ErrorInfo(int decision, ATNConfigSet configs, ITokenStream input, int startIndex, int stopIndex, bool fullCtx)
+            : base(decision, configs, input, startIndex, stopIndex, fullCtx)
     {
     }
     }
diff --git a/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/LookaheadEventInfo.cs b/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/LookaheadEventInfo.cs
index 2b5e3f30a..a77b017aa 100644
--- a/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/LookaheadEventInfo.cs
+++ b/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/LookaheadEventInfo.cs
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+/* Copyright (c) 2012-2019 The ANTLR Project. All rights reserved.
  * Use of this file is governed by the BSD 3-clause license that
  * can be found in the LICENSE.txt file in the project root.
  */
@@ -19,6 +19,13 @@ namespace Antlr4.Runtime.Atn
     /// <since>4.3</since>
     public class LookaheadEventInfo : DecisionEventInfo
     {
+        /// <summary>The alternative chosen by adaptivePredict(), not necessarily
+        ///  the outermost alt shown for a rule; left-recursive rules have
+        ///  user-level alts that differ from the rewritten rule with a (...) block
+        ///  and a (..)* loop.
+        /// </summary>
+        public int predictedAlt;
+
     /// <summary>
     /// Constructs a new instance of the
     /// <see cref="LookaheadEventInfo"/>
@@ -26,18 +33,14 @@ namespace Antlr4.Runtime.Atn
     /// the specified detailed lookahead information.
     /// </summary>
     /// <param name="decision">The decision number</param>
-        /// <param name="state">
-        /// The final simulator state containing the necessary
-        /// information to determine the result of a prediction, or
-        /// <see langword="null"/>
-        /// if
-        /// the final state is not available
+        /// <param name="configs">The final configuration set containing the necessary
+        /// information to determine the result of a prediction, or {@code null} if
+        /// the final configuration set is not available
     /// </param>
     /// <param name="input">The input token stream</param>
     /// <param name="startIndex">The start index for the current prediction</param>
     /// <param name="stopIndex">The index at which the prediction was finally made</param>
     /// <param name="fullCtx">
-        ///
     /// <see langword="true"/>
     /// if the current lookahead is part of an LL
     /// prediction; otherwise,
@@ -45,9 +48,10 @@ namespace Antlr4.Runtime.Atn
     /// if the current lookahead is part of
     /// an SLL prediction
     /// </param>
-        public LookaheadEventInfo(int decision, SimulatorState state, ITokenStream input, int startIndex, int stopIndex, bool fullCtx)
-            : base(decision, state, input, startIndex, stopIndex, fullCtx)
+        public LookaheadEventInfo(int decision, ATNConfigSet configs, int predictedAlt, ITokenStream input, int startIndex, int stopIndex, bool fullCtx)
+            : base(decision, configs, input, startIndex, stopIndex, fullCtx)
     {
+            this.predictedAlt = predictedAlt;
     }
     }
 }
diff --git a/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/PredicateEvalInfo.cs b/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/PredicateEvalInfo.cs
index 467ac40f2..52889f30c 100644
--- a/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/PredicateEvalInfo.cs
+++ b/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/PredicateEvalInfo.cs
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+/* Copyright (c) 2012-2019 The ANTLR Project. All rights reserved.
  * Use of this file is governed by the BSD 3-clause license that
  * can be found in the LICENSE.txt file in the project root.
  */
@@ -49,7 +49,6 @@ namespace Antlr4.Runtime.Atn
     /// class with the
     /// specified detailed predicate evaluation information.
     /// </summary>
-        /// <param name="state">The simulator state</param>
     /// <param name="decision">The decision number</param>
     /// <param name="input">The input token stream</param>
     /// <param name="startIndex">The start index for the current prediction</param>
@@ -68,10 +67,15 @@ namespace Antlr4.Runtime.Atn
     /// <see cref="predictedAlt"/>
     /// for more information.
     /// </param>
+        /// <param name="fullCtx">{@code true} if the semantic context was
+        /// evaluated during LL prediction; otherwise, {@code false} if the semantic
+        /// context was evaluated during SLL prediction
+        /// </param>
+        ///
     /// <seealso cref="ParserATNSimulator.EvalSemanticContext(SemanticContext, ParserRuleContext, int, bool)"/>
     /// <seealso cref="SemanticContext.Eval"/>
-        public PredicateEvalInfo(SimulatorState state, int decision, ITokenStream input, int startIndex, int stopIndex, SemanticContext semctx, bool evalResult, int predictedAlt)
-            : base(decision, state, input, startIndex, stopIndex, state.useContext)
+        public PredicateEvalInfo(int decision, ITokenStream input, int startIndex, int stopIndex, SemanticContext semctx, bool evalResult, int predictedAlt, bool fullCtx)
+            : base(decision, new ATNConfigSet(), input, startIndex, stopIndex, fullCtx)
     {
         this.semctx = semctx;
         this.evalResult = evalResult;
diff --git a/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/ProfilingATNSimulator.cs b/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/ProfilingATNSimulator.cs
index 8c5ac6b99..9184a2dc6 100644
--- a/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/ProfilingATNSimulator.cs
+++ b/runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Atn/ProfilingATNSimulator.cs
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+/* Copyright (c) 2012-2019 The ANTLR Project. All rights reserved.
  * Use of this file is governed by the BSD 3-clause license that
  * can be found in the LICENSE.txt file in the project root.
  */
@@ -9,234 +9,234 @@ using Antlr4.Runtime.Sharpen;
 namespace Antlr4.Runtime.Atn
 {

-   /**
-    * @since 4.3
-    */
-   public class ProfilingATNSimulator : ParserATNSimulator
-   {
-   protected readonly DecisionInfo[] decisions;
-   protected int numDecisions;
-
-       protected int sllStopIndex;
-       protected int llStopIndex;
-
-   protected int currentDecision;
-   protected DFAState currentState;
-
-   /** At the point of LL failover, we record how SLL would resolve the conflict so that
-    *  we can determine whether or not a decision / input pair is context-sensitive.
-    *  If LL gives a different result than SLL's predicted alternative, we have a
-    *  context sensitivity for sure. The converse is not necessarily true, however.
-    *  It's possible that after conflict resolution chooses minimum alternatives,
-    *  SLL could get the same answer as LL. Regardless of whether or not the result indicates
-    *  an ambiguity, it is not treated as a context sensitivity because LL prediction
-    *  was not required in order to produce a correct prediction for this decision and input sequence.
-    *  It may in fact still be a context sensitivity but we don't know by looking at the
-    *  minimum alternatives for the current input.
-    */
-   protected int conflictingAltResolvedBySLL;
-
-   public ProfilingATNSimulator(Parser parser)
-
-       : base(parser,
-               parser.Interpreter.atn,
-               parser.Interpreter.decisionToDFA,
-              parser.Interpreter.getSharedContextCache())
-       {
-           numDecisions = atn.decisionToState.Count;
-       decisions = new DecisionInfo[numDecisions];
-       for (int i = 0; i < numDecisions; i++)
-       {
-           decisions[i] = new DecisionInfo(i);
-       }
-   }
-
-   public override int AdaptivePredict(ITokenStream input, int decision, ParserRuleContext outerContext)
-   {
-       try
-       {
-           this.sllStopIndex = -1;
-           this.llStopIndex = -1;
-           this.currentDecision = decision;
-               long start = DateTime.Now.ToFileTime(); // expensive but useful info
-           int alt = base.AdaptivePredict(input, decision, outerContext);
-           long stop = DateTime.Now.ToFileTime();
-           decisions[decision].timeInPrediction += (stop - start);
-           decisions[decision].invocations++;
-
-           int SLL_k = sllStopIndex - startIndex + 1;
-           decisions[decision].SLL_TotalLook += SLL_k;
-           decisions[decision].SLL_MinLook = decisions[decision].SLL_MinLook == 0 ? SLL_k : Math.Min(decisions[decision].SLL_MinLook, SLL_k);
-           if (SLL_k > decisions[decision].SLL_MaxLook)
-           {
-               decisions[decision].SLL_MaxLook = SLL_k;
-               decisions[decision].SLL_MaxLookEvent =
-                       new LookaheadEventInfo(decision, null/*, alt*/, input, startIndex, sllStopIndex, false);
-           }
-
-           if (llStopIndex >= 0)
-           {
-               int LL_k = llStopIndex - startIndex + 1;
-               decisions[decision].LL_TotalLook += LL_k;
-               decisions[decision].LL_MinLook = decisions[decision].LL_MinLook == 0 ? LL_k : Math.Min(decisions[decision].LL_MinLook, LL_k);
-               if (LL_k > decisions[decision].LL_MaxLook)
-               {
-                   decisions[decision].LL_MaxLook = LL_k;
-                   decisions[decision].LL_MaxLookEvent =
-                           new LookaheadEventInfo(decision, null/*, alt*/, input, startIndex, llStopIndex, true);
-               }
-           }
-
-           return alt;
-       }
-       finally
-       {
-           this.currentDecision = -1;
-       }
-   }
-
-   protected override DFAState GetExistingTargetState(DFAState previousD, int t)
-   {
-       // this method is called after each time the input position advances
-       // during SLL prediction
-       sllStopIndex = input.Index;
-
-       DFAState existingTargetState = base.GetExistingTargetState(previousD, t);
-       if (existingTargetState != null)
-       {
-           decisions[currentDecision].SLL_DFATransitions++; // count only if we transition over a DFA state
-           if (existingTargetState == ERROR)
-           {
-               decisions[currentDecision].errors.Add(
-                       new ErrorInfo(currentDecision, null /*previousD.configs*/, input, startIndex, sllStopIndex)
-               );
-           }
-       }
-
-       currentState = existingTargetState;
-       return existingTargetState;
-   }
-
-   protected override DFAState ComputeTargetState(DFA dfa, DFAState previousD, int t)
-   {
-       DFAState state = base.ComputeTargetState(dfa, previousD, t);
-       currentState = state;
-       return state;
-   }
-
-   protected override ATNConfigSet ComputeReachSet(ATNConfigSet closure, int t, bool fullCtx)
-   {
-       if (fullCtx)
-       {
-           // this method is called after each time the input position advances
-           // during full context prediction
-           llStopIndex = input.Index;
-       }
-
-       ATNConfigSet reachConfigs = base.ComputeReachSet(closure, t, fullCtx);
-       if (fullCtx)
-       {
-           decisions[currentDecision].LL_ATNTransitions++; // count computation even if error
-           if (reachConfigs != null)
-           {
-           }
-           else { // no reach on current lookahead symbol. ERROR.
-                  // TODO: does not handle delayed errors per getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule()
-               decisions[currentDecision].errors.Add(
-                   new ErrorInfo(currentDecision, null /*closure*/, input, startIndex, llStopIndex)
-               );
-           }
-       }
-       else {
-           decisions[currentDecision].SLL_ATNTransitions++;
-           if (reachConfigs != null)
-           {
-           }
-           else { // no reach on current lookahead symbol. ERROR.
-               decisions[currentDecision].errors.Add(
-                   new ErrorInfo(currentDecision, null /*closure*/, input, startIndex, sllStopIndex)
-               );
-           }
-       }
-       return reachConfigs;
-   }
-
-   protected override bool EvalSemanticContext(SemanticContext pred, ParserRuleContext parserCallStack, int alt, bool fullCtx)
-   {
-       bool result = base.EvalSemanticContext(pred, parserCallStack, alt, fullCtx);
-       if (!(pred is SemanticContext.PrecedencePredicate)) {
-           bool fullContext = llStopIndex >= 0;
-           int stopIndex = fullContext ? llStopIndex : sllStopIndex;
-           decisions[currentDecision].predicateEvals.Add(
-               new PredicateEvalInfo(null , currentDecision, input, startIndex, stopIndex, pred, result, alt/*, fullCtx*/)
-           );
-       }
-
-       return result;
-   }
-
-   protected override void ReportAttemptingFullContext(DFA dfa, BitSet conflictingAlts, ATNConfigSet configs, int startIndex, int stopIndex)
-   {
-       if (conflictingAlts != null)
-       {
-           conflictingAltResolvedBySLL = conflictingAlts.NextSetBit(0);
-       }
-       else {
-               conflictingAltResolvedBySLL = configs.GetAlts().NextSetBit(0);
-       }
-       decisions[currentDecision].LL_Fallback++;
-       base.ReportAttemptingFullContext(dfa, conflictingAlts, configs, startIndex, stopIndex);
-   }
-
-   protected override void ReportContextSensitivity(DFA dfa, int prediction, ATNConfigSet configs, int startIndex, int stopIndex)
-   {
-       if (prediction != conflictingAltResolvedBySLL)
-       {
-           decisions[currentDecision].contextSensitivities.Add(
-                   new ContextSensitivityInfo(currentDecision, null /*configs*/, input, startIndex, stopIndex)
-           );
-       }
-           base.ReportContextSensitivity(dfa, prediction, configs, startIndex, stopIndex);
-   }
-
-   protected override void ReportAmbiguity(DFA dfa, DFAState D, int startIndex, int stopIndex, bool exact,
-                                           BitSet ambigAlts, ATNConfigSet configSet)
-   {
-       int prediction;
-       if (ambigAlts != null)
-       {
-           prediction = ambigAlts.NextSetBit(0);
-       }
-       else {
-               prediction = configSet.GetAlts().NextSetBit(0);
-       }
-           if (configSet.fullCtx && prediction != conflictingAltResolvedBySLL)
-       {
-           // Even though this is an ambiguity we are reporting, we can
-           // still detect some context sensitivities.  Both SLL and LL
-           // are showing a conflict, hence an ambiguity, but if they resolve
-           // to different minimum alternatives we have also identified a
-           // context sensitivity.
-           decisions[currentDecision].contextSensitivities.Add( new ContextSensitivityInfo(currentDecision, null /*configs*/, input, startIndex, stopIndex) );
-       }
-       decisions[currentDecision].ambiguities.Add(
-           new AmbiguityInfo(currentDecision, null /*configs, ambigAlts*/,
-                             input, startIndex, stopIndex/*, configs.IsFullContext*/)
-       );
-       base.ReportAmbiguity(dfa, D, startIndex, stopIndex, exact, ambigAlts, configSet);
-   }
-
-   // ---------------------------------------------------------------------
-
-   public DecisionInfo[] getDecisionInfo()
-   {
-       return decisions;
-   }
-
-   public DFAState getCurrentState()
-   {
-       return currentState;
-   }
+    /**
+     * @since 4.3
+     */
+    public class ProfilingATNSimulator : ParserATNSimulator
+    {
+        protected readonly DecisionInfo[] decisions;
+        protected int numDecisions;
+
+        protected int sllStopIndex;
+        protected int llStopIndex;
+
+        protected int currentDecision;
+        protected DFAState currentState;
+
+        /** At the point of LL failover, we record how SLL would resolve the conflict so that
+         *  we can determine whether or not a decision / input pair is context-sensitive.
+         *  If LL gives a different result than SLL's predicted alternative, we have a
+         *  context sensitivity for sure. The converse is not necessarily true, however.
+         *  It's possible that after conflict resolution chooses minimum alternatives,
+         *  SLL could get the same answer as LL. Regardless of whether or not the result indicates
+         *  an ambiguity, it is not treated as a context sensitivity because LL prediction
+         *  was not required in order to produce a correct prediction for this decision and input sequence.
+         *  It may in fact still be a context sensitivity but we don't know by looking at the
+         *  minimum alternatives for the current input.
+         */
+        protected int conflictingAltResolvedBySLL;
+
+        public ProfilingATNSimulator(Parser parser)
+
+        : base(parser,
+               parser.Interpreter.atn,
+               parser.Interpreter.decisionToDFA,
+               parser.Interpreter.getSharedContextCache())
+        {
+            numDecisions = atn.decisionToState.Count;
+            decisions = new DecisionInfo[numDecisions];
+            for (int i = 0; i < numDecisions; i++)
+            {
+                decisions[i] = new DecisionInfo(i);
+            }
+        }
+
+    public override int AdaptivePredict(ITokenStream input, int decision, ParserRuleContext outerContext)
+    {
+        try
+        {
+            this.sllStopIndex = -1;
+            this.llStopIndex = -1;
+            this.currentDecision = decision;
+            long start = DateTime.Now.ToFileTime(); // expensive but useful info
+            int alt = base.AdaptivePredict(input, decision, outerContext);
+            long stop = DateTime.Now.ToFileTime();
+            decisions[decision].timeInPrediction += (stop - start);
+            decisions[decision].invocations++;
+
+            int SLL_k = sllStopIndex - startIndex + 1;
+            decisions[decision].SLL_TotalLook += SLL_k;
+            decisions[decision].SLL_MinLook = decisions[decision].SLL_MinLook == 0 ? SLL_k : Math.Min(decisions[decision].SLL_MinLook, SLL_k);
+            if (SLL_k > decisions[decision].SLL_MaxLook)
+            {
+                decisions[decision].SLL_MaxLook = SLL_k;
+                decisions[decision].SLL_MaxLookEvent =
+                    new LookaheadEventInfo(decision, null, alt, input, startIndex, sllStopIndex, false);
+            }
+
+            if (llStopIndex >= 0)
+            {
+                int LL_k = llStopIndex - startIndex + 1;
+                decisions[decision].LL_TotalLook += LL_k;
+                decisions[decision].LL_MinLook = decisions[decision].LL_MinLook == 0 ? LL_k : Math.Min(decisions[decision].LL_MinLook, LL_k);
+                if (LL_k > decisions[decision].LL_MaxLook)
+                {
+                    decisions[decision].LL_MaxLook = LL_k;
+                    decisions[decision].LL_MaxLookEvent =
+                        new LookaheadEventInfo(decision, null, alt, input, startIndex, llStopIndex, true);
+                }
+            }
+
+            return alt;
+        }
+        finally
+        {
+            this.currentDecision = -1;
+        }
+    }
+
+    protected override DFAState GetExistingTargetState(DFAState previousD, int t)
+    {
+        // this method is called after each time the input position advances
+        // during SLL prediction
+        sllStopIndex = input.Index;
+
+        DFAState existingTargetState = base.GetExistingTargetState(previousD, t);
+        if (existingTargetState != null)
+        {
+            decisions[currentDecision].SLL_DFATransitions++; // count only if we transition over a DFA state
+            if (existingTargetState == ERROR)
+            {
+                decisions[currentDecision].errors.Add(
+                    new ErrorInfo(currentDecision, previousD.configSet, input, startIndex, sllStopIndex, false)
+                );
+            }
+        }
+
+        currentState = existingTargetState;
+        return existingTargetState;
+    }
+
+    protected override DFAState ComputeTargetState(DFA dfa, DFAState previousD, int t)
+    {
+        DFAState state = base.ComputeTargetState(dfa, previousD, t);
+        currentState = state;
+        return state;
+    }
+
+    protected override ATNConfigSet ComputeReachSet(ATNConfigSet closure, int t, bool fullCtx)
+    {
+        if (fullCtx)
+        {
+            // this method is called after each time the input position advances
+            // during full context prediction
+            llStopIndex = input.Index;
+        }
+
+        ATNConfigSet reachConfigs = base.ComputeReachSet(closure, t, fullCtx);
+        if (fullCtx)
+        {
+            decisions[currentDecision].LL_ATNTransitions++; // count computation even if error
+            if (reachConfigs != null)
+            {
+            }
+            else { // no reach on current lookahead symbol. ERROR.
+                   // TODO: does not handle delayed errors per getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule()
+                decisions[currentDecision].errors.Add(
+                    new ErrorInfo(currentDecision, closure, input, startIndex, llStopIndex, true)
+                );
+            }
+        }
+        else {
+            decisions[currentDecision].SLL_ATNTransitions++;
+            if (reachConfigs != null)
+            {
+            }
+            else { // no reach on current lookahead symbol. ERROR.
+                decisions[currentDecision].errors.Add(
+                    new ErrorInfo(currentDecision, closure, input, startIndex, sllStopIndex, false)
+                );
+            }
+        }
+        return reachConfigs;
+    }
+
+    protected override bool EvalSemanticContext(SemanticContext pred, ParserRuleContext parserCallStack, int alt, bool fullCtx)
+    {
+        bool result = base.EvalSemanticContext(pred, parserCallStack, alt, fullCtx);
+        if (!(pred is SemanticContext.PrecedencePredicate)) {
+            bool fullContext = llStopIndex >= 0;
+            int stopIndex = fullContext ? llStopIndex : sllStopIndex;
+            decisions[currentDecision].predicateEvals.Add(
+                new PredicateEvalInfo(currentDecision, input, startIndex, stopIndex, pred, result, alt, fullCtx)
+            );
+        }
+
+        return result;
+    }
+
+    protected override void ReportAttemptingFullContext(DFA dfa, BitSet conflictingAlts, ATNConfigSet configs, int startIndex, int stopIndex)
+    {
+        if (conflictingAlts != null)
+        {
+            conflictingAltResolvedBySLL = conflictingAlts.NextSetBit(0);
+        }
+        else {
+            conflictingAltResolvedBySLL = configs.GetAlts().NextSetBit(0);
+        }
+        decisions[currentDecision].LL_Fallback++;
+        base.ReportAttemptingFullContext(dfa, conflictingAlts, configs, startIndex, stopIndex);
+    }
+
+    protected override void ReportContextSensitivity(DFA dfa, int prediction, ATNConfigSet configs, int startIndex, int stopIndex)
+    {
+        if (prediction != conflictingAltResolvedBySLL)
+        {
+            decisions[currentDecision].contextSensitivities.Add(
+                new ContextSensitivityInfo(currentDecision, configs, input, startIndex, stopIndex)
+            );
+        }
+            base.ReportContextSensitivity(dfa, prediction, configs, startIndex, stopIndex);
+    }
+
+    protected override void ReportAmbiguity(DFA dfa, DFAState D, int startIndex, int stopIndex, bool exact,
+                                            BitSet ambigAlts, ATNConfigSet configs)
+    {
+        int prediction;
+        if (ambigAlts != null)
+        {
+            prediction = ambigAlts.NextSetBit(0);
+        }
+        else {
+                prediction = configs.GetAlts().NextSetBit(0);
+        }
+        if (configs.fullCtx && prediction != conflictingAltResolvedBySLL)
+        {
+            // Even though this is an ambiguity we are reporting, we can
+            // still detect some context sensitivities.  Both SLL and LL
+            // are showing a conflict, hence an ambiguity, but if they resolve
+            // to different minimum alternatives we have also identified a
+            // context sensitivity.
+            decisions[currentDecision].contextSensitivities.Add( new ContextSensitivityInfo(currentDecision, configs, input, startIndex, stopIndex) );
+        }
+        decisions[currentDecision].ambiguities.Add(
+            new AmbiguityInfo(currentDecision, configs, ambigAlts,
+                              input, startIndex, stopIndex, configs.fullCtx)
+        );
+        base.ReportAmbiguity(dfa, D, startIndex, stopIndex, exact, ambigAlts, configs);
+    }
+
+    // ---------------------------------------------------------------------
+
+    public DecisionInfo[] getDecisionInfo()
+    {
+        return decisions;
+    }
+
+    public DFAState getCurrentState()
+    {
+        return currentState;
+    }
 }

 }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions