FileDocCategorySizeDatePackage
StepPattern.javaAPI DocJava SE 6 API17110Tue Jun 10 00:22:30 BST 2008com.sun.org.apache.xalan.internal.xsltc.compiler

StepPattern

public class StepPattern extends RelativePathPattern
author
Jacek Ambroziak
author
Santiago Pericas-Geertsen
author
Erwin Bolwidt

Fields Summary
private static final int
NO_CONTEXT
private static final int
SIMPLE_CONTEXT
private static final int
GENERAL_CONTEXT
protected final int
_axis
protected final int
_nodeType
protected Vector
_predicates
private Step
_step
private boolean
_isEpsilon
private int
_contextCase
private double
_priority
Constructors Summary
public StepPattern(int axis, int nodeType, Vector predicates)


           
	_axis = axis;
	_nodeType = nodeType;
	_predicates = predicates;
    
Methods Summary
private intanalyzeCases()

	boolean noContext = true;
	final int n = _predicates.size();

	for (int i = 0; i < n && noContext; i++) {
	    Predicate pred = (Predicate) _predicates.elementAt(i);
            if (pred.isNthPositionFilter() || 
                pred.hasPositionCall() || 
                pred.hasLastCall()) 
            {
		noContext = false;
	    }
	}

	if (noContext) {
	    return NO_CONTEXT;
	}
	else if (n == 1) {
	    return SIMPLE_CONTEXT;
	}
	return GENERAL_CONTEXT;
    
public intgetAxis()

	return _axis;
    
public doublegetDefaultPriority()

	if (_priority != Double.MAX_VALUE) {
	    return _priority;
	}

	if (hasPredicates()) {
	    return 0.5;
	}
	else {
	    switch(_nodeType) {
	    case -1:
		return -0.5;	// node()
	    case 0:
		return 0.0;
	    default:
		return (_nodeType >= NodeTest.GTYPE) ? 0.0 : -0.5;
	    }
	}
    
public com.sun.org.apache.xalan.internal.xsltc.compiler.StepPatterngetKernelPattern()

	return this;
    
private java.lang.StringgetNextFieldName()

	return  "__step_pattern_iter_" + getXSLTC().nextStepPatternSerial();
    
public intgetNodeType()

	return _nodeType;
    
protected booleanhasPredicates()

	return _predicates != null && _predicates.size() > 0;
    
public booleanisWildcard()

	return _isEpsilon && hasPredicates() == false;
    
public voidreduceKernelPattern()

	_isEpsilon = true;
    
public voidsetParser(com.sun.org.apache.xalan.internal.xsltc.compiler.Parser parser)

	super.setParser(parser);
	if (_predicates != null) {
	    final int n = _predicates.size();
	    for (int i = 0; i < n; i++) {
		final Predicate exp = (Predicate)_predicates.elementAt(i);
		exp.setParser(parser);
		exp.setParent(this);
	    }
	}
    
public com.sun.org.apache.xalan.internal.xsltc.compiler.StepPatternsetPredicates(java.util.Vector predicates)

	_predicates = predicates;
	return(this);
    
public voidsetPriority(double priority)

	_priority = priority;
    
