1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 /*
  21  * $Id: FunctionCall.java,v 1.2.4.1 2005/09/12 10:31:32 pvedula Exp $
  22  */
  23 
  24 package com.sun.org.apache.xalan.internal.xsltc.compiler;
  25 
  26 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  27 import com.sun.org.apache.bcel.internal.generic.IFEQ;
  28 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  29 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
  30 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
  31 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  32 import com.sun.org.apache.bcel.internal.generic.InstructionConstants;
  33 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  34 import com.sun.org.apache.bcel.internal.generic.InvokeInstruction;
  35 import com.sun.org.apache.bcel.internal.generic.LDC;
  36 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
  37 import com.sun.org.apache.bcel.internal.generic.NEW;
  38 import com.sun.org.apache.bcel.internal.generic.POP;
  39 import com.sun.org.apache.bcel.internal.generic.PUSH;
  40 import com.sun.org.apache.xalan.internal.utils.FeatureManager;
  41 import com.sun.org.apache.xalan.internal.utils.ObjectFactory;
  42 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType;
  43 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  44 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  45 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
  46 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  47 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType;
  48 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MultiHashtable;
  49 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ObjectType;
  50 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
  51 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  52 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  53 import java.lang.reflect.Constructor;
  54 import java.lang.reflect.Method;
  55 import java.lang.reflect.Modifier;
  56 import java.util.Collections;
  57 import java.util.Enumeration;
  58 import java.util.HashMap;
  59 import java.util.Map;
  60 import java.util.Objects;
  61 import java.util.Vector;
  62 
  63 /**
  64  * @author Jacek Ambroziak
  65  * @author Santiago Pericas-Geertsen
  66  * @author Morten Jorgensen
  67  * @author Erwin Bolwidt <ejb@klomp.org>
  68  * @author Todd Miller
  69  */
  70 class FunctionCall extends Expression {
  71 
  72     // Name of this function call
  73     private QName  _fname;
  74     // Arguments to this function call (might not be any)
  75     private final Vector _arguments;
  76     // Empty argument list, used for certain functions
  77     private final static Vector EMPTY_ARG_LIST = new Vector(0);
  78 
  79     // Valid namespaces for Java function-call extension
  80     protected final static String EXT_XSLTC =
  81         TRANSLET_URI;
  82 
  83     protected final static String JAVA_EXT_XSLTC =
  84         EXT_XSLTC + "/java";
  85 
  86     protected final static String EXT_XALAN =
  87         "http://xml.apache.org/xalan";
  88 
  89     protected final static String JAVA_EXT_XALAN =
  90         "http://xml.apache.org/xalan/java";
  91 
  92     protected final static String JAVA_EXT_XALAN_OLD =
  93         "http://xml.apache.org/xslt/java";
  94 
  95     protected final static String EXSLT_COMMON =
  96         "http://exslt.org/common";
  97 
  98     protected final static String EXSLT_MATH =
  99         "http://exslt.org/math";
 100 
 101     protected final static String EXSLT_SETS =
 102         "http://exslt.org/sets";
 103 
 104     protected final static String EXSLT_DATETIME =
 105         "http://exslt.org/dates-and-times";
 106 
 107     protected final static String EXSLT_STRINGS =
 108         "http://exslt.org/strings";
 109 
 110     protected final static String XALAN_CLASSPACKAGE_NAMESPACE =
 111         "xalan://";
 112 
 113     // Namespace format constants
 114     protected final static int NAMESPACE_FORMAT_JAVA = 0;
 115     protected final static int NAMESPACE_FORMAT_CLASS = 1;
 116     protected final static int NAMESPACE_FORMAT_PACKAGE = 2;
 117     protected final static int NAMESPACE_FORMAT_CLASS_OR_PACKAGE = 3;
 118 
 119     // Namespace format
 120     private int _namespace_format = NAMESPACE_FORMAT_JAVA;
 121 
 122     /**
 123      * Stores reference to object for non-static Java calls
 124      */
 125     Expression _thisArgument = null;
 126 
 127     // External Java function's class/method/signature
 128     private String      _className;
 129     private Class       _clazz;
 130     private Method      _chosenMethod;
 131     private Constructor _chosenConstructor;
 132     private MethodType  _chosenMethodType;
 133 
 134     // Encapsulates all unsupported external function calls
 135     private boolean    unresolvedExternal;
 136 
 137     // If FunctionCall is a external java constructor
 138     private boolean     _isExtConstructor = false;
 139 
 140     // If the java method is static
 141     private boolean       _isStatic = false;
 142 
 143     // Legal conversions between internal and Java types.
 144     private static final MultiHashtable<Type, JavaType> _internal2Java = new MultiHashtable<>();
 145 
 146     // Legal conversions between Java and internal types.
 147     private static final Map<Class<?>, Type> JAVA2INTERNAL;
 148 
 149     // The mappings between EXSLT extension namespaces and implementation classes
 150     private static final Map<String, String> EXTENSIONNAMESPACE;
 151 
 152     // Extension functions that are implemented in BasisLibrary
 153     private static final Map<String, String> EXTENSIONFUNCTION;
 154     /**
 155      * inner class to used in internal2Java mappings, contains
 156      * the Java type and the distance between the internal type and
 157      * the Java type.
 158      */
 159     static class JavaType {
 160         public Class<?>  type;
 161         public int distance;
 162 
 163         public JavaType(Class type, int distance){
 164             this.type = type;
 165             this.distance = distance;
 166         }
 167 
 168         @Override
 169         public int hashCode() {
 170             return Objects.hashCode(this.type);
 171         }
 172 
 173         @Override
 174         public boolean equals(Object query) {
 175             if (query == null) {
 176                 return false;
 177             }
 178             if (query.getClass().isAssignableFrom(JavaType.class)) {
 179                 return ((JavaType)query).type.equals(type);
 180             } else {
 181                 return query.equals(type);
 182             }
 183         }
 184     }
 185 
 186     /**
 187      * Defines 2 conversion tables:
 188      * 1. From internal types to Java types and
 189      * 2. From Java types to internal types.
 190      * These two tables are used when calling external (Java) functions.
 191      */
 192     static {
 193         final Class<?> nodeClass, nodeListClass;
 194         try {
 195             nodeClass     = Class.forName("org.w3c.dom.Node");
 196             nodeListClass = Class.forName("org.w3c.dom.NodeList");
 197         }
 198         catch (ClassNotFoundException e) {
 199             ErrorMsg err = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR,"org.w3c.dom.Node or NodeList");
 200             throw new Error(err.toString());
 201         }
 202 
 203         // -- Internal to Java --------------------------------------------
 204 
 205         // Type.Boolean -> { boolean(0), Boolean(1), Object(2) }
 206         _internal2Java.put(Type.Boolean, new JavaType(Boolean.TYPE, 0));
 207         _internal2Java.put(Type.Boolean, new JavaType(Boolean.class, 1));
 208         _internal2Java.put(Type.Boolean, new JavaType(Object.class, 2));
 209 
 210         // Type.Real -> { double(0), Double(1), float(2), long(3), int(4),
 211         //                short(5), byte(6), char(7), Object(8) }
 212         _internal2Java.put(Type.Real, new JavaType(Double.TYPE, 0));
 213         _internal2Java.put(Type.Real, new JavaType(Double.class, 1));
 214         _internal2Java.put(Type.Real, new JavaType(Float.TYPE, 2));
 215         _internal2Java.put(Type.Real, new JavaType(Long.TYPE, 3));
 216         _internal2Java.put(Type.Real, new JavaType(Integer.TYPE, 4));
 217         _internal2Java.put(Type.Real, new JavaType(Short.TYPE, 5));
 218         _internal2Java.put(Type.Real, new JavaType(Byte.TYPE, 6));
 219         _internal2Java.put(Type.Real, new JavaType(Character.TYPE, 7));
 220         _internal2Java.put(Type.Real, new JavaType(Object.class, 8));
 221 
 222         // Type.Int must be the same as Type.Real
 223         _internal2Java.put(Type.Int, new JavaType(Double.TYPE, 0));
 224         _internal2Java.put(Type.Int, new JavaType(Double.class, 1));
 225         _internal2Java.put(Type.Int, new JavaType(Float.TYPE, 2));
 226         _internal2Java.put(Type.Int, new JavaType(Long.TYPE, 3));
 227         _internal2Java.put(Type.Int, new JavaType(Integer.TYPE, 4));
 228         _internal2Java.put(Type.Int, new JavaType(Short.TYPE, 5));
 229         _internal2Java.put(Type.Int, new JavaType(Byte.TYPE, 6));
 230         _internal2Java.put(Type.Int, new JavaType(Character.TYPE, 7));
 231         _internal2Java.put(Type.Int, new JavaType(Object.class, 8));
 232 
 233         // Type.String -> { String(0), Object(1) }
 234         _internal2Java.put(Type.String, new JavaType(String.class, 0));
 235         _internal2Java.put(Type.String, new JavaType(Object.class, 1));
 236 
 237         // Type.NodeSet -> { NodeList(0), Node(1), Object(2), String(3) }
 238         _internal2Java.put(Type.NodeSet, new JavaType(nodeListClass, 0));
 239         _internal2Java.put(Type.NodeSet, new JavaType(nodeClass, 1));
 240         _internal2Java.put(Type.NodeSet, new JavaType(Object.class, 2));
 241         _internal2Java.put(Type.NodeSet, new JavaType(String.class, 3));
 242 
 243         // Type.Node -> { Node(0), NodeList(1), Object(2), String(3) }
 244         _internal2Java.put(Type.Node, new JavaType(nodeListClass, 0));
 245         _internal2Java.put(Type.Node, new JavaType(nodeClass, 1));
 246         _internal2Java.put(Type.Node, new JavaType(Object.class, 2));
 247         _internal2Java.put(Type.Node, new JavaType(String.class, 3));
 248 
 249         // Type.ResultTree -> { NodeList(0), Node(1), Object(2), String(3) }
 250         _internal2Java.put(Type.ResultTree, new JavaType(nodeListClass, 0));
 251         _internal2Java.put(Type.ResultTree, new JavaType(nodeClass, 1));
 252         _internal2Java.put(Type.ResultTree, new JavaType(Object.class, 2));
 253         _internal2Java.put(Type.ResultTree, new JavaType(String.class, 3));
 254 
 255         _internal2Java.put(Type.Reference, new JavaType(Object.class, 0));
 256 
 257         _internal2Java.makeUnmodifiable();
 258 
 259         Map<Class<?>, Type> java2Internal = new HashMap<>();
 260         Map<String, String> extensionNamespaceTable = new HashMap<>();
 261         Map<String, String> extensionFunctionTable = new HashMap<>();
 262 
 263         // Possible conversions between Java and internal types
 264         java2Internal.put(Boolean.TYPE, Type.Boolean);
 265         java2Internal.put(Void.TYPE, Type.Void);
 266         java2Internal.put(Character.TYPE, Type.Real);
 267         java2Internal.put(Byte.TYPE, Type.Real);
 268         java2Internal.put(Short.TYPE, Type.Real);
 269         java2Internal.put(Integer.TYPE, Type.Real);
 270         java2Internal.put(Long.TYPE, Type.Real);
 271         java2Internal.put(Float.TYPE, Type.Real);
 272         java2Internal.put(Double.TYPE, Type.Real);
 273 
 274         java2Internal.put(String.class, Type.String);
 275 
 276         java2Internal.put(Object.class, Type.Reference);
 277 
 278         // Conversions from org.w3c.dom.Node/NodeList to internal NodeSet
 279         java2Internal.put(nodeListClass, Type.NodeSet);
 280         java2Internal.put(nodeClass, Type.NodeSet);
 281 
 282         // Initialize the extension namespace table
 283         extensionNamespaceTable.put(EXT_XALAN, "com.sun.org.apache.xalan.internal.lib.Extensions");
 284         extensionNamespaceTable.put(EXSLT_COMMON, "com.sun.org.apache.xalan.internal.lib.ExsltCommon");
 285         extensionNamespaceTable.put(EXSLT_MATH, "com.sun.org.apache.xalan.internal.lib.ExsltMath");
 286         extensionNamespaceTable.put(EXSLT_SETS, "com.sun.org.apache.xalan.internal.lib.ExsltSets");
 287         extensionNamespaceTable.put(EXSLT_DATETIME, "com.sun.org.apache.xalan.internal.lib.ExsltDatetime");
 288         extensionNamespaceTable.put(EXSLT_STRINGS, "com.sun.org.apache.xalan.internal.lib.ExsltStrings");
 289 
 290         // Initialize the extension function table
 291         extensionFunctionTable.put(EXSLT_COMMON + ":nodeSet", "nodeset");
 292         extensionFunctionTable.put(EXSLT_COMMON + ":objectType", "objectType");
 293         extensionFunctionTable.put(EXT_XALAN + ":nodeset", "nodeset");
 294 
 295         JAVA2INTERNAL = Collections.unmodifiableMap(java2Internal);
 296         EXTENSIONNAMESPACE = Collections.unmodifiableMap(extensionNamespaceTable);
 297         EXTENSIONFUNCTION = Collections.unmodifiableMap(extensionFunctionTable);
 298 
 299     }
 300 
 301     public FunctionCall(QName fname, Vector arguments) {
 302         _fname = fname;
 303         _arguments = arguments;
 304         _type = null;
 305     }
 306 
 307     public FunctionCall(QName fname) {
 308         this(fname, EMPTY_ARG_LIST);
 309     }
 310 
 311     public String getName() {
 312         return(_fname.toString());
 313     }
 314 
 315     @Override
 316     public void setParser(Parser parser) {
 317         super.setParser(parser);
 318         if (_arguments != null) {
 319             final int n = _arguments.size();
 320             for (int i = 0; i < n; i++) {
 321                 final Expression exp = (Expression)_arguments.elementAt(i);
 322                 exp.setParser(parser);
 323                 exp.setParent(this);
 324             }
 325         }
 326     }
 327 
 328     public String getClassNameFromUri(String uri)
 329     {
 330         String className = EXTENSIONNAMESPACE.get(uri);
 331 
 332         if (className != null)
 333             return className;
 334         else {
 335             if (uri.startsWith(JAVA_EXT_XSLTC)) {
 336                 int length = JAVA_EXT_XSLTC.length() + 1;
 337                 return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
 338             }
 339             else if (uri.startsWith(JAVA_EXT_XALAN)) {
 340                 int length = JAVA_EXT_XALAN.length() + 1;
 341                 return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
 342             }
 343             else if (uri.startsWith(JAVA_EXT_XALAN_OLD)) {
 344                 int length = JAVA_EXT_XALAN_OLD.length() + 1;
 345                 return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
 346             }
 347             else {
 348                 int index = uri.lastIndexOf('/');
 349                 return (index > 0) ? uri.substring(index+1) : uri;
 350             }
 351         }
 352     }
 353 
 354     /**
 355      * Type check a function call. Since different type conversions apply,
 356      * type checking is different for standard and external (Java) functions.
 357      */
 358     @Override
 359     public Type typeCheck(SymbolTable stable)
 360         throws TypeCheckError
 361     {
 362         if (_type != null) return _type;
 363 
 364         final String namespace = _fname.getNamespace();
 365         String local = _fname.getLocalPart();
 366 
 367         if (isExtension()) {
 368             _fname = new QName(null, null, local);
 369             return typeCheckStandard(stable);
 370         }
 371         else if (isStandard()) {
 372             return typeCheckStandard(stable);
 373         }
 374         // Handle extension functions (they all have a namespace)
 375         else {
 376             try {
 377                 _className = getClassNameFromUri(namespace);
 378 
 379                 final int pos = local.lastIndexOf('.');
 380                 if (pos > 0) {
 381                     _isStatic = true;
 382                     if (_className != null && _className.length() > 0) {
 383                         _namespace_format = NAMESPACE_FORMAT_PACKAGE;
 384                         _className = _className + "." + local.substring(0, pos);
 385                     }
 386                     else {
 387                         _namespace_format = NAMESPACE_FORMAT_JAVA;
 388                         _className = local.substring(0, pos);
 389                     }
 390 
 391                     _fname = new QName(namespace, null, local.substring(pos + 1));
 392                 }
 393                 else {
 394                     if (_className != null && _className.length() > 0) {
 395                         try {
 396                             _clazz = ObjectFactory.findProviderClass(_className, true);
 397                             _namespace_format = NAMESPACE_FORMAT_CLASS;
 398                         }
 399                         catch (ClassNotFoundException e) {
 400                             _namespace_format = NAMESPACE_FORMAT_PACKAGE;
 401                         }
 402                     }
 403                     else
 404                         _namespace_format = NAMESPACE_FORMAT_JAVA;
 405 
 406                     if (local.indexOf('-') > 0) {
 407                         local = replaceDash(local);
 408                     }
 409 
 410                     String extFunction = EXTENSIONFUNCTION.get(namespace + ":" + local);
 411                     if (extFunction != null) {
 412                         _fname = new QName(null, null, extFunction);
 413                         return typeCheckStandard(stable);
 414                     }
 415                     else
 416                         _fname = new QName(namespace, null, local);
 417                 }
 418 
 419                 return typeCheckExternal(stable);
 420             }
 421             catch (TypeCheckError e) {
 422                 ErrorMsg errorMsg = e.getErrorMsg();
 423                 if (errorMsg == null) {
 424                     final String name = _fname.getLocalPart();
 425                     errorMsg = new ErrorMsg(ErrorMsg.METHOD_NOT_FOUND_ERR, name);
 426                 }
 427                 getParser().reportError(ERROR, errorMsg);
 428                 return _type = Type.Void;
 429             }
 430           }
 431     }
 432 
 433     /**
 434      * Type check a call to a standard function. Insert CastExprs when needed.
 435      * If as a result of the insertion of a CastExpr a type check error is
 436      * thrown, then catch it and re-throw it with a new "this".
 437      */
 438     public Type typeCheckStandard(SymbolTable stable) throws TypeCheckError {
 439         _fname.clearNamespace();        // HACK!!!
 440 
 441         final int n = _arguments.size();
 442         final Vector argsType = typeCheckArgs(stable);
 443         final MethodType args = new MethodType(Type.Void, argsType);
 444         final MethodType ptype =
 445             lookupPrimop(stable, _fname.getLocalPart(), args);
 446 
 447         if (ptype != null) {
 448             for (int i = 0; i < n; i++) {
 449                 final Type argType = (Type) ptype.argsType().elementAt(i);
 450                 final Expression exp = (Expression)_arguments.elementAt(i);
 451                 if (!argType.identicalTo(exp.getType())) {
 452                     try {
 453                         _arguments.setElementAt(new CastExpr(exp, argType), i);
 454                     }
 455                     catch (TypeCheckError e) {
 456                         throw new TypeCheckError(this); // invalid conversion
 457                     }
 458                 }
 459             }
 460             _chosenMethodType = ptype;
 461             return _type = ptype.resultType();
 462         }
 463         throw new TypeCheckError(this);
 464     }
 465 
 466 
 467 
 468     public Type typeCheckConstructor(SymbolTable stable) throws TypeCheckError{
 469         final Vector constructors = findConstructors();
 470         if (constructors == null) {
 471             // Constructor not found in this class
 472             throw new TypeCheckError(ErrorMsg.CONSTRUCTOR_NOT_FOUND,
 473                 _className);
 474 
 475         }
 476 
 477         final int nConstructors = constructors.size();
 478         final int nArgs = _arguments.size();
 479         final Vector argsType = typeCheckArgs(stable);
 480 
 481         // Try all constructors
 482         int bestConstrDistance = Integer.MAX_VALUE;
 483         _type = null;                   // reset
 484         for (int j, i = 0; i < nConstructors; i++) {
 485             // Check if all parameters to this constructor can be converted
 486             final Constructor constructor =
 487                 (Constructor)constructors.elementAt(i);
 488             final Class[] paramTypes = constructor.getParameterTypes();
 489 
 490             Class<?> extType;
 491             int currConstrDistance = 0;
 492             for (j = 0; j < nArgs; j++) {
 493                 // Convert from internal (translet) type to external (Java) type
 494                 extType = paramTypes[j];
 495                 final Type intType = (Type)argsType.elementAt(j);
 496                 JavaType match = _internal2Java.maps(intType, new JavaType(extType, 0));
 497                 if (match != null) {
 498                     currConstrDistance += match.distance;
 499                 }
 500                 else if (intType instanceof ObjectType) {
 501                     ObjectType objectType = (ObjectType)intType;
 502                     if (objectType.getJavaClass() == extType)
 503                         continue;
 504                     else if (extType.isAssignableFrom(objectType.getJavaClass()))
 505                         currConstrDistance += 1;
 506                     else {
 507                         currConstrDistance = Integer.MAX_VALUE;
 508                         break;
 509                     }
 510                 }
 511                 else {
 512                     // no mapping available
 513                     currConstrDistance = Integer.MAX_VALUE;
 514                     break;
 515                 }
 516             }
 517 
 518             if (j == nArgs && currConstrDistance < bestConstrDistance ) {
 519                 _chosenConstructor = constructor;
 520                 _isExtConstructor = true;
 521                 bestConstrDistance = currConstrDistance;
 522 
 523                 _type = (_clazz != null) ? Type.newObjectType(_clazz)
 524                     : Type.newObjectType(_className);
 525             }
 526         }
 527 
 528         if (_type != null) {
 529             return _type;
 530         }
 531 
 532         throw new TypeCheckError(ErrorMsg.ARGUMENT_CONVERSION_ERR, getMethodSignature(argsType));
 533     }
 534 
 535 
 536     /**
 537      * Type check a call to an external (Java) method.
 538      * The method must be static an public, and a legal type conversion
 539      * must exist for all its arguments and its return type.
 540      * Every method of name <code>_fname</code> is inspected
 541      * as a possible candidate.
 542      */
 543     public Type typeCheckExternal(SymbolTable stable) throws TypeCheckError {
 544         int nArgs = _arguments.size();
 545         final String name = _fname.getLocalPart();
 546 
 547         // check if function is a contructor 'new'
 548         if (_fname.getLocalPart().equals("new")) {
 549             return typeCheckConstructor(stable);
 550         }
 551         // check if we are calling an instance method
 552         else {
 553             boolean hasThisArgument = false;
 554 
 555             if (nArgs == 0)
 556                 _isStatic = true;
 557 
 558             if (!_isStatic) {
 559                 if (_namespace_format == NAMESPACE_FORMAT_JAVA
 560                     || _namespace_format == NAMESPACE_FORMAT_PACKAGE)
 561                     hasThisArgument = true;
 562 
 563                 Expression firstArg = (Expression)_arguments.elementAt(0);
 564                 Type firstArgType = (Type)firstArg.typeCheck(stable);
 565 
 566                 if (_namespace_format == NAMESPACE_FORMAT_CLASS
 567                     && firstArgType instanceof ObjectType
 568                     && _clazz != null
 569                     && _clazz.isAssignableFrom(((ObjectType)firstArgType).getJavaClass()))
 570                     hasThisArgument = true;
 571 
 572                 if (hasThisArgument) {
 573                     _thisArgument = (Expression) _arguments.elementAt(0);
 574                     _arguments.remove(0); nArgs--;
 575                     if (firstArgType instanceof ObjectType) {
 576                         _className = ((ObjectType) firstArgType).getJavaClassName();
 577                     }
 578                     else
 579                         throw new TypeCheckError(ErrorMsg.NO_JAVA_FUNCT_THIS_REF, name);
 580                 }
 581             }
 582             else if (_className.length() == 0) {
 583                 /*
 584                  * Warn user if external function could not be resolved.
 585                  * Warning will _NOT_ be issued is the call is properly
 586                  * wrapped in an <xsl:if> or <xsl:when> element. For details
 587                  * see If.parserContents() and When.parserContents()
 588                  */
 589                 final Parser parser = getParser();
 590                 if (parser != null) {
 591                     reportWarning(this, parser, ErrorMsg.FUNCTION_RESOLVE_ERR,
 592                                   _fname.toString());
 593                 }
 594                 unresolvedExternal = true;
 595                 return _type = Type.Int;        // use "Int" as "unknown"
 596             }
 597         }
 598 
 599         final Vector methods = findMethods();
 600 
 601         if (methods == null) {
 602             // Method not found in this class
 603             throw new TypeCheckError(ErrorMsg.METHOD_NOT_FOUND_ERR, _className + "." + name);
 604         }
 605 
 606         Class extType = null;
 607         final int nMethods = methods.size();
 608         final Vector argsType = typeCheckArgs(stable);
 609 
 610         // Try all methods to identify the best fit
 611         int bestMethodDistance  = Integer.MAX_VALUE;
 612         _type = null;                       // reset internal type
 613         for (int j, i = 0; i < nMethods; i++) {
 614             // Check if all paramteters to this method can be converted
 615             final Method method = (Method)methods.elementAt(i);
 616             final Class[] paramTypes = method.getParameterTypes();
 617 
 618             int currMethodDistance = 0;
 619             for (j = 0; j < nArgs; j++) {
 620                 // Convert from internal (translet) type to external (Java) type
 621                 extType = paramTypes[j];
 622                 final Type intType = (Type)argsType.elementAt(j);
 623                 JavaType match = _internal2Java.maps(intType, new JavaType(extType, 0));
 624                 if (match != null) {
 625                     currMethodDistance += match.distance;
 626                 }
 627                 else {
 628                     // no mapping available
 629                     //
 630                     // Allow a Reference type to match any external (Java) type at
 631                     // the moment. The real type checking is performed at runtime.
 632                     if (intType instanceof ReferenceType) {
 633                        currMethodDistance += 1;
 634                     }
 635                     else if (intType instanceof ObjectType) {
 636                         ObjectType object = (ObjectType)intType;
 637                         if (extType.getName().equals(object.getJavaClassName()))
 638                             currMethodDistance += 0;
 639                         else if (extType.isAssignableFrom(object.getJavaClass()))
 640                             currMethodDistance += 1;
 641                         else {
 642                             currMethodDistance = Integer.MAX_VALUE;
 643                             break;
 644                         }
 645                     }
 646                     else {
 647                         currMethodDistance = Integer.MAX_VALUE;
 648                         break;
 649                     }
 650                 }
 651             }
 652 
 653             if (j == nArgs) {
 654                   // Check if the return type can be converted
 655                   extType = method.getReturnType();
 656 
 657                   _type = JAVA2INTERNAL.get(extType);
 658                   if (_type == null) {
 659                       _type = Type.newObjectType(extType);
 660                   }
 661 
 662                   // Use this method if all parameters & return type match
 663                   if (_type != null && currMethodDistance < bestMethodDistance) {
 664                       _chosenMethod = method;
 665                       bestMethodDistance = currMethodDistance;
 666                   }
 667             }
 668         }
 669 
 670         // It is an error if the chosen method is an instance menthod but we don't
 671         // have a this argument.
 672         if (_chosenMethod != null && _thisArgument == null &&
 673             !Modifier.isStatic(_chosenMethod.getModifiers())) {
 674             throw new TypeCheckError(ErrorMsg.NO_JAVA_FUNCT_THIS_REF, getMethodSignature(argsType));
 675         }
 676 
 677         if (_type != null) {
 678             if (_type == Type.NodeSet) {
 679                 getXSLTC().setMultiDocument(true);
 680             }
 681             return _type;
 682         }
 683 
 684         throw new TypeCheckError(ErrorMsg.ARGUMENT_CONVERSION_ERR, getMethodSignature(argsType));
 685     }
 686 
 687     /**
 688      * Type check the actual arguments of this function call.
 689      */
 690     public Vector typeCheckArgs(SymbolTable stable) throws TypeCheckError {
 691         final Vector result = new Vector();
 692         final Enumeration e = _arguments.elements();
 693         while (e.hasMoreElements()) {
 694             final Expression exp = (Expression)e.nextElement();
 695             result.addElement(exp.typeCheck(stable));
 696         }
 697         return result;
 698     }
 699 
 700     protected final Expression argument(int i) {
 701         return (Expression)_arguments.elementAt(i);
 702     }
 703 
 704     protected final Expression argument() {
 705         return argument(0);
 706     }
 707 
 708     protected final int argumentCount() {
 709         return _arguments.size();
 710     }
 711 
 712     protected final void setArgument(int i, Expression exp) {
 713         _arguments.setElementAt(exp, i);
 714     }
 715 
 716     /**
 717      * Compile the function call and treat as an expression
 718      * Update true/false-lists.
 719      */
 720     @Override
 721     public void translateDesynthesized(ClassGenerator classGen,
 722                                        MethodGenerator methodGen)
 723     {
 724         Type type = Type.Boolean;
 725         if (_chosenMethodType != null)
 726             type = _chosenMethodType.resultType();
 727 
 728         final InstructionList il = methodGen.getInstructionList();
 729         translate(classGen, methodGen);
 730 
 731         if ((type instanceof BooleanType) || (type instanceof IntType)) {
 732             _falseList.add(il.append(new IFEQ(null)));
 733         }
 734     }
 735 
 736 
 737     /**
 738      * Translate a function call. The compiled code will leave the function's
 739      * return value on the JVM's stack.
 740      */
 741     @Override
 742     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
 743         final int n = argumentCount();
 744         final ConstantPoolGen cpg = classGen.getConstantPool();
 745         final InstructionList il = methodGen.getInstructionList();
 746         final boolean isSecureProcessing = classGen.getParser().getXSLTC().isSecureProcessing();
 747         final boolean isExtensionFunctionEnabled = classGen.getParser().getXSLTC()
 748                 .getFeature(FeatureManager.Feature.ORACLE_ENABLE_EXTENSION_FUNCTION);
 749         int index;
 750 
 751         // Translate calls to methods in the BasisLibrary
 752         if (isStandard() || isExtension()) {
 753             for (int i = 0; i < n; i++) {
 754                 final Expression exp = argument(i);
 755                 exp.translate(classGen, methodGen);
 756                 exp.startIterator(classGen, methodGen);
 757             }
 758 
 759             // append "F" to the function's name
 760             final String name = _fname.toString().replace('-', '_') + "F";
 761             String args = Constants.EMPTYSTRING;
 762 
 763             // Special precautions for some method calls
 764             if (name.equals("sumF")) {
 765                 args = DOM_INTF_SIG;
 766                 il.append(methodGen.loadDOM());
 767             }
 768             else if (name.equals("normalize_spaceF")) {
 769                 if (_chosenMethodType.toSignature(args).
 770                     equals("()Ljava/lang/String;")) {
 771                     args = "I"+DOM_INTF_SIG;
 772                     il.append(methodGen.loadContextNode());
 773                     il.append(methodGen.loadDOM());
 774                 }
 775             }
 776 
 777             // Invoke the method in the basis library
 778             index = cpg.addMethodref(BASIS_LIBRARY_CLASS, name,
 779                                      _chosenMethodType.toSignature(args));
 780             il.append(new INVOKESTATIC(index));
 781         }
 782         // Add call to BasisLibrary.unresolved_externalF() to generate
 783         // run-time error message for unsupported external functions
 784         else if (unresolvedExternal) {
 785             index = cpg.addMethodref(BASIS_LIBRARY_CLASS,
 786                                      "unresolved_externalF",
 787                                      "(Ljava/lang/String;)V");
 788             il.append(new PUSH(cpg, _fname.toString()));
 789             il.append(new INVOKESTATIC(index));
 790         }
 791         else if (_isExtConstructor) {
 792             if (isSecureProcessing && !isExtensionFunctionEnabled)
 793                 translateUnallowedExtension(cpg, il);
 794 
 795             final String clazz =
 796                 _chosenConstructor.getDeclaringClass().getName();
 797 
 798             // Generate call to Module.addReads:
 799             //   <TransletClass>.class.getModule().addReads(
 800             generateAddReads(classGen, methodGen, clazz);
 801             
 802             Class[] paramTypes = _chosenConstructor.getParameterTypes();
 803             LocalVariableGen[] paramTemp = new LocalVariableGen[n];
 804 
 805             // Backwards branches are prohibited if an uninitialized object is
 806             // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed.
 807             // We don't know whether this code might contain backwards branches
 808             // so we mustn't create the new object until after we've created
 809             // the suspect arguments to its constructor.  Instead we calculate
 810             // the values of the arguments to the constructor first, store them
 811             // in temporary variables, create the object and reload the
 812             // arguments from the temporaries to avoid the problem.
 813 
 814             for (int i = 0; i < n; i++) {
 815                 final Expression exp = argument(i);
 816                 Type expType = exp.getType();
 817                 exp.translate(classGen, methodGen);
 818                 // Convert the argument to its Java type
 819                 exp.startIterator(classGen, methodGen);
 820                 expType.translateTo(classGen, methodGen, paramTypes[i]);
 821                 paramTemp[i] =
 822                     methodGen.addLocalVariable("function_call_tmp"+i,
 823                                                expType.toJCType(),
 824                                                null, null);
 825                 paramTemp[i].setStart(
 826                         il.append(expType.STORE(paramTemp[i].getIndex())));
 827 
 828             }
 829 
 830             il.append(new NEW(cpg.addClass(_className)));
 831             il.append(InstructionConstants.DUP);
 832 
 833             for (int i = 0; i < n; i++) {
 834                 final Expression arg = argument(i);
 835                 paramTemp[i].setEnd(
 836                         il.append(arg.getType().LOAD(paramTemp[i].getIndex())));
 837             }
 838 
 839             final StringBuffer buffer = new StringBuffer();
 840             buffer.append('(');
 841             for (int i = 0; i < paramTypes.length; i++) {
 842                 buffer.append(getSignature(paramTypes[i]));
 843             }
 844             buffer.append(')');
 845             buffer.append("V");
 846 
 847             index = cpg.addMethodref(clazz,
 848                                      "<init>",
 849                                      buffer.toString());
 850             il.append(new INVOKESPECIAL(index));
 851 
 852             // Convert the return type back to our internal type
 853             (Type.Object).translateFrom(classGen, methodGen,
 854                                 _chosenConstructor.getDeclaringClass());
 855 
 856         }
 857         // Invoke function calls that are handled in separate classes
 858         else {
 859             if (isSecureProcessing && !isExtensionFunctionEnabled)
 860                 translateUnallowedExtension(cpg, il);
 861 
 862             final String clazz = _chosenMethod.getDeclaringClass().getName();
 863             Class[] paramTypes = _chosenMethod.getParameterTypes();
 864 
 865 
 866             // Generate call to Module.addReads:
 867             //   <TransletClass>.class.getModule().addReads(
 868             //        Class.forName(<clazz>).getModule());
 869             generateAddReads(classGen, methodGen, clazz);
 870 
 871             // Push "this" if it is an instance method
 872             if (_thisArgument != null) {
 873                 _thisArgument.translate(classGen, methodGen);
 874             }
 875 
 876             for (int i = 0; i < n; i++) {
 877                 final Expression exp = argument(i);
 878                 exp.translate(classGen, methodGen);
 879                 // Convert the argument to its Java type
 880                 exp.startIterator(classGen, methodGen);
 881                 exp.getType().translateTo(classGen, methodGen, paramTypes[i]);
 882             }
 883 
 884             final StringBuffer buffer = new StringBuffer();
 885             buffer.append('(');
 886             for (int i = 0; i < paramTypes.length; i++) {
 887                 buffer.append(getSignature(paramTypes[i]));
 888             }
 889             buffer.append(')');
 890             buffer.append(getSignature(_chosenMethod.getReturnType()));
 891 
 892             if (_thisArgument != null && _clazz.isInterface()) {
 893                 index = cpg.addInterfaceMethodref(clazz,
 894                                      _fname.getLocalPart(),
 895                                      buffer.toString());
 896                 il.append(new INVOKEINTERFACE(index, n+1));
 897             }
 898             else {
 899                 index = cpg.addMethodref(clazz,
 900                                      _fname.getLocalPart(),
 901                                      buffer.toString());
 902                 il.append(_thisArgument != null ? (InvokeInstruction) new INVOKEVIRTUAL(index) :
 903                           (InvokeInstruction) new INVOKESTATIC(index));
 904             }
 905 
 906             // Convert the return type back to our internal type
 907             _type.translateFrom(classGen, methodGen,
 908                                 _chosenMethod.getReturnType());
 909         }
 910     }
 911 
 912     private void generateAddReads(ClassGenerator classGen, MethodGenerator methodGen,
 913                           String clazz) {
 914         final ConstantPoolGen cpg = classGen.getConstantPool();
 915         final InstructionList il = methodGen.getInstructionList();
 916 
 917         if (classGen.getMajor() < com.sun.org.apache.bcel.internal.Constants.MAJOR_1_5) {
 918             // Major version needs to be >= 5.0 in order to support loading
 919             // a class ref from the constant pool (LDC)
 920             classGen.setMajor(com.sun.org.apache.bcel.internal.Constants.MAJOR_1_5);
 921             classGen.setMinor(com.sun.org.apache.bcel.internal.Constants.MINOR_1_5);
 922         }
 923 
 924         // Generate call to Module.addReads:
 925         //   <TransletClass>.class.getModule().addReads(
 926         //        Class.forName(<clazz>).getModule());
 927         // Class.forName may throw ClassNotFoundException.
 928         // This is OK as it will caught higher up the stack in
 929         // TransformerImpl.transform() and wrapped into a
 930         // TransformerException.
 931         methodGen.markChunkStart();
 932 
 933         int index = cpg.addMethodref(CLASS_CLASS,
 934                                      GET_MODULE,
 935                                      GET_MODULE_SIG);
 936         il.append(new LDC(cpg.addClass(classGen.getClassName())));
 937         il.append(new INVOKEVIRTUAL(index));
 938         int index2 = cpg.addMethodref(CLASS_CLASS,
 939                                       FOR_NAME,
 940                                       FOR_NAME_SIG);
 941         il.append(new LDC(cpg.addString(clazz)));
 942         il.append(new INVOKESTATIC(index2));
 943         il.append(new INVOKEVIRTUAL(index));
 944         index = cpg.addMethodref(MODULE_CLASS,
 945                                  ADD_READS,
 946                                  ADD_READS_SIG);
 947         il.append(new INVOKEVIRTUAL(index));
 948         il.append(new POP());
 949 
 950         methodGen.markChunkEnd();
 951     }
 952 
 953     @Override
 954     public String toString() {
 955         return "funcall(" + _fname + ", " + _arguments + ')';
 956     }
 957 
 958     public boolean isStandard() {
 959         final String namespace = _fname.getNamespace();
 960         return (namespace == null) || (namespace.equals(Constants.EMPTYSTRING));
 961     }
 962 
 963     public boolean isExtension() {
 964         final String namespace = _fname.getNamespace();
 965         return (namespace != null) && (namespace.equals(EXT_XSLTC));
 966     }
 967 
 968     /**
 969      * Returns a vector with all methods named <code>_fname</code>
 970      * after stripping its namespace or <code>null</code>
 971      * if no such methods exist.
 972      */
 973     private Vector findMethods() {
 974 
 975           Vector result = null;
 976           final String namespace = _fname.getNamespace();
 977 
 978           if (_className != null && _className.length() > 0) {
 979             final int nArgs = _arguments.size();
 980             try {
 981                 if (_clazz == null) {
 982                     final boolean isSecureProcessing = getXSLTC().isSecureProcessing();
 983                     final boolean isExtensionFunctionEnabled = getXSLTC()
 984                             .getFeature(FeatureManager.Feature.ORACLE_ENABLE_EXTENSION_FUNCTION);
 985 
 986                     //Check if FSP and SM - only then process with loading
 987                     if (namespace != null && isSecureProcessing
 988                             && isExtensionFunctionEnabled
 989                             && (namespace.startsWith(JAVA_EXT_XALAN)
 990                             || namespace.startsWith(JAVA_EXT_XSLTC)
 991                             || namespace.startsWith(JAVA_EXT_XALAN_OLD)
 992                             || namespace.startsWith(XALAN_CLASSPACKAGE_NAMESPACE))) {
 993                         _clazz = getXSLTC().loadExternalFunction(_className);
 994                     } else {
 995                         _clazz = ObjectFactory.findProviderClass(_className, true);
 996                     }
 997 
 998                 if (_clazz == null) {
 999                   final ErrorMsg msg =
1000                         new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
1001                   getParser().reportError(Constants.ERROR, msg);
1002                 }
1003               }
1004 
1005               final String methodName = _fname.getLocalPart();
1006               final Method[] methods = _clazz.getMethods();
1007 
1008               for (int i = 0; i < methods.length; i++) {
1009                 final int mods = methods[i].getModifiers();
1010                 // Is it public and same number of args ?
1011                 if (Modifier.isPublic(mods)
1012                     && methods[i].getName().equals(methodName)
1013                     && methods[i].getParameterTypes().length == nArgs)
1014                 {
1015                   if (result == null) {
1016                     result = new Vector();
1017                   }
1018                   result.addElement(methods[i]);
1019                 }
1020               }
1021             }
1022             catch (ClassNotFoundException e) {
1023                   final ErrorMsg msg = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
1024                   getParser().reportError(Constants.ERROR, msg);
1025             }
1026           }
1027           return result;
1028     }
1029 
1030     /**
1031      * Returns a vector with all constructors named <code>_fname</code>
1032      * after stripping its namespace or <code>null</code>
1033      * if no such methods exist.
1034      */
1035     private Vector findConstructors() {
1036         Vector result = null;
1037         final String namespace = _fname.getNamespace();
1038 
1039         final int nArgs = _arguments.size();
1040         try {
1041           if (_clazz == null) {
1042             _clazz = ObjectFactory.findProviderClass(_className, true);
1043 
1044             if (_clazz == null) {
1045               final ErrorMsg msg = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
1046               getParser().reportError(Constants.ERROR, msg);
1047             }
1048           }
1049 
1050           final Constructor[] constructors = _clazz.getConstructors();
1051 
1052           for (int i = 0; i < constructors.length; i++) {
1053               final int mods = constructors[i].getModifiers();
1054               // Is it public, static and same number of args ?
1055               if (Modifier.isPublic(mods) &&
1056                   constructors[i].getParameterTypes().length == nArgs)
1057               {
1058                 if (result == null) {
1059                   result = new Vector();
1060                 }
1061                 result.addElement(constructors[i]);
1062               }
1063           }
1064         }
1065         catch (ClassNotFoundException e) {
1066           final ErrorMsg msg = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
1067           getParser().reportError(Constants.ERROR, msg);
1068         }
1069 
1070         return result;
1071     }
1072 
1073 
1074     /**
1075      * Compute the JVM signature for the class.
1076      */
1077     static final String getSignature(Class clazz) {
1078         if (clazz.isArray()) {
1079             final StringBuffer sb = new StringBuffer();
1080             Class cl = clazz;
1081             while (cl.isArray()) {
1082                 sb.append("[");
1083                 cl = cl.getComponentType();
1084             }
1085             sb.append(getSignature(cl));
1086             return sb.toString();
1087         }
1088         else if (clazz.isPrimitive()) {
1089             if (clazz == Integer.TYPE) {
1090                 return "I";
1091             }
1092             else if (clazz == Byte.TYPE) {
1093                 return "B";
1094             }
1095             else if (clazz == Long.TYPE) {
1096                 return "J";
1097             }
1098             else if (clazz == Float.TYPE) {
1099                 return "F";
1100             }
1101             else if (clazz == Double.TYPE) {
1102                 return "D";
1103             }
1104             else if (clazz == Short.TYPE) {
1105                 return "S";
1106             }
1107             else if (clazz == Character.TYPE) {
1108                 return "C";
1109             }
1110             else if (clazz == Boolean.TYPE) {
1111                 return "Z";
1112             }
1113             else if (clazz == Void.TYPE) {
1114                 return "V";
1115             }
1116             else {
1117                 final String name = clazz.toString();
1118                 ErrorMsg err = new ErrorMsg(ErrorMsg.UNKNOWN_SIG_TYPE_ERR,name);
1119                 throw new Error(err.toString());
1120             }
1121         }
1122         else {
1123             return "L" + clazz.getName().replace('.', '/') + ';';
1124         }
1125     }
1126 
1127     /**
1128      * Compute the JVM method descriptor for the method.
1129      */
1130     static final String getSignature(Method meth) {
1131         final StringBuffer sb = new StringBuffer();
1132         sb.append('(');
1133         final Class[] params = meth.getParameterTypes(); // avoid clone
1134         for (int j = 0; j < params.length; j++) {
1135             sb.append(getSignature(params[j]));
1136         }
1137         return sb.append(')').append(getSignature(meth.getReturnType()))
1138             .toString();
1139     }
1140 
1141     /**
1142      * Compute the JVM constructor descriptor for the constructor.
1143      */
1144     static final String getSignature(Constructor cons) {
1145         final StringBuffer sb = new StringBuffer();
1146         sb.append('(');
1147         final Class[] params = cons.getParameterTypes(); // avoid clone
1148         for (int j = 0; j < params.length; j++) {
1149             sb.append(getSignature(params[j]));
1150         }
1151         return sb.append(")V").toString();
1152     }
1153 
1154     /**
1155      * Return the signature of the current method
1156      */
1157     private String getMethodSignature(Vector argsType) {
1158         final StringBuffer buf = new StringBuffer(_className);
1159         buf.append('.').append(_fname.getLocalPart()).append('(');
1160 
1161         int nArgs = argsType.size();
1162         for (int i = 0; i < nArgs; i++) {
1163             final Type intType = (Type)argsType.elementAt(i);
1164             buf.append(intType.toString());
1165             if (i < nArgs - 1) buf.append(", ");
1166         }
1167 
1168         buf.append(')');
1169         return buf.toString();
1170     }
1171 
1172     /**
1173      * To support EXSLT extensions, convert names with dash to allowable Java names:
1174      * e.g., convert abc-xyz to abcXyz.
1175      * Note: dashes only appear in middle of an EXSLT function or element name.
1176      */
1177     protected static String replaceDash(String name)
1178     {
1179         char dash = '-';
1180         final StringBuilder buff = new StringBuilder("");
1181         for (int i = 0; i < name.length(); i++) {
1182         if (i > 0 && name.charAt(i-1) == dash)
1183             buff.append(Character.toUpperCase(name.charAt(i)));
1184         else if (name.charAt(i) != dash)
1185             buff.append(name.charAt(i));
1186         }
1187         return buff.toString();
1188     }
1189 
1190     /**
1191      * Translate code to call the BasisLibrary.unallowed_extensionF(String)
1192      * method.
1193      */
1194     private void translateUnallowedExtension(ConstantPoolGen cpg,
1195                                              InstructionList il) {
1196         int index = cpg.addMethodref(BASIS_LIBRARY_CLASS,
1197                                      "unallowed_extension_functionF",
1198                                      "(Ljava/lang/String;)V");
1199         il.append(new PUSH(cpg, _fname.toString()));
1200         il.append(new INVOKESTATIC(index));
1201     }
1202 }