jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/FunctionCall.java

Print this page




  37 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
  38 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  39 import com.sun.org.apache.bcel.internal.generic.InstructionConstants;
  40 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  41 import com.sun.org.apache.bcel.internal.generic.InvokeInstruction;
  42 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
  43 import com.sun.org.apache.bcel.internal.generic.NEW;
  44 import com.sun.org.apache.bcel.internal.generic.PUSH;
  45 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType;
  46 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  47 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  48 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
  49 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  50 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType;
  51 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MultiHashtable;
  52 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ObjectType;
  53 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
  54 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  55 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  56 import com.sun.org.apache.xalan.internal.utils.ObjectFactory;

  57 
  58 /**
  59  * @author Jacek Ambroziak
  60  * @author Santiago Pericas-Geertsen
  61  * @author Morten Jorgensen
  62  * @author Erwin Bolwidt <ejb@klomp.org>
  63  * @author Todd Miller
  64  */
  65 class FunctionCall extends Expression {
  66 
  67     // Name of this function call
  68     private QName  _fname;
  69     // Arguments to this function call (might not be any)
  70     private final Vector _arguments;
  71     // Empty argument list, used for certain functions
  72     private final static Vector EMPTY_ARG_LIST = new Vector(0);
  73 
  74     // Valid namespaces for Java function-call extension
  75     protected final static String EXT_XSLTC =
  76         TRANSLET_URI;


 139     private static final Hashtable _java2Internal = new Hashtable();
 140 
 141     // The mappings between EXSLT extension namespaces and implementation classes
 142     private static final Hashtable _extensionNamespaceTable = new Hashtable();
 143 
 144     // Extension functions that are implemented in BasisLibrary
 145     private static final Hashtable _extensionFunctionTable = new Hashtable();
 146     /**
 147      * inner class to used in internal2Java mappings, contains
 148      * the Java type and the distance between the internal type and
 149      * the Java type.
 150      */
 151     static class JavaType {
 152         public Class  type;
 153         public int distance;
 154 
 155         public JavaType(Class type, int distance){
 156             this.type = type;
 157             this.distance = distance;
 158         }







 159         public boolean equals(Object query){
 160             return query.equals(type);
 161         }
 162     }
 163 
 164     /**
 165      * Defines 2 conversion tables:
 166      * 1. From internal types to Java types and
 167      * 2. From Java types to internal types.
 168      * These two tables are used when calling external (Java) functions.
 169      */
 170     static {
 171         try {
 172             final Class nodeClass     = Class.forName("org.w3c.dom.Node");
 173             final Class nodeListClass = Class.forName("org.w3c.dom.NodeList");
 174 
 175             // -- Internal to Java --------------------------------------------
 176 
 177             // Type.Boolean -> { boolean(0), Boolean(1), Object(2) }
 178             _internal2Java.put(Type.Boolean, new JavaType(Boolean.TYPE, 0));
 179             _internal2Java.put(Type.Boolean, new JavaType(Boolean.class, 1));
 180             _internal2Java.put(Type.Boolean, new JavaType(Object.class, 2));


 260         }
 261         catch (ClassNotFoundException e) {
 262             System.err.println(e);
 263         }
 264     }
 265 
 266     public FunctionCall(QName fname, Vector arguments) {
 267         _fname = fname;
 268         _arguments = arguments;
 269         _type = null;
 270     }
 271 
 272     public FunctionCall(QName fname) {
 273         this(fname, EMPTY_ARG_LIST);
 274     }
 275 
 276     public String getName() {
 277         return(_fname.toString());
 278     }
 279 

 280     public void setParser(Parser parser) {
 281         super.setParser(parser);
 282         if (_arguments != null) {
 283             final int n = _arguments.size();
 284             for (int i = 0; i < n; i++) {
 285                 final Expression exp = (Expression)_arguments.elementAt(i);
 286                 exp.setParser(parser);
 287                 exp.setParent(this);
 288             }
 289         }
 290     }
 291 
 292     public String getClassNameFromUri(String uri)
 293     {
 294         String className = (String)_extensionNamespaceTable.get(uri);
 295 
 296         if (className != null)
 297             return className;
 298         else {
 299             if (uri.startsWith(JAVA_EXT_XSLTC)) {


 302             }
 303             else if (uri.startsWith(JAVA_EXT_XALAN)) {
 304                 int length = JAVA_EXT_XALAN.length() + 1;
 305                 return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
 306             }
 307             else if (uri.startsWith(JAVA_EXT_XALAN_OLD)) {
 308                 int length = JAVA_EXT_XALAN_OLD.length() + 1;
 309                 return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
 310             }
 311             else {
 312                 int index = uri.lastIndexOf('/');
 313                 return (index > 0) ? uri.substring(index+1) : uri;
 314             }
 315         }
 316     }
 317 
 318     /**
 319      * Type check a function call. Since different type conversions apply,
 320      * type checking is different for standard and external (Java) functions.
 321      */

 322     public Type typeCheck(SymbolTable stable)
 323         throws TypeCheckError
 324     {
 325         if (_type != null) return _type;
 326 
 327         final String namespace = _fname.getNamespace();
 328         String local = _fname.getLocalPart();
 329 
 330         if (isExtension()) {
 331             _fname = new QName(null, null, local);
 332             return typeCheckStandard(stable);
 333         }
 334         else if (isStandard()) {
 335             return typeCheckStandard(stable);
 336         }
 337         // Handle extension functions (they all have a namespace)
 338         else {
 339             try {
 340                 _className = getClassNameFromUri(namespace);
 341 


 663     protected final Expression argument(int i) {
 664         return (Expression)_arguments.elementAt(i);
 665     }
 666 
 667     protected final Expression argument() {
 668         return argument(0);
 669     }
 670 
 671     protected final int argumentCount() {
 672         return _arguments.size();
 673     }
 674 
 675     protected final void setArgument(int i, Expression exp) {
 676         _arguments.setElementAt(exp, i);
 677     }
 678 
 679     /**
 680      * Compile the function call and treat as an expression
 681      * Update true/false-lists.
 682      */

 683     public void translateDesynthesized(ClassGenerator classGen,
 684                                        MethodGenerator methodGen)
 685     {
 686         Type type = Type.Boolean;
 687         if (_chosenMethodType != null)
 688             type = _chosenMethodType.resultType();
 689 
 690         final InstructionList il = methodGen.getInstructionList();
 691         translate(classGen, methodGen);
 692 
 693         if ((type instanceof BooleanType) || (type instanceof IntType)) {
 694             _falseList.add(il.append(new IFEQ(null)));
 695         }
 696     }
 697 
 698 
 699     /**
 700      * Translate a function call. The compiled code will leave the function's
 701      * return value on the JVM's stack.
 702      */

 703     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
 704         final int n = argumentCount();
 705         final ConstantPoolGen cpg = classGen.getConstantPool();
 706         final InstructionList il = methodGen.getInstructionList();
 707         final boolean isSecureProcessing = classGen.getParser().getXSLTC().isSecureProcessing();
 708         int index;
 709 
 710         // Translate calls to methods in the BasisLibrary
 711         if (isStandard() || isExtension()) {
 712             for (int i = 0; i < n; i++) {
 713                 final Expression exp = argument(i);
 714                 exp.translate(classGen, methodGen);
 715                 exp.startIterator(classGen, methodGen);
 716             }
 717 
 718             // append "F" to the function's name
 719             final String name = _fname.toString().replace('-', '_') + "F";
 720             String args = Constants.EMPTYSTRING;
 721 
 722             // Special precautions for some method calls


 840             if (_thisArgument != null && _clazz.isInterface()) {
 841                 index = cpg.addInterfaceMethodref(clazz,
 842                                      _fname.getLocalPart(),
 843                                      buffer.toString());
 844                 il.append(new INVOKEINTERFACE(index, n+1));
 845             }
 846             else {
 847                 index = cpg.addMethodref(clazz,
 848                                      _fname.getLocalPart(),
 849                                      buffer.toString());
 850                 il.append(_thisArgument != null ? (InvokeInstruction) new INVOKEVIRTUAL(index) :
 851                           (InvokeInstruction) new INVOKESTATIC(index));
 852             }
 853 
 854             // Convert the return type back to our internal type
 855             _type.translateFrom(classGen, methodGen,
 856                                 _chosenMethod.getReturnType());
 857         }
 858     }
 859 

 860     public String toString() {
 861         return "funcall(" + _fname + ", " + _arguments + ')';
 862     }
 863 
 864     public boolean isStandard() {
 865         final String namespace = _fname.getNamespace();
 866         return (namespace == null) || (namespace.equals(Constants.EMPTYSTRING));
 867     }
 868 
 869     public boolean isExtension() {
 870         final String namespace = _fname.getNamespace();
 871         return (namespace != null) && (namespace.equals(EXT_XSLTC));
 872     }
 873 
 874     /**
 875      * Returns a vector with all methods named <code>_fname</code>
 876      * after stripping its namespace or <code>null</code>
 877      * if no such methods exist.
 878      */
 879     private Vector findMethods() {


1052 
1053         int nArgs = argsType.size();
1054         for (int i = 0; i < nArgs; i++) {
1055             final Type intType = (Type)argsType.elementAt(i);
1056             buf.append(intType.toString());
1057             if (i < nArgs - 1) buf.append(", ");
1058         }
1059 
1060         buf.append(')');
1061         return buf.toString();
1062     }
1063 
1064     /**
1065      * To support EXSLT extensions, convert names with dash to allowable Java names:
1066      * e.g., convert abc-xyz to abcXyz.
1067      * Note: dashes only appear in middle of an EXSLT function or element name.
1068      */
1069     protected static String replaceDash(String name)
1070     {
1071         char dash = '-';
1072         StringBuffer buff = new StringBuffer("");
1073         for (int i = 0; i < name.length(); i++) {
1074         if (i > 0 && name.charAt(i-1) == dash)
1075             buff.append(Character.toUpperCase(name.charAt(i)));
1076         else if (name.charAt(i) != dash)
1077             buff.append(name.charAt(i));
1078         }
1079         return buff.toString();
1080     }
1081 
1082     /**
1083      * Translate code to call the BasisLibrary.unallowed_extensionF(String)
1084      * method.
1085      */
1086     private void translateUnallowedExtension(ConstantPoolGen cpg,
1087                                              InstructionList il) {
1088         int index = cpg.addMethodref(BASIS_LIBRARY_CLASS,
1089                                      "unallowed_extension_functionF",
1090                                      "(Ljava/lang/String;)V");
1091         il.append(new PUSH(cpg, _fname.toString()));
1092         il.append(new INVOKESTATIC(index));


  37 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
  38 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  39 import com.sun.org.apache.bcel.internal.generic.InstructionConstants;
  40 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  41 import com.sun.org.apache.bcel.internal.generic.InvokeInstruction;
  42 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
  43 import com.sun.org.apache.bcel.internal.generic.NEW;
  44 import com.sun.org.apache.bcel.internal.generic.PUSH;
  45 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType;
  46 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  47 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  48 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
  49 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  50 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType;
  51 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MultiHashtable;
  52 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ObjectType;
  53 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
  54 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  55 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  56 import com.sun.org.apache.xalan.internal.utils.ObjectFactory;
  57 import java.util.Objects;
  58 
  59 /**
  60  * @author Jacek Ambroziak
  61  * @author Santiago Pericas-Geertsen
  62  * @author Morten Jorgensen
  63  * @author Erwin Bolwidt <ejb@klomp.org>
  64  * @author Todd Miller
  65  */
  66 class FunctionCall extends Expression {
  67 
  68     // Name of this function call
  69     private QName  _fname;
  70     // Arguments to this function call (might not be any)
  71     private final Vector _arguments;
  72     // Empty argument list, used for certain functions
  73     private final static Vector EMPTY_ARG_LIST = new Vector(0);
  74 
  75     // Valid namespaces for Java function-call extension
  76     protected final static String EXT_XSLTC =
  77         TRANSLET_URI;


 140     private static final Hashtable _java2Internal = new Hashtable();
 141 
 142     // The mappings between EXSLT extension namespaces and implementation classes
 143     private static final Hashtable _extensionNamespaceTable = new Hashtable();
 144 
 145     // Extension functions that are implemented in BasisLibrary
 146     private static final Hashtable _extensionFunctionTable = new Hashtable();
 147     /**
 148      * inner class to used in internal2Java mappings, contains
 149      * the Java type and the distance between the internal type and
 150      * the Java type.
 151      */
 152     static class JavaType {
 153         public Class  type;
 154         public int distance;
 155 
 156         public JavaType(Class type, int distance){
 157             this.type = type;
 158             this.distance = distance;
 159         }
 160 
 161         @Override
 162         public int hashCode() {
 163             return Objects.hashCode(this.type);
 164         }
 165 
 166         @Override
 167         public boolean equals(Object query){
 168             return query != null && query.equals(type);
 169         }
 170     }
 171 
 172     /**
 173      * Defines 2 conversion tables:
 174      * 1. From internal types to Java types and
 175      * 2. From Java types to internal types.
 176      * These two tables are used when calling external (Java) functions.
 177      */
 178     static {
 179         try {
 180             final Class nodeClass     = Class.forName("org.w3c.dom.Node");
 181             final Class nodeListClass = Class.forName("org.w3c.dom.NodeList");
 182 
 183             // -- Internal to Java --------------------------------------------
 184 
 185             // Type.Boolean -> { boolean(0), Boolean(1), Object(2) }
 186             _internal2Java.put(Type.Boolean, new JavaType(Boolean.TYPE, 0));
 187             _internal2Java.put(Type.Boolean, new JavaType(Boolean.class, 1));
 188             _internal2Java.put(Type.Boolean, new JavaType(Object.class, 2));


 268         }
 269         catch (ClassNotFoundException e) {
 270             System.err.println(e);
 271         }
 272     }
 273 
 274     public FunctionCall(QName fname, Vector arguments) {
 275         _fname = fname;
 276         _arguments = arguments;
 277         _type = null;
 278     }
 279 
 280     public FunctionCall(QName fname) {
 281         this(fname, EMPTY_ARG_LIST);
 282     }
 283 
 284     public String getName() {
 285         return(_fname.toString());
 286     }
 287 
 288     @Override
 289     public void setParser(Parser parser) {
 290         super.setParser(parser);
 291         if (_arguments != null) {
 292             final int n = _arguments.size();
 293             for (int i = 0; i < n; i++) {
 294                 final Expression exp = (Expression)_arguments.elementAt(i);
 295                 exp.setParser(parser);
 296                 exp.setParent(this);
 297             }
 298         }
 299     }
 300 
 301     public String getClassNameFromUri(String uri)
 302     {
 303         String className = (String)_extensionNamespaceTable.get(uri);
 304 
 305         if (className != null)
 306             return className;
 307         else {
 308             if (uri.startsWith(JAVA_EXT_XSLTC)) {


 311             }
 312             else if (uri.startsWith(JAVA_EXT_XALAN)) {
 313                 int length = JAVA_EXT_XALAN.length() + 1;
 314                 return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
 315             }
 316             else if (uri.startsWith(JAVA_EXT_XALAN_OLD)) {
 317                 int length = JAVA_EXT_XALAN_OLD.length() + 1;
 318                 return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
 319             }
 320             else {
 321                 int index = uri.lastIndexOf('/');
 322                 return (index > 0) ? uri.substring(index+1) : uri;
 323             }
 324         }
 325     }
 326 
 327     /**
 328      * Type check a function call. Since different type conversions apply,
 329      * type checking is different for standard and external (Java) functions.
 330      */
 331     @Override
 332     public Type typeCheck(SymbolTable stable)
 333         throws TypeCheckError
 334     {
 335         if (_type != null) return _type;
 336 
 337         final String namespace = _fname.getNamespace();
 338         String local = _fname.getLocalPart();
 339 
 340         if (isExtension()) {
 341             _fname = new QName(null, null, local);
 342             return typeCheckStandard(stable);
 343         }
 344         else if (isStandard()) {
 345             return typeCheckStandard(stable);
 346         }
 347         // Handle extension functions (they all have a namespace)
 348         else {
 349             try {
 350                 _className = getClassNameFromUri(namespace);
 351 


 673     protected final Expression argument(int i) {
 674         return (Expression)_arguments.elementAt(i);
 675     }
 676 
 677     protected final Expression argument() {
 678         return argument(0);
 679     }
 680 
 681     protected final int argumentCount() {
 682         return _arguments.size();
 683     }
 684 
 685     protected final void setArgument(int i, Expression exp) {
 686         _arguments.setElementAt(exp, i);
 687     }
 688 
 689     /**
 690      * Compile the function call and treat as an expression
 691      * Update true/false-lists.
 692      */
 693     @Override
 694     public void translateDesynthesized(ClassGenerator classGen,
 695                                        MethodGenerator methodGen)
 696     {
 697         Type type = Type.Boolean;
 698         if (_chosenMethodType != null)
 699             type = _chosenMethodType.resultType();
 700 
 701         final InstructionList il = methodGen.getInstructionList();
 702         translate(classGen, methodGen);
 703 
 704         if ((type instanceof BooleanType) || (type instanceof IntType)) {
 705             _falseList.add(il.append(new IFEQ(null)));
 706         }
 707     }
 708 
 709 
 710     /**
 711      * Translate a function call. The compiled code will leave the function's
 712      * return value on the JVM's stack.
 713      */
 714     @Override
 715     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
 716         final int n = argumentCount();
 717         final ConstantPoolGen cpg = classGen.getConstantPool();
 718         final InstructionList il = methodGen.getInstructionList();
 719         final boolean isSecureProcessing = classGen.getParser().getXSLTC().isSecureProcessing();
 720         int index;
 721 
 722         // Translate calls to methods in the BasisLibrary
 723         if (isStandard() || isExtension()) {
 724             for (int i = 0; i < n; i++) {
 725                 final Expression exp = argument(i);
 726                 exp.translate(classGen, methodGen);
 727                 exp.startIterator(classGen, methodGen);
 728             }
 729 
 730             // append "F" to the function's name
 731             final String name = _fname.toString().replace('-', '_') + "F";
 732             String args = Constants.EMPTYSTRING;
 733 
 734             // Special precautions for some method calls


 852             if (_thisArgument != null && _clazz.isInterface()) {
 853                 index = cpg.addInterfaceMethodref(clazz,
 854                                      _fname.getLocalPart(),
 855                                      buffer.toString());
 856                 il.append(new INVOKEINTERFACE(index, n+1));
 857             }
 858             else {
 859                 index = cpg.addMethodref(clazz,
 860                                      _fname.getLocalPart(),
 861                                      buffer.toString());
 862                 il.append(_thisArgument != null ? (InvokeInstruction) new INVOKEVIRTUAL(index) :
 863                           (InvokeInstruction) new INVOKESTATIC(index));
 864             }
 865 
 866             // Convert the return type back to our internal type
 867             _type.translateFrom(classGen, methodGen,
 868                                 _chosenMethod.getReturnType());
 869         }
 870     }
 871 
 872     @Override
 873     public String toString() {
 874         return "funcall(" + _fname + ", " + _arguments + ')';
 875     }
 876 
 877     public boolean isStandard() {
 878         final String namespace = _fname.getNamespace();
 879         return (namespace == null) || (namespace.equals(Constants.EMPTYSTRING));
 880     }
 881 
 882     public boolean isExtension() {
 883         final String namespace = _fname.getNamespace();
 884         return (namespace != null) && (namespace.equals(EXT_XSLTC));
 885     }
 886 
 887     /**
 888      * Returns a vector with all methods named <code>_fname</code>
 889      * after stripping its namespace or <code>null</code>
 890      * if no such methods exist.
 891      */
 892     private Vector findMethods() {


1065 
1066         int nArgs = argsType.size();
1067         for (int i = 0; i < nArgs; i++) {
1068             final Type intType = (Type)argsType.elementAt(i);
1069             buf.append(intType.toString());
1070             if (i < nArgs - 1) buf.append(", ");
1071         }
1072 
1073         buf.append(')');
1074         return buf.toString();
1075     }
1076 
1077     /**
1078      * To support EXSLT extensions, convert names with dash to allowable Java names:
1079      * e.g., convert abc-xyz to abcXyz.
1080      * Note: dashes only appear in middle of an EXSLT function or element name.
1081      */
1082     protected static String replaceDash(String name)
1083     {
1084         char dash = '-';
1085         final StringBuilder buff = new StringBuilder("");
1086         for (int i = 0; i < name.length(); i++) {
1087         if (i > 0 && name.charAt(i-1) == dash)
1088             buff.append(Character.toUpperCase(name.charAt(i)));
1089         else if (name.charAt(i) != dash)
1090             buff.append(name.charAt(i));
1091         }
1092         return buff.toString();
1093     }
1094 
1095     /**
1096      * Translate code to call the BasisLibrary.unallowed_extensionF(String)
1097      * method.
1098      */
1099     private void translateUnallowedExtension(ConstantPoolGen cpg,
1100                                              InstructionList il) {
1101         int index = cpg.addMethodref(BASIS_LIBRARY_CLASS,
1102                                      "unallowed_extension_functionF",
1103                                      "(Ljava/lang/String;)V");
1104         il.append(new PUSH(cpg, _fname.toString()));
1105         il.append(new INVOKESTATIC(index));