You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by sa...@apache.org on 2002/07/29 23:30:52 UTC

cvs commit: xml-xalan/java/src/org/apache/xalan/xsltc/compiler Expression.java FlowList.java Mode.java StepPattern.java TestSeq.java

santiagopg    2002/07/29 14:30:52

  Modified:    java/src/org/apache/xalan/xsltc/compiler Expression.java
                        FlowList.java Mode.java StepPattern.java
                        TestSeq.java
  Log:
  Fix for Bugzilla 11166.
  
  Revision  Changes    Path
  1.14      +9 -1      xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Expression.java
  
  Index: Expression.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Expression.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- Expression.java	26 Jun 2002 21:25:35 -0000	1.13
  +++ Expression.java	29 Jul 2002 21:30:51 -0000	1.14
  @@ -214,6 +214,14 @@
   	_falseList.add(il.append(new IFEQ(null)));
       }
   
  +    public FlowList getFalseList() {
  +	return _falseList;
  +    }
  +
  +    public FlowList getTrueList() {
  +	return _trueList;
  +    }
  +
       public void backPatchFalseList(InstructionHandle ih) {
   	_falseList.backPatch(ih);
       }
  
  
  
  1.3       +31 -1     xml-xalan/java/src/org/apache/xalan/xsltc/compiler/FlowList.java
  
  Index: FlowList.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/FlowList.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- FlowList.java	1 Feb 2002 20:07:08 -0000	1.2
  +++ FlowList.java	29 Jul 2002 21:30:51 -0000	1.3
  @@ -64,6 +64,7 @@
   package org.apache.xalan.xsltc.compiler;
   
   import java.util.Vector;
  +import java.util.Iterator;
   import org.apache.bcel.generic.*;
   
   public final class FlowList {
  @@ -118,5 +119,34 @@
   	    }
   	    _elements.clear();		// avoid backpatching more than once
   	}
  +    }
  +
  +    /**
  +     * Redirect the handles from oldList to newList. "This" flow list
  +     * is assumed to be relative to oldList.
  +     */
  +    public FlowList copyAndRedirect(InstructionList oldList, 
  +	InstructionList newList) 
  +    {
  +	final FlowList result = new FlowList();
  +	if (_elements == null) {
  +	    return result;
  +	}
  +
  +	final int n = _elements.size();
  +	final Iterator oldIter = oldList.iterator();
  +	final Iterator newIter = newList.iterator();
  +	
  +	while (oldIter.hasNext()) {
  +	    final InstructionHandle oldIh = (InstructionHandle) oldIter.next();
  +	    final InstructionHandle newIh = (InstructionHandle) newIter.next();
  +
  +	    for (int i = 0; i < n; i++) {
  +		if (_elements.elementAt(i) == oldIh) {
  +		    result.add(newIh);
  +		}
  +	    }
  +	}
  +	return result;
       }
   }
  
  
  
  1.23      +162 -61   xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Mode.java
  
  Index: Mode.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Mode.java,v
  retrieving revision 1.22
  retrieving revision 1.23
  diff -u -r1.22 -r1.23
  --- Mode.java	15 Jul 2002 19:48:19 -0000	1.22
  +++ Mode.java	29 Jul 2002 21:30:51 -0000	1.23
  @@ -77,8 +77,9 @@
   import org.apache.xalan.xsltc.DOM;
   
   /**
  - * Mode gathers all the templates belonging to a given mode; it is responsible
  - * for generating an appropriate applyTemplates + (mode name) function
  + * Mode gathers all the templates belonging to a given mode; 
  + * it is responsible for generating an appropriate 
  + * applyTemplates + (mode name) method in the translet.
    */
   final class Mode implements Constants {
   
  @@ -120,32 +121,67 @@
       /**
        * Test sequence for patterns with id() or key()-type kernel.
        */
  -    private TestSeq  _idxTestSeq = null;
  +    private TestSeq _idxTestSeq = null;
   
       /**
        * Group for patterns with any other kernel type.
        */
  -    private Vector[]  _patternGroups;
  +    private Vector[] _patternGroups;
   
       /**
        * Test sequence for patterns with any other kernel type.
        */
       private TestSeq[] _testSeq;
   
  +    /**
  +     * A mapping between patterns and instruction lists used by 
  +     * test sequences to avoid compiling the same pattern multiple 
  +     * times. Note that patterns whose kernels are "*", "node()" 
  +     * and "@*" can between shared by test sequences.
  +     */
  +    private Hashtable _preCompiled = new Hashtable();
  +
  +    /**
  +     * A mapping between templates and test sequences.
  +     */
       private Hashtable _neededTemplates = new Hashtable();
  +
  +    /**
  +     * A mapping between named templates and Mode objects.
  +     */
       private Hashtable _namedTemplates = new Hashtable();
  +
  +    /**
  +     * A mapping between templates and instruction handles.
  +     */
       private Hashtable _templateIHs = new Hashtable();
  +
  +    /**
  +     * A mapping between templates and instruction lists.
  +     */
       private Hashtable _templateILs = new Hashtable();
  +
  +    /**
  +     * A reference to the pattern matching the root node.
  +     */
       private LocationPathPattern _rootPattern = null;
   
  +    /**
  +     * Stores ranges of template precendences for the compilation 
  +     * of apply-imports (a Hashtable for historical reasons).
  +     */
       private Hashtable _importLevels = null;
   
  +    /**
  +     * A mapping between key names and keys.
  +     */
       private Hashtable _keys = null;
   
  -    // Variable index for the current node - used in code generation
  +    /**
  +     * Variable index for the current node used in code generation.
  +     */
       private int _currentIndex;
   
  -
       /**
        * Creates a new Mode.
        *
  @@ -155,19 +191,18 @@
        *               (normally a sequence number - still in a String).
        */
       public Mode(QName name, Stylesheet stylesheet, String suffix) {
  -	// Save global info
   	_name = name;
   	_stylesheet = stylesheet;
   	_methodName = APPLY_TEMPLATES + suffix;
  -	// Initialise some data structures
   	_templates = new Vector();
   	_patternGroups = new Vector[32];
       }
   
       /**
  -     * Returns the name of the method (_not_ function) that will be compiled
  -     * for this mode. Normally takes the form 'applyTemplates()' or
  -     * 'applyTemplates2()'.
  +     * Returns the name of the method (_not_ function) that will be 
  +     * compiled for this mode. Normally takes the form 'applyTemplates()' 
  +     * or * 'applyTemplates2()'.
  +     *
        * @return Method name for this mode
        */
       public String functionName() {
  @@ -175,9 +210,28 @@
       }
   
       public String functionName(int min, int max) {
  -	if (_importLevels == null) _importLevels = new Hashtable();
  +	if (_importLevels == null) {
  +	    _importLevels = new Hashtable();
  +	}
   	_importLevels.put(new Integer(max), new Integer(min));
  -	return _methodName+'_'+max;
  +	return _methodName + '_' + max;
  +    }
  +
  +    /**
  +     * Add a pre-compiled pattern to this mode. 
  +     */
  +    public void addInstructionList(Pattern pattern, 
  +	InstructionList ilist) 
  +    {
  +	_preCompiled.put(pattern, ilist);
  +    }
  +
  +    /**
  +     * Get the instruction list for a pre-compiled pattern. Used by 
  +     * test sequences to avoid compiling patterns more than once.
  +     */
  +    public InstructionList getInstructionList(Pattern pattern) {
  +	return (InstructionList) _preCompiled.get(pattern);
       }
   
       /**
  @@ -187,10 +241,10 @@
   	return _stylesheet.getClassName();
       }
   
  -    /**
  -     * Add a template to this mode
  -     * @param template The template to add
  -     */
  +    public Stylesheet getStylesheet() {
  +	return _stylesheet;
  +    }
  +
       public void addTemplate(Template template) {
   	_templates.addElement(template);
       }
  @@ -304,10 +358,32 @@
       }
   
       /**
  +     * Group patterns by NodeTests of their last Step
  +     * Keep them sorted by priority within group
  +     */
  +    private void addPatternToGroup(final LocationPathPattern lpp) {
  +	// id() and key()-type patterns do not have a kernel type
  +	if (lpp instanceof IdKeyPattern) {
  +	    addPattern(-1, lpp);
  +	}
  +	// Otherwise get the kernel pattern from the LPP
  +	else {
  +	    // kernel pattern is the last (maybe only) Step
  +	    final StepPattern kernel = lpp.getKernelPattern();
  +	    if (kernel != null) {
  +		addPattern(kernel.getNodeType(), lpp);
  +	    }
  +	    else if (_rootPattern == null ||
  +		     lpp.noSmallerThan(_rootPattern)) {
  +		_rootPattern = lpp;
  +	    }
  +	}
  +    }
  +
  +    /**
        * Adds a pattern to a pattern group
        */
       private void addPattern(int kernelType, LocationPathPattern pattern) {
  -
   	// Make sure the array of pattern groups is long enough
   	final int oldLength = _patternGroups.length;
   	if (kernelType >= oldLength) {
  @@ -326,10 +402,13 @@
   	if (patterns == null) {
   	    patterns = new Vector(2);
   	    patterns.addElement(pattern);
  -	    if (kernelType == -1)
  +
  +	    if (kernelType == -1) {
   		_nodeGroup = patterns;
  -	    else
  +	    }
  +	    else {
   		_patternGroups[kernelType] = patterns;
  +	    }
   	}
   	// Otherwise make sure patterns are ordered by precedence/priorities
   	else {
  @@ -350,40 +429,58 @@
       }
       
       /**
  -     * Group patterns by NodeTests of their last Step
  -     * Keep them sorted by priority within group
  +     * Build test sequences. The first step is to complete the test sequences 
  +     * by including patterns of "*" and "node()" kernel to all element test 
  +     * sequences, and of "@*" to all attribute test sequences.
        */
  -    private void addPatternToGroup(final LocationPathPattern lpp) {
  -	// id() and key()-type patterns do not have a kernel type
  -	if (lpp instanceof IdKeyPattern) {
  -	    addPattern(-1, lpp);
  -	}
  -	// Otherwise get the kernel pattern from the LPP
  -	else {
  -	    // kernel pattern is the last (maybe only) Step
  -	    final StepPattern kernel = lpp.getKernelPattern();
  -	    if (kernel != null) {
  -		addPattern(kernel.getNodeType(), lpp);
  -	    }
  -	    else if (_rootPattern == null ||
  -		     lpp.noSmallerThan(_rootPattern)) {
  -		_rootPattern = lpp;
  +    private void prepareTestSequences() {
  +	final Vector names = _stylesheet.getXSLTC().getNamesIndex();
  +
  +	final Vector starGroup = _patternGroups[DOM.ELEMENT];
  +	final Vector atStarGroup = _patternGroups[DOM.ATTRIBUTE];
  +
  +	// Complete test sequences with "*", "@*" and "node()"
  +	if (starGroup != null || atStarGroup != null || _nodeGroup != null) {
  +	    final int n = DOM.NTYPES + names.size();
  +
  +	    for (int m, i = DOM.NTYPES; i < n; i++) {
  +		if (_patternGroups[i] == null) continue;
  +
  +		final String name = (String) names.elementAt(i - DOM.NTYPES);
  +
  +		if (isAttributeName(name)) {
  +		    // If an attribute then copy "@*" to its test sequence
  +		    m = (atStarGroup != null) ? atStarGroup.size() : 0;
  +		    for (int j = 0; j < m; j++) {
  +			addPattern(i, 
  +			    (LocationPathPattern) atStarGroup.elementAt(j));
  +		    }
  +		}
  +		else {
  +		    // If an element then copy "*" to its test sequence
  +		    m = (starGroup != null) ? starGroup.size() : 0;
  +		    for (int j = 0; j < m; j++) {
  +			addPattern(i, 
  +			    (LocationPathPattern) starGroup.elementAt(j));
  +		    }
  +
  +		    // And also copy "node()" to its test sequence
  +		    m = (_nodeGroup != null) ? _nodeGroup.size() : 0;
  +		    for (int j = 0; j < m; j++) {
  +			addPattern(i, 
  +			    (LocationPathPattern) _nodeGroup.elementAt(j));
  +		    }
  +		}
   	    }
   	}
  -    }
   
  -    /**
  -     * Build test sequences
  -     */
  -    private void prepareTestSequences() {
  -	final Vector names = _stylesheet.getXSLTC().getNamesIndex();
   	_testSeq = new TestSeq[DOM.NTYPES + names.size()];
   	
   	final int n = _patternGroups.length;
   	for (int i = 0; i < n; i++) {
   	    final Vector patterns = _patternGroups[i];
   	    if (patterns != null) {
  -		final TestSeq testSeq = new TestSeq(patterns, this);
  +		final TestSeq testSeq = new TestSeq(patterns, i, this);
   		testSeq.reduce();
   		_testSeq[i] = testSeq;
   		testSeq.findTemplates(_neededTemplates);
  @@ -391,7 +488,7 @@
   	}
   
   	if ((_nodeGroup != null) && (_nodeGroup.size() > 0)) {
  -	    _nodeTestSeq = new TestSeq(_nodeGroup, this);
  +	    _nodeTestSeq = new TestSeq(_nodeGroup, -1, this);
   	    _nodeTestSeq.reduce();
   	    _nodeTestSeq.findTemplates(_neededTemplates);
   	}
  @@ -619,20 +716,7 @@
   	}
       }
   
  -    /**
  -     * Auxiliary method to determine if a qname describes an attribute/element
  -     */
  -    private static boolean isAttributeName(String qname) {
  -	final int col = qname.lastIndexOf(':') + 1;
  -	return (qname.charAt(col) == '@');
  -    }
  -
  -    private static boolean isNamespaceName(String qname) {
  -	final int col = qname.lastIndexOf(':');
  -	return (col > -1 && qname.charAt(qname.length()-1) == '*');
  -    }
  -
  -    /**
  +   /**
        * Compiles the applyTemplates() method and adds it to the translet.
        * This is the main dispatch method.
        */
  @@ -742,7 +826,6 @@
   	// If there is a match on node() we need to replace ihElem
   	// and ihText if the priority of node() is higher
   	if (_nodeTestSeq != null) {
  -
   	    // Compare priorities of node() and "*"
   	    double nodePrio = _nodeTestSeq.getPriority();
   	    int    nodePos  = _nodeTestSeq.getPosition();
  @@ -815,6 +898,7 @@
   	    }
   	}
   
  +
   	// Handle pattern with match on root node - default: traverse children
   	targets[DOM.ROOT] = _rootPattern != null
   	    ? getTemplateInstructionHandle(_rootPattern.getTemplate())
  @@ -1320,5 +1404,22 @@
   
       public InstructionHandle getTemplateInstructionHandle(Template template) {
   	return (InstructionHandle)_templateIHs.get(template);
  +    }
  +
  +    /**
  +     * Auxiliary method to determine if a qname is an attribute.
  +     */
  +    private static boolean isAttributeName(String qname) {
  +	final int col = qname.lastIndexOf(':') + 1;
  +	return (qname.charAt(col) == '@');
  +    }
  +
  +    /**
  +     * Auxiliary method to determine if a qname is a namespace 
  +     * qualified "*".
  +     */
  +    private static boolean isNamespaceName(String qname) {
  +	final int col = qname.lastIndexOf(':');
  +	return (col > -1 && qname.charAt(qname.length()-1) == '*');
       }
   }
  
  
  
  1.17      +4 -2      xml-xalan/java/src/org/apache/xalan/xsltc/compiler/StepPattern.java
  
  Index: StepPattern.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/StepPattern.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- StepPattern.java	6 May 2002 13:53:22 -0000	1.16
  +++ StepPattern.java	29 Jul 2002 21:30:51 -0000	1.17
  @@ -150,7 +150,9 @@
   	final StringBuffer buffer = new StringBuffer("stepPattern(\"");
   	buffer.append(Axis.names[_axis])
   	    .append("\", ")
  -	    .append(_isEpsilon ? "epsilon" : Integer.toString(_nodeType));
  +	    .append(_isEpsilon ? 
  +			("epsilon{" + Integer.toString(_nodeType) + "}") :
  +			 Integer.toString(_nodeType));
   	if (_predicates != null)
   	    buffer.append(", ").append(_predicates.toString());
   	return buffer.append(')').toString();
  
  
  
  1.8       +154 -101  xml-xalan/java/src/org/apache/xalan/xsltc/compiler/TestSeq.java
  
  Index: TestSeq.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/TestSeq.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- TestSeq.java	3 May 2002 14:20:25 -0000	1.7
  +++ TestSeq.java	29 Jul 2002 21:30:51 -0000	1.8
  @@ -69,6 +69,7 @@
   import java.util.Hashtable;
   import java.util.Dictionary;
   import java.util.Enumeration;
  +import java.util.Iterator;
   
   import org.apache.bcel.generic.*;
   import org.apache.xalan.xsltc.compiler.util.*;
  @@ -77,110 +78,149 @@
    * A test sequence is a sequence of patterns that
    *
    *  (1) occured in templates in the same mode
  - *  (2) share the same kernel node type (such as A/B and C/C/B).
  + *  (2) share the same kernel node type (e.g. A/B and C/C/B)
  + *  (3) may also contain patterns matching "*" and "node()"
  + *      (element sequence only) or matching "@*" (attribute
  + *      sequence only).
    *
  - * A test sequence may have a default template, which will be run if
  - * none of the patterns do not match. This template is always a template
  - * that matches solely on the shared kernel node type.
  + * A test sequence may have a default template, which will be 
  + * instantiated if none of the other patterns match. 
    */
   final class TestSeq {
   
  -    private Vector   _patterns = null; // all patterns
  -    private Mode     _mode     = null; // the shared mode
  -    private Template _default  = null; // the default template
  +    /**
  +     * Integer code for the kernel type of this test sequence
  +     */
  +    private int _kernelType;
  +
  +    /**
  +     * Vector of all patterns in the test sequence. May include
  +     * patterns with "*", "@*" or "node()" kernel.
  +     */
  +    private Vector _patterns = null;
  +
  +    /**
  +     * A reference to the Mode object.
  +     */
  +    private Mode _mode = null;
  +
  +    /**
  +     * Default template for this test sequence
  +     */
  +    private Template _default = null;
   
  +    /**
  +     * Instruction list representing this test sequence.
  +     */
       private InstructionList _instructionList;
   
       /**
  -     * Creates a new test sequence, given a set of patterns and a mode.
  +     * Cached handle to avoid compiling more than once.
  +     */
  +    private InstructionHandle _start = null;
  +
  +    /**
  +     * Creates a new test sequence given a set of patterns and a mode.
        */
       public TestSeq(Vector patterns, Mode mode) {
  +	this(patterns, -2, mode);
  +    }
  +
  +    public TestSeq(Vector patterns, int kernelType, Mode mode) {
   	_patterns = patterns;
  +	_kernelType = kernelType;
   	_mode = mode;
       }
   
       /**
  -     * The priority is only calculated if the test sequence has a default
  -     * template. This is bad, bad, bad. We should get the priority from the
  -     * other templates that make up the test sequence.
  +     * Returns a string representation of this test sequence. Notice
  +     * that test sequences are mutable, so the value returned by this
  +     * method is different before and after calling reduce().
        */
  -    public double getPriority() {
  -	double prio = (0 - Double.MAX_VALUE);
  +    public String toString() {
   	final int count = _patterns.size();
  +	final StringBuffer result = new StringBuffer();
   
   	for (int i = 0; i < count; i++) {
  -	    final Pattern pattern = (Pattern)_patterns.elementAt(i);
  -	    final Template template = pattern.getTemplate();
  -	    final double tp = template.getPriority();
  -	    if (tp > prio) prio = tp;
  -	}
  -	if (_default != null) {
  -	    final double tp = _default.getPriority();
  -	    if (tp > prio) prio = tp;
  +	    final LocationPathPattern pattern =
  +		(LocationPathPattern) _patterns.elementAt(i);
  +
  +	    if (i == 0) {
  +		result.append("Testseq for kernel " + _kernelType)
  +		      .append('\n');
  +	    }
  +	    result.append("   pattern " + i + ": ")
  +	          .append(pattern.toString())
  +		  .append('\n');
   	}
  -	return prio;
  +	return result.toString();
       }
   
       /**
  -     * This method should return the last position of any template included
  -     * in this test sequence.
  +     * Returns the instruction list for this test sequence
        */
  -    public int getPosition() {
  -	int pos = Integer.MIN_VALUE;
  -	final int count = _patterns.size();
  +    public InstructionList getInstructionList() {
  +	return _instructionList;
  +    }
   
  -	for (int i = 0; i < count; i++) {
  -	    final Pattern pattern = (Pattern)_patterns.elementAt(i);
  -	    final Template template = pattern.getTemplate();
  -	    final int tp = template.getPosition();
  -	    if (tp > pos) pos = tp;
  -	}
  -	if (_default != null) {
  -	    final int tp = _default.getPosition();
  -	    if (tp > pos) pos = tp;
  -	}
  -	return pos;
  +    /**
  +     * Return the highest priority for a pattern in this test
  +     * sequence. This is either the priority of the first or
  +     * of the default pattern.
  +     */
  +    public double getPriority() {
  +	final Template template = (_patterns.size() == 0) ? _default 
  +	    : ((Pattern) _patterns.elementAt(0)).getTemplate();
  +	return template.getPriority();
       }
  -	
  +
  +    /**
  +     * Returns the position of the highest priority pattern in 
  +     * this test sequence.
  +     */
  +    public int getPosition() {
  +	final Template template = (_patterns.size() == 0) ? _default 
  +	    : ((Pattern) _patterns.elementAt(0)).getTemplate();
  +	return template.getPosition();
  +    }
  +
       /**
  -     * Reduce the patterns in this test sequence to exclude the shared
  -     * kernel node type. After the switch() in the translet's applyTemplates()
  -     * we already know that we have a hit for the kernel node type, we only
  -     * have the check the rest of the pattern.
  +     * Reduce the patterns in this test sequence. Creates a new
  +     * vector of patterns and sets the default pattern if it
  +     * finds a patterns that is fully reduced.
        */
       public void reduce() {
   	final Vector newPatterns = new Vector();
  -	final int count = _patterns.size();
   
  -	// Traverse the existing set of patterns (they are in prioritised order)
  +	final int count = _patterns.size();
   	for (int i = 0; i < count; i++) {
   	    final LocationPathPattern pattern =
   		(LocationPathPattern)_patterns.elementAt(i);
  -	    // Reduce this pattern (get rid of kernel node type)
  +		
  +	    // Reduce this pattern
   	    pattern.reduceKernelPattern();
   			
  -	    // Add this pattern to the new vector of patterns.
  -	    if (!pattern.isWildcard()) {
  -		newPatterns.addElement(pattern);
  +	    // Is this pattern fully reduced?
  +	    if (pattern.isWildcard()) {
  +		_default = pattern.getTemplate();
  +		break; 		// Ignore following patterns 
   	    }
  -	    // Set template as default if its pattern matches purely on kernel
   	    else {
  -		_default = pattern.getTemplate();
  -		// Following patterns can be ignored since default has priority
  -		break;
  +		newPatterns.addElement(pattern);
   	    }
   	}
   	_patterns = newPatterns;
       }
   
       /**
  -     * Returns, by reference, the templates that are included in this test
  -     * sequence. Remember that a single template can occur in several test
  -     * sequences if its pattern is a union (ex. match="A/B | A/C").
  +     * Returns, by reference, the templates that are included in 
  +     * this test sequence. Note that a single template can occur 
  +     * in several test sequences if its pattern is a union.
        */
       public void findTemplates(Dictionary templates) {
  -	if (_default != null)
  +	if (_default != null) {
   	    templates.put(_default, this);
  +	}
   	for (int i = 0; i < _patterns.size(); i++) {
   	    final LocationPathPattern pattern =
   		(LocationPathPattern)_patterns.elementAt(i);
  @@ -189,9 +229,10 @@
       }
   
       /**
  -     * Get the instruction handle to a template's code. This is used when
  -     * a single template occurs in several test sequences; that is, if its
  -     * pattern is a union of patterns (ex. match="A/B | A/C").
  +     * Get the instruction handle to a template's code. This is 
  +     * used when a single template occurs in several test 
  +     * sequences; that is, if its pattern is a union of patterns 
  +     * (e.g. match="A/B | A/C").
        */
       private InstructionHandle getTemplateHandle(Template template) {
   	return (InstructionHandle)_mode.getTemplateInstructionHandle(template);
  @@ -204,71 +245,83 @@
   	return (LocationPathPattern)_patterns.elementAt(n);
       }
   
  -
  -    private InstructionHandle _start = null;
  -
       /**
  -     * Copile the code for this test sequence. The code will first test for
  -     * the pattern with the highest priority, then go on to the next ones,
  -     * until it hits or finds the default template.
  +     * Compile the code for this test sequence. Compile patterns 
  +     * from highest to lowest priority. Note that since patterns 
  +     * can be share by multiple test sequences, instruction lists 
  +     * must be copied before backpatching.
        */
       public InstructionHandle compile(ClassGenerator classGen,
   				     MethodGenerator methodGen,
  -				     InstructionHandle continuation) {
  +				     InstructionHandle continuation) 
  +    {
  +	// Returned cached value if already compiled
  +	if (_start != null) {
  +	    return _start;
  +	}
   
  +	// If not patterns, then return handle for default template
   	final int count = _patterns.size();
  -	
  -	if (_start != null) return(_start);
  -
  -	// EZ DC if there is only one (default) pattern
  -	if (count == 0) getTemplateHandle(_default);
  +	if (count == 0) {
  +	    return (_start = getTemplateHandle(_default));
  +	}
   
  -	// The 'fail' instruction handle represents a branch to go to when
  -	// test fails. It is updated in each iteration, so that the tests
  -	// are linked together in the  if-elseif-elseif-else fashion.
  -	InstructionHandle fail;
  +	// Init handle to jump when all patterns failed
  +	InstructionHandle fail = (_default == null) ? continuation
  +	    : getTemplateHandle(_default);
   	
  -	// Initialize 'fail' to either the code for the default template
  -	if (_default != null)
  -	    fail = getTemplateHandle(_default);
  -	// ..or if that does not exist, to a location set by the caller.
  -	else
  -	    fail = continuation;
  -
  -	for (int n = (count - 1); n >= 0; n--) {
  +	// Compile all patterns in reverse order
  +	for (int n = count - 1; n >= 0; n--) {
   	    final LocationPathPattern pattern = getPattern(n);
   	    final Template template = pattern.getTemplate();
   	    final InstructionList il = new InstructionList();
   
   	    // Patterns expect current node on top of stack
   	    il.append(methodGen.loadCurrentNode());
  +
   	    // Apply the test-code compiled for the pattern
  -	    il.append(pattern.compile(classGen, methodGen));
  +	    InstructionList ilist = _mode.getInstructionList(pattern);
  +	    if (ilist == null) {
  +		ilist = pattern.compile(classGen, methodGen);
  +		_mode.addInstructionList(pattern, ilist);
  +	    }
  +
  +	    // Make a copy of the instruction list for backpatching
  +	    InstructionList copyOfilist = ilist.copy();
  +
  +	    FlowList trueList = pattern.getTrueList();
  +	    if (trueList != null) {
  +		trueList = trueList.copyAndRedirect(ilist, copyOfilist);
  +	    }
  +	    FlowList falseList = pattern.getFalseList();
  +	    if (falseList != null) {
  +		falseList = falseList.copyAndRedirect(ilist, copyOfilist);
  +	    }
  +
  +	    il.append(copyOfilist);
   
   	    // On success branch to the template code
   	    final InstructionHandle gtmpl = getTemplateHandle(template);
   	    final InstructionHandle success = il.append(new GOTO_W(gtmpl));
  -	    pattern.backPatchTrueList(success);
  -	    pattern.backPatchFalseList(fail);
   
  -	    // We're working backwards here. The next pattern's 'fail' target
  -	    // is this pattern's first instruction
  +	    if (trueList != null) {
  +		trueList.backPatch(success);
  +	    }
  +	    if (falseList != null) {
  +		falseList.backPatch(fail);
  +	    } 
  +
  +	    // Next pattern's 'fail' target is this pattern's first instruction
   	    fail = il.getStart();
   
   	    // Append existing instruction list to the end of this one
  -	    if (_instructionList != null) il.append(_instructionList);
  +	    if (_instructionList != null) {
  +		il.append(_instructionList);
  +	    }
   
  -	    // Set current instruction list to be this one.
  +	    // Set current instruction list to be this one
   	    _instructionList = il;
   	}
  -	return(_start = fail);
  -    }
  -
  -    /**
  -     * Returns the instruction list for this test sequence
  -     */
  -    public InstructionList getInstructionList() {
  -	return _instructionList;
  +	return (_start = fail);
       }
  -
   }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: xalan-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: xalan-cvs-help@xml.apache.org