From 3212dc9c6f3538e1d0bd1809efd5f33ad8b47701 Mon Sep 17 00:00:00 2001
From: Joe Wang <joehw@openjdk.org>
Date: Thu, 7 Jul 2022 19:07:04 +0000
Subject: [PATCH] 8289486: Improve XSLT XPath operators count efficiency

Reviewed-by: naoto, lancea
---
 .../java_cup/internal/runtime/lr_parser.java  | 26 ++++++++-
 .../internal/xsltc/compiler/XPathParser.java  | 57 ++++++++++---------
 2 files changed, 55 insertions(+), 28 deletions(-)

diff --git a/src/java.xml/share/classes/com/sun/java_cup/internal/runtime/lr_parser.java b/src/java.xml/share/classes/com/sun/java_cup/internal/runtime/lr_parser.java
index 8da2d63d6f8..2aa71318d4e 100644
--- a/src/java.xml/share/classes/com/sun/java_cup/internal/runtime/lr_parser.java
+++ b/src/java.xml/share/classes/com/sun/java_cup/internal/runtime/lr_parser.java
@@ -137,7 +137,7 @@ import java.util.Stack;
  * @see     com.sun.java_cup.internal.runtime.virtual_parse_stack
  * @author  Frank Flannery
  *
- * @LastModified: June 2022
+ * @LastModified: July 2022
  */
 
 public abstract class lr_parser {
@@ -150,6 +150,10 @@ public abstract class lr_parser {
     private int opCount = 0;
     private int totalOpCount = 0;
     private int lastSym;
+    private boolean overLimit = false;
+    public int grpLimit = 0;
+    public int opLimit = 0;
+    public int totalOpLimit = 0;
 
   /*-----------------------------------------------------------*/
   /*--- Constructor(s) ----------------------------------------*/
@@ -376,11 +380,13 @@ public abstract class lr_parser {
             grpCount++;
           }
           opCount++; // function
+          totalOpCount++;
           isLiteral = false;
       } else if (contains(sym.OPERATORS, s.sym)) {
           // axis nodetest is counted as one step, so not counted if last=DCOLON
           if (lastSym != sym.DCOLON) {
               opCount++;
+              totalOpCount++;
           }
           isLiteral = false;
       }
@@ -390,6 +396,16 @@ public abstract class lr_parser {
       }
       lastSym = s.sym;
 
+      /*
+       * Sets the overLimit status as soon as the count of operators is over the
+       * limit, which in turn triggers the XPathParser to report an error.
+      */
+      if (grpLimit > 0 && grpCount > grpLimit
+              || opLimit > 0 && opCount > opLimit
+              || totalOpLimit > 0 && totalOpCount > totalOpLimit) {
+          overLimit = true;
+      }
+
     return s;
   }
 
@@ -591,12 +607,14 @@ public abstract class lr_parser {
       /* do user initialization */
       user_init();
       isLiteral = false;
+      overLimit = false;
       grpCount = 0;
       opCount = 0;
       lastSym = -1;
 
       /* get the first token */
       cur_token = scan();
+      if (overLimit) return null;
 
       /* push dummy Symbol with start state to get us underway */
       stack.removeAllElements();
@@ -671,12 +689,16 @@ public abstract class lr_parser {
                   lhs_sym = stack.peek();
                 }
             }
+            if (overLimit) return null;
         }
 
-      totalOpCount += opCount;
       return lhs_sym;
     }
 
+    public boolean isOverLimit() {
+        return overLimit;
+    }
+
     /**
      * Returns the count of operators in XPath expressions.
      *
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XPathParser.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XPathParser.java
index 16fdbe18fc9..174e1440479 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XPathParser.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XPathParser.java
@@ -43,12 +43,9 @@ import jdk.xml.internal.XMLSecurityManager.Limit;
  * CUP v0.11b generated parser.
  * This class was generated by CUP v0.11b on Nov 12, 2019.
  *
- * @LastModified: Jan 2022
+ * @LastModified: July 2022
  */
 public class XPathParser extends lr_parser {
-    private int grpLimit = 0;
-    private int opLimit = 0;
-    private int totalOpLimit = 0;
 
     /**
      * Default constructor.
@@ -1118,29 +1115,37 @@ public class XPathParser extends lr_parser {
             _expression = expression;
             _lineNumber = lineNumber;
             Symbol s = super.parse();
-            int grpCount = getCount(ID_GROUP);
-            int opCount = getCount(ID_OPERATOR);
-            int totalOpCount = getCount(ID_TOTAL_OPERATOR);
+            /*
+             * While the Java CUP parser is used for parsing symbols, the error
+             * report mechanism has so far been kept within the Xalan implementation.
+             * An error, i.e. the count of operators is over the limit, is
+             * therefore handled here.
+            */
+            if (isOverLimit()) {
+                int grpCount = getCount(ID_GROUP);
+                int opCount = getCount(ID_OPERATOR);
+                int totalOpCount = getCount(ID_TOTAL_OPERATOR);
 
-            String errCode = null;
-            Object[] params = null;
-            if (grpLimit > 0 && grpCount > grpLimit) {
-                errCode = ErrorMsg.XPATH_GROUP_LIMIT;
-                params = new Object[]{grpCount, grpLimit,
-                    _xmlSM.getStateLiteral(Limit.XPATH_GROUP_LIMIT)};
-            } else if (opLimit > 0 && opCount > opLimit) {
-                errCode = ErrorMsg.XPATH_OPERATOR_LIMIT;
-                params = new Object[]{opCount, opLimit,
-                    _xmlSM.getStateLiteral(Limit.XPATH_OP_LIMIT)};
-            } else if (totalOpLimit > 0 && totalOpCount > totalOpLimit) {
-                errCode = ErrorMsg.XPATH_TOTAL_OPERATOR_LIMIT;
-                params = new Object[]{totalOpCount, totalOpLimit,
-                    _xmlSM.getStateLiteral(Limit.XPATH_TOTALOP_LIMIT)};
-            }
-            if (errCode != null) {
-                _parser.reportError(Constants.FATAL,
-                        new ErrorMsg(errCode, lineNumber, params));
-                throw new RuntimeException(ErrorMsg.XPATH_LIMIT);
+                String errCode = null;
+                Object[] params = null;
+                if (grpLimit > 0 && grpCount > grpLimit) {
+                    errCode = ErrorMsg.XPATH_GROUP_LIMIT;
+                    params = new Object[]{grpCount, grpLimit,
+                        _xmlSM.getStateLiteral(Limit.XPATH_GROUP_LIMIT)};
+                } else if (opLimit > 0 && opCount > opLimit) {
+                    errCode = ErrorMsg.XPATH_OPERATOR_LIMIT;
+                    params = new Object[]{opCount, opLimit,
+                        _xmlSM.getStateLiteral(Limit.XPATH_OP_LIMIT)};
+                } else if (totalOpLimit > 0 && totalOpCount > totalOpLimit) {
+                    errCode = ErrorMsg.XPATH_TOTAL_OPERATOR_LIMIT;
+                    params = new Object[]{totalOpCount, totalOpLimit,
+                        _xmlSM.getStateLiteral(Limit.XPATH_TOTALOP_LIMIT)};
+                }
+                if (errCode != null) {
+                    _parser.reportError(Constants.FATAL,
+                            new ErrorMsg(errCode, lineNumber, params));
+                    throw new RuntimeException(ErrorMsg.XPATH_LIMIT);
+                }
             }
             return s;
         } catch (IllegalCharException e) {