On Mon, 29 Apr 2002, Remy Maucherat wrote:

> This looks like a good idea to me (Kin-Man is not there this week, so it's
> not an expert opinion). I would see that kind of change going into Jasper 2,
> though. Do you think you can prepare a patch against that version ?
> 
> Remy
> 
> 
> --
> To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
> 

Thanks!

We've done some benchmarks with JMeter, even though the case we tested is pathologic,
the JSP contained 100 tags!  The results were impressive.  The Jasper version included
with the "pre-beta" 4.1 tomcat averaged 20 seconds/hit, with the patch, the CVS
version of jasper2 average 0.8 second/hit.  If there is less try/finally nesting
in the java code of the page, the difference is less impressive of course.

The test setup, the test page and the detail of the results can be found:

        http://www3.sympatico.ca/benoitde/

NOTE my "sunday patch" contained one bug, this one has been more tested.

The patch against the CVS jasper2 is:


Index: 
jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Generator.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Generator.java,v
retrieving revision 1.6
diff -u -r1.6 Generator.java
--- jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Generator.java  
 25 Apr 2002 18:16:06 -0000      1.6
+++ jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Generator.java  
+ 30 Apr 2002 00:23:19 -0000
@@ -63,6 +63,8 @@
 import java.util.*;
 import java.beans.*;
 import java.net.URLEncoder;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
 import java.lang.reflect.Method;
 import javax.servlet.jsp.tagext.*;
 import org.xml.sax.Attributes;
@@ -91,6 +93,9 @@
     private JspCompilationContext ctxt;
     private boolean breakAtLF;
     private PageInfo pageInfo;
+    private FinallyApplyer finallies;
+    private int tryBit;
+    private Stack tryStack;
 
     /**
      * @param s the input string
@@ -176,6 +181,8 @@
            out.print  ((String)iter.next());
            out.println(";");
        }
+       out.printil("import java.util.Vector;");
+       out.printil("import java.util.BitSet;");
        out.println();
 
        // Generate class declaration
@@ -199,6 +206,17 @@
 
        // Constructor (empty so far) here
        // Other methods here
+       out.printil("private void addTagToVector(Vector tags, int index, 
+javax.servlet.jsp.tagext.Tag tag) {");
+       out.pushIndent();
+       out.printil("if (index + 1 > tags.size())");
+       out.pushIndent();
+       out.printil("tags.setSize(index + 1);");
+       out.popIndent();
+       out.printil("tags.setElementAt(tag, index);");
+       out.popIndent();
+       out.printil("}");
+       out.println();
+       out.println();
 
        // Now the service method
        out.printin("public void ");
@@ -222,6 +240,8 @@
        out.printil("ServletConfig config = null;");
        out.printil("JspWriter out = null;");
        out.printil("Object page = this;");
+       out.printil("BitSet bitmask = new BitSet();");
+       out.printil("Vector tags = new Vector();");
 
        out.printil("try {");
        out.pushIndent();
@@ -882,6 +902,10 @@
            out.println(" ---- */");
 
            Class tagHandlerClass = handlerInfo.getTagHandlerClass();
+
+           boolean implementsTryCatchFinally =
+                   TryCatchFinally.class.isAssignableFrom(tagHandlerClass);
+
            out.printin(tagHandlerClass.getName());
            out.print(" ");
            out.print(tagHandlerVar);
@@ -895,8 +919,22 @@
            declareTagVariableInfos(tagVarInfos, n.getTagData(),
                                    VariableInfo.AT_BEGIN);
            
-           out.printil("try {");
-           out.pushIndent();
+           if (implementsTryCatchFinally) {
+               out.printil("try {");
+               out.pushIndent();
+           } else {
+               out.printil("// try {");
+               out.printin("bitmask.set(");
+               Integer tryBitVal = new Integer(tryBit++);
+               tryStack.push(tryBitVal);
+               out.print(tryBitVal.toString());
+               out.println(");");
+               out.printin("addTagToVector(tags, ");
+               out.print(tryBitVal.toString());
+               out.print(", ");
+               out.print(tagHandlerVar);
+               out.println(");");
+           }
            out.printin("int ");
            out.print(tagEvalVar);
            out.print(" = ");