public java.lang.StringtoString()

	final StringBuffer buffer = new StringBuffer("stepPattern(\"");
    buffer.append(Axis.getNames(_axis))
	    .append("\", ")
	    .append(_isEpsilon ? 
			("epsilon{" + Integer.toString(_nodeType) + "}") :
			 Integer.toString(_nodeType));
	if (_predicates != null)
	    buffer.append(", ").append(_predicates.toString());
	return buffer.append(')").toString();
    
public voidtranslate(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)

	final ConstantPoolGen cpg = classGen.getConstantPool();
	final InstructionList il = methodGen.getInstructionList();

	if (hasPredicates()) {
	    switch (_contextCase) {
	    case NO_CONTEXT:
		translateNoContext(classGen, methodGen);
		break;
		
	    case SIMPLE_CONTEXT:
		translateSimpleContext(classGen, methodGen);
		break;
		
	    default:
		translateGeneralContext(classGen, methodGen);
		break;
	    }
	}
	else if (isWildcard()) {
	    il.append(POP); 	// true list falls through
	}
	else {
	    translateKernel(classGen, methodGen);
	}
    
private voidtranslateGeneralContext(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)

	final ConstantPoolGen cpg = classGen.getConstantPool();
	final InstructionList il = methodGen.getInstructionList();

	int iteratorIndex = 0;
	BranchHandle ifBlock = null;
	LocalVariableGen iter, node, node2;
	final String iteratorName = getNextFieldName();

	// Store node on the stack into a local variable
	node = methodGen.addLocalVariable("step_pattern_tmp1", 
					  Util.getJCRefType(NODE_SIG),
					  il.getEnd(), null);
	il.append(new ISTORE(node.getIndex()));

	// Create a new local to store the iterator
	iter = methodGen.addLocalVariable("step_pattern_tmp2", 
					  Util.getJCRefType(NODE_ITERATOR_SIG),
					  il.getEnd(), null);

	// Add a new private field if this is the main class
	if (!classGen.isExternal()) {
	    final Field iterator =
		new Field(ACC_PRIVATE, 
			  cpg.addUtf8(iteratorName),
			  cpg.addUtf8(NODE_ITERATOR_SIG),
			  null, cpg.getConstantPool());
	    classGen.addField(iterator);
	    iteratorIndex = cpg.addFieldref(classGen.getClassName(), 
					    iteratorName,
					    NODE_ITERATOR_SIG);

	    il.append(classGen.loadTranslet());
	    il.append(new GETFIELD(iteratorIndex));
	    il.append(DUP);
	    il.append(new ASTORE(iter.getIndex()));
	    ifBlock = il.append(new IFNONNULL(null));
	    il.append(classGen.loadTranslet());
	}	

	// Compile the step created at type checking time
	_step.translate(classGen, methodGen);
	il.append(new ASTORE(iter.getIndex()));

	// If in the main class update the field too
	if (!classGen.isExternal()) {
	    il.append(new ALOAD(iter.getIndex()));
	    il.append(new PUTFIELD(iteratorIndex));
	    ifBlock.setTarget(il.append(NOP));
	}

	// Get the parent of the node on the stack
	il.append(methodGen.loadDOM());
	il.append(new ILOAD(node.getIndex()));
	int index = cpg.addInterfaceMethodref(DOM_INTF,
					      GET_PARENT, GET_PARENT_SIG);
	il.append(new INVOKEINTERFACE(index, 2));

	// Initialize the iterator with the parent
	il.append(new ALOAD(iter.getIndex()));
	il.append(SWAP);
	il.append(methodGen.setStartNode());

	/* 
	 * Inline loop:
	 *
	 * int node2;
	 * while ((node2 = iter.next()) != NodeIterator.END 
	 *		  && node2 < node);
	 * return node2 == node; 
	 */
	BranchHandle skipNext;
	InstructionHandle begin, next;
	node2 = methodGen.addLocalVariable("step_pattern_tmp3", 
					   Util.getJCRefType(NODE_SIG),
					   il.getEnd(), null);

	skipNext = il.append(new GOTO(null));
	next = il.append(new ALOAD(iter.getIndex()));
	begin = il.append(methodGen.nextNode());
	il.append(DUP);
	il.append(new ISTORE(node2.getIndex()));
	_falseList.add(il.append(new IFLT(null)));	// NodeIterator.END

	il.append(new ILOAD(node2.getIndex()));
	il.append(new ILOAD(node.getIndex()));
	il.append(new IF_ICMPLT(next));

	il.append(new ILOAD(node2.getIndex()));
	il.append(new ILOAD(node.getIndex()));
	_falseList.add(il.append(new IF_ICMPNE(null)));

	skipNext.setTarget(begin);
    
private voidtranslateKernel(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)

	final ConstantPoolGen cpg = classGen.getConstantPool();
	final InstructionList il = methodGen.getInstructionList();
	
	if (_nodeType == DTM.ELEMENT_NODE) {
	    final int check = cpg.addInterfaceMethodref(DOM_INTF,
							"isElement", "(I)Z");
	    il.append(methodGen.loadDOM());
	    il.append(SWAP);
	    il.append(new INVOKEINTERFACE(check, 2));
	
	    // Need to allow for long jumps here
	    final BranchHandle icmp = il.append(new IFNE(null));
	    _falseList.add(il.append(new GOTO_W(null)));
	    icmp.setTarget(il.append(NOP));
	}
	else if (_nodeType == DTM.ATTRIBUTE_NODE) {
	    final int check = cpg.addInterfaceMethodref(DOM_INTF,
							"isAttribute", "(I)Z");
	    il.append(methodGen.loadDOM());
	    il.append(SWAP);
	    il.append(new INVOKEINTERFACE(check, 2));
	
	    // Need to allow for long jumps here
	    final BranchHandle icmp = il.append(new IFNE(null));
	    _falseList.add(il.append(new GOTO_W(null)));
	    icmp.setTarget(il.append(NOP));
	}
	else {
	    // context node is on the stack
	    final int getEType = cpg.addInterfaceMethodref(DOM_INTF,
							  "getExpandedTypeID",
                                                          "(I)I");
	    il.append(methodGen.loadDOM());
	    il.append(SWAP);
	    il.append(new INVOKEINTERFACE(getEType, 2));
	    il.append(new PUSH(cpg, _nodeType));
	
	    // Need to allow for long jumps here
	    final BranchHandle icmp = il.append(new IF_ICMPEQ(null));
	    _falseList.add(il.append(new GOTO_W(null)));
	    icmp.setTarget(il.append(NOP));
	}
    
private voidtranslateNoContext(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)

	final ConstantPoolGen cpg = classGen.getConstantPool();
	final InstructionList il = methodGen.getInstructionList();

	// Push current node on the stack
	il.append(methodGen.loadCurrentNode());
	il.append(SWAP);

	// Overwrite current node with matching node
	il.append(methodGen.storeCurrentNode());

	// If pattern not reduced then check kernel
	if (!_isEpsilon) {
	    il.append(methodGen.loadCurrentNode());
	    translateKernel(classGen, methodGen);
	}

	// Compile the expressions within the predicates
	final int n = _predicates.size();
	for (int i = 0; i < n; i++) {
	    Predicate pred = (Predicate)_predicates.elementAt(i);
	    Expression exp = pred.getExpr();
	    exp.translateDesynthesized(classGen, methodGen);
	    _trueList.append(exp._trueList);
	    _falseList.append(exp._falseList);
	}

	// Backpatch true list and restore current iterator/node
	InstructionHandle restore;
	restore = il.append(methodGen.storeCurrentNode());
	backPatchTrueList(restore);
	BranchHandle skipFalse = il.append(new GOTO(null));

	// Backpatch false list and restore current iterator/node
	restore = il.append(methodGen.storeCurrentNode());
	backPatchFalseList(restore);
	_falseList.add(il.append(new GOTO(null)));

	// True list falls through
	skipFalse.setTarget(il.append(NOP));
    
private voidtranslateSimpleContext(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)

	int index;
	final ConstantPoolGen cpg = classGen.getConstantPool();
	final InstructionList il = methodGen.getInstructionList();

	// Store matching node into a local variable
	LocalVariableGen match;
	match = methodGen.addLocalVariable("step_pattern_tmp1", 
					   Util.getJCRefType(NODE_SIG),
					   il.getEnd(), null);
	il.append(new ISTORE(match.getIndex()));

	// If pattern not reduced then check kernel
	if (!_isEpsilon) {
	    il.append(new ILOAD(match.getIndex()));
 	    translateKernel(classGen, methodGen);
	}

	// Push current iterator and current node on the stack
	il.append(methodGen.loadCurrentNode());
	il.append(methodGen.loadIterator());

	// Create a new matching iterator using the matching node
	index = cpg.addMethodref(MATCHING_ITERATOR, "<init>", 
				 "(I" + NODE_ITERATOR_SIG + ")V");

        // Backwards branches are prohibited if an uninitialized object is
        // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed.
        // We don't know whether this code might contain backwards branches,
        // so we mustn't create the new object until after we've created
        // the suspect arguments to its constructor.  Instead we calculate
        // the values of the arguments to the constructor first, store them
        // in temporary variables, create the object and reload the
        // arguments from the temporaries to avoid the problem.

	_step.translate(classGen, methodGen);
        LocalVariableGen stepIteratorTemp =
                methodGen.addLocalVariable("step_pattern_tmp2",
                                           Util.getJCRefType(NODE_ITERATOR_SIG),
                                           il.getEnd(), null);
        il.append(new ASTORE(stepIteratorTemp.getIndex()));

	il.append(new NEW(cpg.addClass(MATCHING_ITERATOR)));
	il.append(DUP);
	il.append(new ILOAD(match.getIndex()));
        il.append(new ALOAD(stepIteratorTemp.getIndex()));
	il.append(new INVOKESPECIAL(index));

	// Get the parent of the matching node
	il.append(methodGen.loadDOM());
	il.append(new ILOAD(match.getIndex()));
	index = cpg.addInterfaceMethodref(DOM_INTF, GET_PARENT, GET_PARENT_SIG);
	il.append(new INVOKEINTERFACE(index, 2));

	// Start the iterator with the parent 
	il.append(methodGen.setStartNode());

	// Overwrite current iterator and current node
	il.append(methodGen.storeIterator());
	il.append(new ILOAD(match.getIndex()));
	il.append(methodGen.storeCurrentNode());

	// Translate the expression of the predicate 
	Predicate pred = (Predicate) _predicates.elementAt(0);
	Expression exp = pred.getExpr();
	exp.translateDesynthesized(classGen, methodGen);

	// Backpatch true list and restore current iterator/node
	InstructionHandle restore = il.append(methodGen.storeIterator());
	il.append(methodGen.storeCurrentNode());
	exp.backPatchTrueList(restore);
	BranchHandle skipFalse = il.append(new GOTO(null));

	// Backpatch false list and restore current iterator/node
	restore = il.append(methodGen.storeIterator());
	il.append(methodGen.storeCurrentNode());
	exp.backPatchFalseList(restore);
	_falseList.add(il.append(new GOTO(null)));

	// True list falls through
	skipFalse.setTarget(il.append(NOP));
    
public com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypetypeCheck(com.sun.org.apache.xalan.internal.xsltc.compiler.SymbolTable stable)

        if (hasPredicates()) {
            // Type check all the predicates (e -> position() = e)
            final int n = _predicates.size();
            for (int i = 0; i < n; i++) {
                final Predicate pred = (Predicate)_predicates.elementAt(i);
                pred.typeCheck(stable);
            }

            // Analyze context cases
            _contextCase = analyzeCases();

            Step step = null;

            // Create an instance of Step to do the translation
            if (_contextCase == SIMPLE_CONTEXT) {
                Predicate pred = (Predicate)_predicates.elementAt(0);
                if (pred.isNthPositionFilter()) {
                    _contextCase = GENERAL_CONTEXT;
                    step = new Step(_axis, _nodeType, _predicates);
                } else {
                    step = new Step(_axis, _nodeType, null);
                }
            } else if (_contextCase == GENERAL_CONTEXT) {
                final int len = _predicates.size();
                for (int i = 0; i < len; i++) {
                    ((Predicate)_predicates.elementAt(i)).dontOptimize();
                }

                step = new Step(_axis, _nodeType, _predicates);
            }
            
            if (step != null) {
                step.setParser(getParser());
                step.typeCheck(stable);
                _step = step;
            }
        }
        return _axis == Axis.CHILD ? Type.Element : Type.Attribute;