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 2003/12/23 21:02:46 UTC
cvs commit: xml-xalan/java/src/org/apache/xalan/xsltc/compiler/util NamedMethodGenerator.java
santiagopg 2003/12/23 12:02:46
Modified: java/src/org/apache/xalan/xsltc/compiler CallTemplate.java
Param.java ParameterRef.java Template.java
VariableBase.java WithParam.java
java/src/org/apache/xalan/xsltc/compiler/util
NamedMethodGenerator.java
Log:
The parameter optimization implemented in 2.5.2 does not work in all cases. The problem (see Bugzilla 25449) is that a param's default value needs to be compiled multiples when there are mulitple calls the a template none of which has a correspoding with-param. However, ASTs store an internal state which is not restored after compilation; consequently, only the first compilation is guaranteed to succeed. Stated differently, the AST cannot be operated as a graph because sub-tree sharing causes problems.
The optimization has now been changed so that a param default value is compiled only once by the callee instead of multiple times by each caller. A caller will now pass 'null' when there is no with-param; a callee will only initialize a param if its value is 'null'. This ensures that default values are compiled exactly once while at the same time preserving the XSLT semantics.
Revision Changes Path
1.16 +46 -112 xml-xalan/java/src/org/apache/xalan/xsltc/compiler/CallTemplate.java
Index: CallTemplate.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/CallTemplate.java,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- CallTemplate.java 6 Oct 2003 13:53:13 -0000 1.15
+++ CallTemplate.java 23 Dec 2003 20:02:45 -0000 1.16
@@ -80,23 +80,24 @@
import java.util.Vector;
final class CallTemplate extends Instruction {
+
+ /**
+ * Name of template to call.
+ */
private QName _name;
- // The array of effective parameters in this CallTemplate.
- // An object in this array can be either a WithParam or
- // a Param if no WithParam exists for a particular parameter.
+ /**
+ * The array of effective parameters in this CallTemplate. An object in
+ * this array can be either a WithParam or a Param if no WithParam
+ * exists for a particular parameter.
+ */
private Object[] _parameters = null;
-
- // True if we need to create temporary variables to hold
- // the parameter values.
- private boolean _createTempVar = false;
-
- // The corresponding template which this CallTemplate calls.
+
+ /**
+ * The corresponding template which this CallTemplate calls.
+ */
private Template _calleeTemplate = null;
- // The array to hold the old load instructions for the parameters.
- private org.apache.bcel.generic.Instruction[] _oldLoadInstructions;
-
public void display(int indent) {
indent(indent);
System.out.print("CallTemplate");
@@ -128,23 +129,16 @@
return Type.Void;
}
- /**
- * Translate call-template.
- * A parameter frame is pushed only if some template in the stylesheet
- * uses parameters.
- * TODO: optimize by checking if the callee has parameters.
- */
public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
final Stylesheet stylesheet = classGen.getStylesheet();
final ConstantPoolGen cpg = classGen.getConstantPool();
final InstructionList il = methodGen.getInstructionList();
-
+ // If there are Params in the stylesheet or WithParams in this call?
if (stylesheet.hasLocalParams() || hasContents()) {
_calleeTemplate = getCalleeTemplate();
- // Build the parameter list if the called template is
- // a simple named template.
+ // Build the parameter list if the called template is simple named
if (_calleeTemplate != null) {
buildParameterList();
}
@@ -157,95 +151,49 @@
PUSH_PARAM_FRAME_SIG);
il.append(classGen.loadTranslet());
il.append(new INVOKEVIRTUAL(push));
- // Translate with-params
translateContents(classGen, methodGen);
}
}
+ // Generate a valid Java method name
final String className = stylesheet.getClassName();
- // Generate a valid Java method name
- String methodName = Util.escape(_name.toString());
+ String methodName = Util.escape(_name.toString());
+ // Load standard arguments
il.append(classGen.loadTranslet());
il.append(methodGen.loadDOM());
il.append(methodGen.loadIterator());
il.append(methodGen.loadHandler());
il.append(methodGen.loadCurrentNode());
- String methodSig = "(" + DOM_INTF_SIG + NODE_ITERATOR_SIG
- + TRANSLET_OUTPUT_SIG + NODE_SIG;
+
+ // Initialize prefix of method signature
+ StringBuffer methodSig = new StringBuffer("(" + DOM_INTF_SIG
+ + NODE_ITERATOR_SIG + TRANSLET_OUTPUT_SIG + NODE_SIG);
+ // If calling a simply named template, push actual arguments
if (_calleeTemplate != null) {
Vector calleeParams = _calleeTemplate.getParameters();
int numParams = _parameters.length;
- org.apache.bcel.generic.Type objectType = null;
- if (_createTempVar) {
- _oldLoadInstructions = new org.apache.bcel.generic.Instruction[numParams];
- objectType = Util.getJCRefType(OBJECT_SIG);
- }
-
- // Translate all effective WithParams and Params in the list
for (int i = 0; i < numParams; i++) {
- methodSig = methodSig + OBJECT_SIG;
SyntaxTreeNode node = (SyntaxTreeNode)_parameters[i];
- node.translate(classGen, methodGen);
-
- // Store the parameter value in a local variable if default
- // parameters are used. In this case the default value of a
- // parameter may reference another parameter declared earlier.
- if (_createTempVar) {
- il.append(DUP);
-
- // The name of the variable used to hold the value of a
- // parameter
- String name = "call$template$" + Util.escape(_name.toString())
- + "$" + getParameterName(node);
-
- // Search for the local variable first, only add it
- // if it does not exist.
- LocalVariableGen local = methodGen.getLocalVariable(name);
-
- if (local == null) {
- local = methodGen.addLocalVariable2(name,
- objectType,
- il.getEnd());
- }
-
- // Store the parameter value into a variable.
- il.append(new ASTORE(local.getIndex()));
-
- // Update the load instructions of the Param objects so that
- // they point to the local variables. Store the old load
- // instructions in the _oldLoadInstructions array so that
- // we can restore them later.
- if (node instanceof Param) {
- Param param = (Param)node;
- org.apache.bcel.generic.Instruction oldInstruction =
- param.setLoadInstruction(new ALOAD(local.getIndex()));
- _oldLoadInstructions[param.getIndex()] = oldInstruction;
- }
- else if (node instanceof WithParam) {
- Param param = (Param)calleeParams.elementAt(i);
- org.apache.bcel.generic.Instruction oldInstruction =
- param.setLoadInstruction(new ALOAD(local.getIndex()));
- _oldLoadInstructions[param.getIndex()] = oldInstruction;
- }
- }
- }
-
- // Restore the old load instructions for the Params.
- if (_createTempVar) {
- for (int i = 0; i < numParams; i++) {
- Param param = (Param)calleeParams.elementAt(i);
- param.setLoadInstruction(_oldLoadInstructions[i]);
- }
- }
- }
-
- methodSig = methodSig + ")V";
+ methodSig.append(OBJECT_SIG); // append Object to signature
+
+ // Push 'null' if Param to indicate no actual parameter specified
+ if (node instanceof Param) {
+ il.append(ACONST_NULL);
+ }
+ else { // translate WithParam
+ node.translate(classGen, methodGen);
+ }
+ }
+ }
+
+ // Complete signature and generate invokevirtual call
+ methodSig.append(")V");
il.append(new INVOKEVIRTUAL(cpg.addMethodref(className,
methodName,
- methodSig)));
+ methodSig.toString())));
// Do not need to call Translet.popParamFrame() if we are
// calling a simple named template.
@@ -270,8 +218,7 @@
WithParam withParam = (WithParam)node;
return Util.escape(withParam.getName().toString());
}
- else
- return null;
+ return null;
}
/**
@@ -282,6 +229,7 @@
public Template getCalleeTemplate() {
Stylesheet stylesheet = getXSLTC().getStylesheet();
Vector templates = stylesheet.getAllValidTemplates();
+
int size = templates.size();
for (int i = 0; i < size; i++) {
Template t = (Template)templates.elementAt(i);
@@ -312,9 +260,13 @@
int count = elementCount();
for (int i = 0; i < count; i++) {
Object node = elementAt(i);
+
+ // Ignore if not WithParam
if (node instanceof WithParam) {
WithParam withParam = (WithParam)node;
QName name = withParam.getName();
+
+ // Search for a Param with the same name
for (int k = 0; k < numParams; k++) {
Object object = _parameters[k];
if (object instanceof Param
@@ -332,24 +284,6 @@
}
}
}
-
- // Set the _createTempVar flag to true if the select expression
- // in a parameter may reference another parameter.
- for (int i = 0; i < numParams; i++) {
- if (_parameters[i] instanceof Param) {
- Param param = (Param)_parameters[i];
- Expression expr = param.getExpression();
- if ((expr != null || param.elementCount() != 0)
- && !(expr instanceof CastExpr
- && (((CastExpr)expr).getExpr() instanceof LiteralExpr
- || ((CastExpr)expr).getExpr() instanceof BooleanExpr)))
- {
- _createTempVar = true;
- break;
- }
- }
- }
- }
-
+ }
}
1.26 +34 -39 xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Param.java
Index: Param.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Param.java,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- Param.java 11 Nov 2003 14:40:28 -0000 1.25
+++ Param.java 23 Dec 2003 20:02:45 -0000 1.26
@@ -67,7 +67,9 @@
package org.apache.xalan.xsltc.compiler;
import org.apache.bcel.classfile.Field;
+import org.apache.bcel.generic.BranchHandle;
import org.apache.bcel.generic.CHECKCAST;
+import org.apache.bcel.generic.IFNONNULL;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.Instruction;
@@ -80,38 +82,42 @@
import org.apache.xalan.xsltc.compiler.util.ReferenceType;
import org.apache.xalan.xsltc.compiler.util.Type;
import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
-
import org.apache.xalan.xsltc.runtime.BasisLibrary;
+
final class Param extends VariableBase {
- // True if this Param is declared in a simple named template.
- // This is used to optimize codegen for parameter passing
- // in named templates.
+ /**
+ * True if this Param is declared in a simple named template.
+ * This is used to optimize codegen for parameter passing
+ * in named templates.
+ */
private boolean _isInSimpleNamedTemplate = false;
- // The order index of the parameter, which is only used when
- // the Param is declared in a simple named template.
- private int _index = 0;
-
/**
* Display variable as single string
*/
public String toString() {
- return("param("+_name+")");
+ return "param(" + _name + ")";
}
/**
- * Set the index of this parameter
+ * Set the instruction for loading the value of this variable onto the
+ * JVM stack and returns the old instruction.
*/
- public void setIndex(int index) {
- _index = index;
+ public Instruction setLoadInstruction(Instruction instruction) {
+ Instruction tmp = _loadInstruction;
+ _loadInstruction = instruction;
+ return tmp;
}
/**
- * Return the index of this parameter
+ * Set the instruction for storing a value from the stack into this
+ * variable and returns the old instruction.
*/
- public int getIndex() {
- return _index;
+ public Instruction setStoreInstruction(Instruction instruction) {
+ Instruction tmp = _storeInstruction;
+ _storeInstruction = instruction;
+ return tmp;
}
/**
@@ -198,33 +204,33 @@
}
public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
-
final ConstantPoolGen cpg = classGen.getConstantPool();
final InstructionList il = methodGen.getInstructionList();
if (_ignore) return;
- // _ignore = true;
+ _ignore = true;
/*
* To fix bug 24518 related to setting parameters of the form
- * {namespaceuri}localName
- * which will get mapped to an instance variable in the class
- * Hence a parameter of the form "{http://foo.bar}xyz"
- * will be replaced with the corresponding values
- * by the BasisLibrary's utility method mapQNametoJavaName
- * and thus get mapped to legal java variable names
+ * {namespaceuri}localName which will get mapped to an instance
+ * variable in the class.
*/
final String name = BasisLibrary.mapQNameToJavaName(_name.toString());
final String signature = _type.toSignature();
final String className = _type.getClassName();
if (isLocal()) {
-
- // %OPT% Only translate the value and put it on the
- // stack if this Param is in a simple named template.
- // No need to call Translet.addParameter().
+ /*
+ * If simple named template then generate a conditional init of the
+ * param using its default value:
+ * if (param == null) param = <default-value>
+ */
if (_isInSimpleNamedTemplate) {
+ il.append(loadInstruction());
+ BranchHandle ifBlock = il.append(new IFNONNULL(null));
translateValue(classGen, methodGen);
+ il.append(storeInstruction());
+ ifBlock.setTarget(il.append(NOP));
return;
}
@@ -282,15 +288,4 @@
}
}
}
-
- /**
- * Set the instruction handle for loading the value of this
- * variable onto the JVM stack and returns the old instruction handle.
- */
- public Instruction setLoadInstruction(Instruction instruction) {
- Instruction tmp = _loadInstruction;
- _loadInstruction = instruction;
- return tmp;
- }
-
}
1.16 +10 -12 xml-xalan/java/src/org/apache/xalan/xsltc/compiler/ParameterRef.java
Index: ParameterRef.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/ParameterRef.java,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- ParameterRef.java 11 Nov 2003 14:40:28 -0000 1.15
+++ ParameterRef.java 23 Dec 2003 20:02:45 -0000 1.16
@@ -73,11 +73,15 @@
import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
import org.apache.xalan.xsltc.compiler.util.NodeSetType;
-
import org.apache.xalan.xsltc.runtime.BasisLibrary;
+
final class ParameterRef extends VariableRefBase {
- QName _name= null ;
+ /**
+ * Name of param being referenced.
+ */
+ QName _name = null;
+
public ParameterRef(Param param) {
super(param);
_name = param._name;
@@ -88,22 +92,16 @@
return "parameter-ref("+_variable.getName()+'/'+_variable.getType()+')';
}
- public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
+ public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
final ConstantPoolGen cpg = classGen.getConstantPool();
final InstructionList il = methodGen.getInstructionList();
/*
* To fix bug 24518 related to setting parameters of the form
- * {namespaceuri}localName
- * which will get mapped to an instance variable in the class
- * Hence a parameter of the form "{http://foo.bar}xyz"
- * will be replaced with the corresponding values
- * by the BasisLibrary's utility method mapQNametoJavaName
- * and thus get mapped to legal java variable names
+ * {namespaceuri}localName, which will get mapped to an instance
+ * variable in the class.
*/
-
final String name = BasisLibrary.mapQNameToJavaName (_name.toString());
-
final String signature = _type.toSignature();
if (_variable.isLocal()) {
1.23 +8 -48 xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Template.java
Index: Template.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Template.java,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -r1.22 -r1.23
--- Template.java 8 Jul 2003 20:32:51 -0000 1.22
+++ Template.java 23 Dec 2003 20:02:45 -0000 1.23
@@ -115,7 +115,6 @@
}
public void addParameter(Param param) {
- param.setIndex(_parameters.size());
_parameters.addElement(param);
}
@@ -352,58 +351,19 @@
// %OPT% Special handling for simple named templates.
if (_isSimpleNamedTemplate && methodGen instanceof NamedMethodGenerator) {
- NamedMethodGenerator namedMethodGen = (NamedMethodGenerator)methodGen;
int numParams = _parameters.size();
- // Update the load instructions of the Params, so that they
- // are loaded from the method parameters.
+ NamedMethodGenerator namedMethodGen = (NamedMethodGenerator)methodGen;
+
+ // Update load/store instructions to access Params from the stack
for (int i = 0; i < numParams; i++) {
Param param = (Param)_parameters.elementAt(i);
param.setLoadInstruction(namedMethodGen.loadParameter(i));
+ param.setStoreInstruction(namedMethodGen.storeParameter(i));
}
- // Translate all children except the parameters.
- // The parameters are translated in CallTemplates if necessary.
- translateContentsWithoutParams(classGen, methodGen);
}
- else {
- translateContents(classGen, methodGen);
- }
-
+
+ translateContents(classGen, methodGen);
il.setPositions(true);
}
-
- /**
- * Call translate() on all child syntax tree nodes except the parameters.
- *
- * This is used for a simple named template, where the paramters are
- * translated in the CallTemplate if necessary.
- *
- * @param classGen BCEL Java class generator
- * @param methodGen BCEL Java method generator
- */
- protected void translateContentsWithoutParams(
- ClassGenerator classGen,
- MethodGenerator methodGen) {
- // Call translate() on all child nodes
- final int n = elementCount();
- for (int i = 0; i < n; i++) {
- final SyntaxTreeNode item = (SyntaxTreeNode) elementAt(i);
- if (!(item instanceof Param)) {
- item.translate(classGen, methodGen);
- }
- }
-
- // After translation, unmap any registers for any
- // variables / parameters
- // that were declared in this scope. Performing this unmapping in the
- // same AST scope as the declaration deals with the problems of
- // references falling out-of-scope inside the for-each element.
- // (the cause of which being 'lazy' register allocation for references)
- for (int i = 0; i < n; i++) {
- if (elementAt(i) instanceof Variable) {
- final Variable var = (Variable) elementAt(i);
- var.unmapRegister(methodGen);
- }
- }
- }
-
+
}
1.21 +18 -4 xml-xalan/java/src/org/apache/xalan/xsltc/compiler/VariableBase.java
Index: VariableBase.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/VariableBase.java,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -r1.20 -r1.21
--- VariableBase.java 19 Dec 2003 15:26:48 -0000 1.20
+++ VariableBase.java 23 Dec 2003 20:02:45 -0000 1.21
@@ -90,6 +90,7 @@
protected boolean _isLocal; // True if the variable is local.
protected LocalVariableGen _local; // Reference to JVM variable
protected Instruction _loadInstruction; // Instruction to load JVM variable
+ protected Instruction _storeInstruction; // Instruction to load JVM variable
protected Expression _select; // Reference to variable expression
protected String select; // Textual repr. of variable expr.
@@ -173,14 +174,27 @@
}
/**
- * Returns a handle to the instruction for loading the value of this
- * variable onto the JVM stack.
+ * Returns an instruction for loading the value of this variable onto
+ * the JVM stack.
*/
public Instruction loadInstruction() {
final Instruction instr = _loadInstruction;
- if (_loadInstruction == null)
+ if (_loadInstruction == null) {
_loadInstruction = _type.LOAD(_local.getIndex());
+ }
return _loadInstruction;
+ }
+
+ /**
+ * Returns an instruction for storing a value from the JVM stack
+ * into this variable.
+ */
+ public Instruction storeInstruction() {
+ final Instruction instr = _storeInstruction;
+ if (_storeInstruction == null) {
+ _storeInstruction = _type.STORE(_local.getIndex());
+ }
+ return _storeInstruction;
}
/**
1.15 +14 -7 xml-xalan/java/src/org/apache/xalan/xsltc/compiler/WithParam.java
Index: WithParam.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/WithParam.java,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- WithParam.java 19 Dec 2003 15:26:48 -0000 1.14
+++ WithParam.java 23 Dec 2003 20:02:45 -0000 1.15
@@ -79,14 +79,22 @@
final class WithParam extends Instruction {
+ /**
+ * Parameter's name.
+ */
private QName _name;
+
+ /**
+ * Parameter's default value.
+ */
private Expression _select;
- // %OPT% This is set to true when the WithParam is used in a
- // CallTemplate for a simple named template. If this is true,
- // the parameters are passed to the named template through method
- // arguments rather than using the expensive Translet.addParameter()
- // call.
+ /**
+ * %OPT% This is set to true when the WithParam is used in a CallTemplate
+ * for a simple named template. If this is true, the parameters are
+ * passed to the named template through method arguments rather than
+ * using the expensive Translet.addParameter() call.
+ */
private boolean _doParameterOptimization = false;
/**
@@ -116,7 +124,6 @@
_doParameterOptimization = flag;
}
-
/**
* The contents of a <xsl:with-param> elements are either in the element's
* 'select' attribute (this has precedence) or in the element body.
1.6 +6 -1 xml-xalan/java/src/org/apache/xalan/xsltc/compiler/util/NamedMethodGenerator.java
Index: NamedMethodGenerator.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/util/NamedMethodGenerator.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- NamedMethodGenerator.java 23 Jun 2003 18:23:15 -0000 1.5
+++ NamedMethodGenerator.java 23 Dec 2003 20:02:46 -0000 1.6
@@ -64,6 +64,7 @@
package org.apache.xalan.xsltc.compiler.util;
import org.apache.bcel.generic.ALOAD;
+import org.apache.bcel.generic.ASTORE;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionList;
@@ -96,5 +97,9 @@
public Instruction loadParameter(int index) {
return new ALOAD(index + PARAM_START_INDEX);
+ }
+
+ public Instruction storeParameter(int index) {
+ return new ASTORE(index + PARAM_START_INDEX);
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: xalan-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: xalan-cvs-help@xml.apache.org