@@ -918,8 +956,17 @@
                out.pushIndent();
                
                if (isBodyTag) {
-                   out.printil("try {");
-                   out.pushIndent();
+                   out.printil("// try {");
+                   out.printin("bitmask.set(");
+                   Integer tryBitVal = new Integer(tryBit++);
+                   tryStack.push(tryBitVal);
+                   out.print(tryBitVal.toString());
+                   out.println(");");
+                   out.printin("addTagToVector(tags, ");
+                   out.print(tryBitVal.toString());
+                   out.print(", ");
+                   out.print(tagHandlerVar);
+                   out.println(");");
                    out.printin("if (");
                    out.print(tagEvalVar);
                    out.println(" != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) 
{");
@@ -981,19 +1028,35 @@
 
            if (n.getBody() != null) {
                if (implementsBodyTag) {
-                   out.popIndent(); // try
+                   Integer tryBitVal = (Integer)tryStack.pop();
+                   out.printil("// } finally {");
+                   out.printin("bitmask.clear(");
+                   out.print(tryBitVal.toString());
+                   out.println(");");
+
+                   out.printin("addTagToVector(tags, ");
+                   out.print(tryBitVal.toString());
+                   out.print(", ");
+                   out.print(tagHandlerVar);
+                   out.println(");");
 
-                   out.printil("} finally {");
-                   out.pushIndent();
                    out.printin("if (");
                    out.print(tagEvalVar);
                    out.println(" != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE)");
                    out.pushIndent();
                    out.printil("out = pageContext.popBody();");
                    out.popIndent();
+
+                   finallies.beginPartMethod(tryBitVal.intValue());
+                   finallies.print("      if (");
+                   
+finallies.print("((javax.servlet.jsp.tagext.BodyTag)tags.elementAt(");
+                   finallies.print(tryBitVal.toString());
+                   finallies.print(")).doAfterBody()");
+                   finallies.println(" != 
+javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE)");
+                   finallies.println("        out = pageContext.popBody();");
                    
-                   out.popIndent();
-                   out.printil("}");
+                   finallies.endPartMethod();
+                   out.printil("// }");
                }
                
                out.popIndent(); // EVAL_BODY
@@ -1007,26 +1070,39 @@
            out.printil("return;");
            out.popIndent();
 
-           out.popIndent(); // try
-
            // TryCatchFinally
            if (implementsTryCatchFinally) {
+               out.popIndent(); // try
+
                out.printil("} catch (Throwable _jspx_exception) {");
                out.pushIndent();
                out.printin(tagHandlerVar);
                out.println(".doCatch(_jspx_exception);");
                out.popIndent();
-           }
-           out.printil("} finally {");
-           out.pushIndent();
-           if (implementsTryCatchFinally) {
+               out.printil("} finally {");
+               out.pushIndent();
                out.printin(tagHandlerVar);
                out.println(".doFinally();");
+               out.printin(tagHandlerVar);
+               out.println(".release();");
+               out.popIndent();
+               out.printil("}");
+           } else {
+               Integer tryBitVal = (Integer)tryStack.pop();
+               out.printil("// } finally {");
+               out.printin("bitmask.clear(");
+               out.print(tryBitVal.toString());
+               out.println(");");
+               out.printin(tagHandlerVar);
+               out.println(".release();");
+               out.printil("// }");
+               finallies.beginPartMethod(tryBitVal.intValue());
+               finallies.printin("((javax.servlet.jsp.tagext.Tag)tags.elementAt(");
+               finallies.print(tryBitVal.toString());
+               finallies.print("))");
+               finallies.println(".release();");
+               finallies.endPartMethod();
            }
-           out.printin(tagHandlerVar);
-           out.println(".release();");
-           out.popIndent();
-           out.printil("}");
 
            // Declare and update AT_END variables
            updateVariableInfos(varInfos, VariableInfo.AT_END, true);
@@ -1302,7 +1378,18 @@
         out.pushIndent();
 
         // Do stuff here for finally actions...
+
+        out.printil("try {");
+        out.pushIndent();
+        out.printil("finallies(bitmask, out, tags, pageContext);");
+        out.popIndent();
+        out.printil("} catch (javax.servlet.jsp.JspException e) {");
+        out.pushIndent();
+        out.printil("if (pageContext != null) pageContext.handlePageException(e);");
+        out.popIndent();
+        out.printil("}");
         out.printil("if (_jspxFactory != null) 
_jspxFactory.releasePageContext(pageContext);");
+
         out.popIndent();
         out.printil("}");
 
@@ -1310,6 +1397,10 @@
         out.popIndent();
         out.printil("}");
 
+        // Call the final method
+        finallies.done();
+        out.printil(finallies.toString());
+
         // Close the class definition
         out.popIndent();
         out.printil("}");
@@ -1325,6 +1416,8 @@
        pageInfo = compiler.getPageInfo();
        beanInfo = pageInfo.getBeanRepository();
        breakAtLF = ctxt.getOptions().getMappedFile();
+       finallies = new FinallyApplyer();
+       tryStack = new Stack();
     }
 
     /**
@@ -1417,6 +1510,55 @@
         */
        public Class getTagHandlerClass() {
            return tagHandlerClass;
+       }
+    }
+  
+    private static class FinallyApplyer {
+       private PrintStream finalOutput;
+       private ByteArrayOutputStream rawOutput;
+
+       FinallyApplyer() {
+           rawOutput = new ByteArrayOutputStream();
+           finalOutput = new PrintStream(rawOutput, true);
+
+           finalOutput.println();
+           finalOutput.println("  private void finallies(BitSet bitmask, JspWriter 
+out, Vector tags, PageContext pageContext)");
+           finalOutput.println("  throws javax.servlet.jsp.JspException {");
+       }
+
+       public void done() {
+           finalOutput.println("  }");
+       }
+
+       public void beginPartMethod(int bit) {
+           finalOutput.print("    if (bitmask.get(");
+           finalOutput.print(bit);
+           finalOutput.println(")) {");
+       }
+
+       public void endPartMethod() {
+           finalOutput.println("    }");
+           finalOutput.println();
+       }
+
+       public void println(String aLine) {
+           if (null != aLine) {
+               finalOutput.print(aLine);
+           }
+           finalOutput.println();
+       }
+
+       public void printin(String partLine) {
+           finalOutput.print("      ");
+           finalOutput.print(partLine);
+       }
+
+       public void print(String partLine) {
+           finalOutput.print(partLine);
+       }
+
+       public String toString() {
+           return rawOutput.toString();
        }
     }
 }


--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to