- /*
- * Copyright 2001-2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /*
- * $Id: StepPattern.java,v 1.24 2004/02/16 22:24:29 minchau Exp $
- */
-
- package com.sun.org.apache.xalan.internal.xsltc.compiler;
-
- import java.util.Vector;
-
- import com.sun.org.apache.bcel.internal.classfile.Field;
- import com.sun.org.apache.bcel.internal.generic.ALOAD;
- import com.sun.org.apache.bcel.internal.generic.ASTORE;
- import com.sun.org.apache.bcel.internal.generic.BranchHandle;
- import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
- import com.sun.org.apache.bcel.internal.generic.GETFIELD;
- import com.sun.org.apache.bcel.internal.generic.GOTO;
- import com.sun.org.apache.bcel.internal.generic.GOTO_W;
- import com.sun.org.apache.bcel.internal.generic.IFLT;
- import com.sun.org.apache.bcel.internal.generic.IFNE;
- import com.sun.org.apache.bcel.internal.generic.IFNONNULL;
- import com.sun.org.apache.bcel.internal.generic.IF_ICMPEQ;
- import com.sun.org.apache.bcel.internal.generic.IF_ICMPLT;
- import com.sun.org.apache.bcel.internal.generic.IF_ICMPNE;
- import com.sun.org.apache.bcel.internal.generic.ILOAD;
- import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
- import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
- import com.sun.org.apache.bcel.internal.generic.ISTORE;
- import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
- import com.sun.org.apache.bcel.internal.generic.InstructionList;
- import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
- import com.sun.org.apache.bcel.internal.generic.NEW;
- import com.sun.org.apache.bcel.internal.generic.PUSH;
- import com.sun.org.apache.bcel.internal.generic.PUTFIELD;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
- import com.sun.org.apache.xalan.internal.xsltc.dom.Axis;
- import com.sun.org.apache.xml.internal.dtm.DTM;
-
- /**
- * @author Jacek Ambroziak
- * @author Santiago Pericas-Geertsen
- * @author Erwin Bolwidt <ejb@klomp.org>
- */
- class StepPattern extends RelativePathPattern {
-
- private static final int NO_CONTEXT = 0;
- private static final int SIMPLE_CONTEXT = 1;
- private static final int GENERAL_CONTEXT = 2;
-
- protected final int _axis;
- protected final int _nodeType;
- protected Vector _predicates;
-
- private Step _step = null;
- private boolean _isEpsilon = false;
- private int _contextCase;
-
- private double _priority = Double.MAX_VALUE;
-
- public StepPattern(int axis, int nodeType, Vector predicates) {
- _axis = axis;
- _nodeType = nodeType;
- _predicates = predicates;
- }
-
- public void setParser(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 int getNodeType() {
- return _nodeType;
- }
-
- public void setPriority(double priority) {
- _priority = priority;
- }
-
- public StepPattern getKernelPattern() {
- return this;
- }
-
- public boolean isWildcard() {
- return _isEpsilon && hasPredicates() == false;
- }
-
- public StepPattern setPredicates(Vector predicates) {
- _predicates = predicates;
- return(this);
- }
-
- protected boolean hasPredicates() {
- return _predicates != null && _predicates.size() > 0;
- }
-
- public double getDefaultPriority() {
- 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 int getAxis() {
- return _axis;
- }
-
- public void reduceKernelPattern() {
- _isEpsilon = true;
- }
-
- public String toString() {
- final StringBuffer buffer = new StringBuffer("stepPattern(\"");
- buffer.append(Axis.names[_axis])
- .append("\", ")
- .append(_isEpsilon ?
- ("epsilon{" + Integer.toString(_nodeType) + "}") :
- Integer.toString(_nodeType));
- if (_predicates != null)
- buffer.append(", ").append(_predicates.toString());
- return buffer.append(')').toString();
- }
-
- private int analyzeCases() {
- 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;
- }
-
- private String getNextFieldName() {
- return "__step_pattern_iter_" + getXSLTC().nextStepPatternSerial();
- }
-
- public Type typeCheck(SymbolTable stable) throws TypeCheckError {
- 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;
- }
-
- private void translateKernel(ClassGenerator classGen,
- 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 void translateNoContext(ClassGenerator classGen,
- 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 void translateSimpleContext(ClassGenerator classGen,
- 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");
- il.append(new NEW(cpg.addClass(MATCHING_ITERATOR)));
- il.append(DUP);
- il.append(new ILOAD(match.getIndex()));
- _step.translate(classGen, methodGen);
- 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));
- }
-
- private void translateGeneralContext(ClassGenerator classGen,
- 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);
- }
-
- public void translate(ClassGenerator classGen, 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);
- }
- }
- }