< prev index next >

src/java.base/share/classes/java/lang/invoke/LambdaForm.java

Print this page
rev 14964 : 8160717: MethodHandles.loop() does not check for excessive signature


   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 

  28 import jdk.internal.vm.annotation.DontInline;
  29 import jdk.internal.vm.annotation.Stable;
  30 import sun.invoke.util.Wrapper;
  31 
  32 import java.lang.annotation.ElementType;
  33 import java.lang.annotation.Retention;
  34 import java.lang.annotation.RetentionPolicy;
  35 import java.lang.annotation.Target;
  36 import java.lang.reflect.Method;
  37 import java.util.Arrays;
  38 import java.util.HashMap;
  39 
  40 import static java.lang.invoke.LambdaForm.BasicType.*;
  41 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
  42 import static java.lang.invoke.MethodHandleStatics.debugEnabled;
  43 import static java.lang.invoke.MethodHandleStatics.newInternalError;
  44 
  45 /**
  46  * The symbolic, non-executable form of a method handle's invocation semantics.
  47  * It consists of a series of names.
  48  * The first N (N=arity) names are parameters,
  49  * while any remaining names are temporary values.
  50  * Each temporary specifies the application of a function to some arguments.
  51  * The functions are method handles, while the arguments are mixes of
  52  * constant values and local names.
  53  * The result of the lambda is defined as one of the names, often the last one.
  54  * <p>
  55  * Here is an approximate grammar:
  56  * <blockquote><pre>{@code
  57  * LambdaForm = "(" ArgName* ")=>{" TempName* Result "}"
  58  * ArgName = "a" N ":" T
  59  * TempName = "t" N ":" T "=" Function "(" Argument* ");"
  60  * Function = ConstantValue
  61  * Argument = NameRef | ConstantValue
  62  * Result = NameRef | "void"
  63  * NameRef = "a" N | "t" N


 379             return buf.toString();
 380         }
 381         return debugName;
 382     }
 383 
 384     private static boolean namesOK(int arity, Name[] names) {
 385         for (int i = 0; i < names.length; i++) {
 386             Name n = names[i];
 387             assert(n != null) : "n is null";
 388             if (i < arity)
 389                 assert( n.isParam()) : n + " is not param at " + i;
 390             else
 391                 assert(!n.isParam()) : n + " is param at " + i;
 392         }
 393         return true;
 394     }
 395 
 396     /** Customize LambdaForm for a particular MethodHandle */
 397     LambdaForm customize(MethodHandle mh) {
 398         LambdaForm customForm = new LambdaForm(debugName, arity, names, result, forceInline, mh);
 399         if (COMPILE_THRESHOLD > 0 && isCompiled) {
 400             // If shared LambdaForm has been compiled, compile customized version as well.
 401             customForm.compileToBytecode();
 402         }
 403         customForm.transformCache = this; // LambdaFormEditor should always use uncustomized form.
 404         return customForm;
 405     }
 406 
 407     /** Get uncustomized flavor of the LambdaForm */
 408     LambdaForm uncustomize() {
 409         if (customized == null) {
 410             return this;
 411         }
 412         assert(transformCache != null); // Customized LambdaForm should always has a link to uncustomized version.
 413         LambdaForm uncustomizedForm = (LambdaForm)transformCache;
 414         if (COMPILE_THRESHOLD > 0 && isCompiled) {
 415             // If customized LambdaForm has been compiled, compile uncustomized version as well.
 416             uncustomizedForm.compileToBytecode();
 417         }
 418         return uncustomizedForm;
 419     }
 420 
 421     /** Renumber and/or replace params so that they are interned and canonically numbered.
 422      *  @return maximum argument list length among the names (since we have to pass over them anyway)
 423      */
 424     private int normalize() {
 425         Name[] oldNames = null;
 426         int maxOutArity = 0;
 427         int changesStart = 0;
 428         for (int i = 0; i < names.length; i++) {
 429             Name n = names[i];
 430             if (!n.initIndex(i)) {
 431                 if (oldNames == null) {
 432                     oldNames = names.clone();
 433                     changesStart = i;
 434                 }


 700      * a generic LF with a more specialized one, on the same MH,
 701      * if (a) the MH is frequently executed and (b) the MH cannot
 702      * be inlined into a containing caller, such as an invokedynamic.
 703      *
 704      * Compiled LFs that are no longer used should be GC-able.
 705      * If they contain non-BCP references, they should be properly
 706      * interlinked with the class loader(s) that their embedded types
 707      * depend on.  This probably means that reusable compiled LFs
 708      * will be tabulated (indexed) on relevant class loaders,
 709      * or else that the tables that cache them will have weak links.
 710      */
 711 
 712     /**
 713      * Make this LF directly executable, as part of a MethodHandle.
 714      * Invariant:  Every MH which is invoked must prepare its LF
 715      * before invocation.
 716      * (In principle, the JVM could do this very lazily,
 717      * as a sort of pre-invocation linkage step.)
 718      */
 719     public void prepare() {
 720         if (COMPILE_THRESHOLD == 0 && !isCompiled) {
 721             compileToBytecode();
 722         }
 723         if (this.vmentry != null) {
 724             // already prepared (e.g., a primitive DMH invoker form)
 725             return;
 726         }
 727         MethodType mtype = methodType();
 728         LambdaForm prep = mtype.form().cachedLambdaForm(MethodTypeForm.LF_INTERPRET);
 729         if (prep == null) {
 730             assert (isValidSignature(basicTypeSignature()));
 731             prep = new LambdaForm(mtype);
 732             prep.vmentry = InvokerBytecodeGenerator.generateLambdaFormInterpreterEntryPoint(mtype);
 733             prep = mtype.form().setCachedLambdaForm(MethodTypeForm.LF_INTERPRET, prep);
 734         }
 735         this.vmentry = prep.vmentry;
 736         // TO DO: Maybe add invokeGeneric, invokeWithArguments
 737     }
 738 



 739     /** Generate optimizable bytecode for this form. */
 740     MemberName compileToBytecode() {



 741         if (vmentry != null && isCompiled) {
 742             return vmentry;  // already compiled somehow
 743         }
 744         MethodType invokerType = methodType();
 745         assert(vmentry == null || vmentry.getMethodType().basicType().equals(invokerType));
 746         try {
 747             vmentry = InvokerBytecodeGenerator.generateCustomizedCode(this, invokerType);
 748             if (TRACE_INTERPRETER)
 749                 traceInterpreter("compileToBytecode", this);
 750             isCompiled = true;
 751             return vmentry;
 752         } catch (Error | Exception ex) {
 753             throw newInternalError(this.toString(), ex);







 754         }
 755     }
 756 
 757     private static void computeInitialPreparedForms() {
 758         // Find all predefined invokers and associate them with canonical empty lambda forms.
 759         for (MemberName m : MemberName.getFactory().getMethods(LambdaForm.class, false, null, null, null)) {
 760             if (!m.isStatic() || !m.isPackage())  continue;
 761             MethodType mt = m.getMethodType();
 762             if (mt.parameterCount() > 0 &&
 763                 mt.parameterType(0) == MethodHandle.class &&
 764                 m.getName().startsWith("interpret_")) {
 765                 String sig = null;
 766                 assert((sig = basicTypeSignature(mt)) != null &&
 767                         m.getName().equals("interpret" + sig.substring(sig.indexOf('_'))));
 768                 LambdaForm form = new LambdaForm(mt);
 769                 form.vmentry = m;
 770                 form = mt.form().setCachedLambdaForm(MethodTypeForm.LF_INTERPRET, form);
 771             }
 772         }
 773     }


 839     private static boolean checkInt(Class<?> type, Object x) {
 840         assert(x instanceof Integer);
 841         if (type == int.class)  return true;
 842         Wrapper w = Wrapper.forBasicType(type);
 843         assert(w.isSubwordOrInt());
 844         Object x1 = Wrapper.INT.wrap(w.wrap(x));
 845         return x.equals(x1);
 846     }
 847     private static boolean checkRef(Class<?> type, Object x) {
 848         assert(!type.isPrimitive());
 849         if (x == null)  return true;
 850         if (type.isInterface())  return true;
 851         return type.isInstance(x);
 852     }
 853 
 854     /** If the invocation count hits the threshold we spin bytecodes and call that subsequently. */
 855     private static final int COMPILE_THRESHOLD;
 856     static {
 857         COMPILE_THRESHOLD = Math.max(-1, MethodHandleStatics.COMPILE_THRESHOLD);
 858     }
 859     private int invocationCounter = 0;




 860 
 861     @Hidden
 862     @DontInline
 863     /** Interpretively invoke this form on the given arguments. */
 864     Object interpretWithArguments(Object... argumentValues) throws Throwable {
 865         if (TRACE_INTERPRETER)
 866             return interpretWithArgumentsTracing(argumentValues);
 867         checkInvocationCounter();
 868         assert(arityCheck(argumentValues));
 869         Object[] values = Arrays.copyOf(argumentValues, names.length);
 870         for (int i = argumentValues.length; i < values.length; i++) {
 871             values[i] = interpretName(names[i], values);
 872         }
 873         Object rv = (result < 0) ? null : values[result];
 874         assert(resultCheck(argumentValues, rv));
 875         return rv;
 876     }
 877 
 878     @Hidden
 879     @DontInline
 880     /** Evaluate a single Name within this form, applying its function to its arguments. */
 881     Object interpretName(Name name, Object[] values) throws Throwable {
 882         if (TRACE_INTERPRETER)
 883             traceInterpreter("| interpretName", name.debugString(), (Object[]) null);
 884         Object[] arguments = Arrays.copyOf(name.arguments, name.arguments.length, Object[].class);
 885         for (int i = 0; i < arguments.length; i++) {
 886             Object a = arguments[i];
 887             if (a instanceof Name) {
 888                 int i2 = ((Name)a).index();
 889                 assert(names[i2] == a);
 890                 a = values[i2];
 891                 arguments[i] = a;
 892             }
 893         }
 894         return name.function.invokeWithArguments(arguments);
 895     }
 896 
 897     private void checkInvocationCounter() {
 898         if (COMPILE_THRESHOLD != 0 &&
 899             invocationCounter < COMPILE_THRESHOLD) {
 900             invocationCounter++;  // benign race
 901             if (invocationCounter >= COMPILE_THRESHOLD) {
 902                 // Replace vmentry with a bytecode version of this LF.
 903                 compileToBytecode();
 904             }
 905         }
 906     }
 907     Object interpretWithArgumentsTracing(Object... argumentValues) throws Throwable {
 908         traceInterpreter("[ interpretWithArguments", this, argumentValues);
 909         if (invocationCounter < COMPILE_THRESHOLD) {
 910             int ctr = invocationCounter++;  // benign race
 911             traceInterpreter("| invocationCounter", ctr);
 912             if (invocationCounter >= COMPILE_THRESHOLD) {
 913                 compileToBytecode();
 914             }
 915         }
 916         Object rval;
 917         try {
 918             assert(arityCheck(argumentValues));
 919             Object[] values = Arrays.copyOf(argumentValues, names.length);
 920             for (int i = argumentValues.length; i < values.length; i++) {
 921                 values[i] = interpretName(names[i], values);
 922             }
 923             rval = (result < 0) ? null : values[result];
 924         } catch (Throwable ex) {
 925             traceInterpreter("] throw =>", ex);
 926             throw ex;
 927         }
 928         traceInterpreter("] return =>", rval);
 929         return rval;




   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 
  28 import jdk.internal.perf.PerfCounter;
  29 import jdk.internal.vm.annotation.DontInline;
  30 import jdk.internal.vm.annotation.Stable;
  31 import sun.invoke.util.Wrapper;
  32 
  33 import java.lang.annotation.ElementType;
  34 import java.lang.annotation.Retention;
  35 import java.lang.annotation.RetentionPolicy;
  36 import java.lang.annotation.Target;
  37 import java.lang.reflect.Method;
  38 import java.util.Arrays;
  39 import java.util.HashMap;
  40 
  41 import static java.lang.invoke.LambdaForm.BasicType.*;
  42 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
  43 import static java.lang.invoke.MethodHandleStatics.*;

  44 
  45 /**
  46  * The symbolic, non-executable form of a method handle's invocation semantics.
  47  * It consists of a series of names.
  48  * The first N (N=arity) names are parameters,
  49  * while any remaining names are temporary values.
  50  * Each temporary specifies the application of a function to some arguments.
  51  * The functions are method handles, while the arguments are mixes of
  52  * constant values and local names.
  53  * The result of the lambda is defined as one of the names, often the last one.
  54  * <p>
  55  * Here is an approximate grammar:
  56  * <blockquote><pre>{@code
  57  * LambdaForm = "(" ArgName* ")=>{" TempName* Result "}"
  58  * ArgName = "a" N ":" T
  59  * TempName = "t" N ":" T "=" Function "(" Argument* ");"
  60  * Function = ConstantValue
  61  * Argument = NameRef | ConstantValue
  62  * Result = NameRef | "void"
  63  * NameRef = "a" N | "t" N


 379             return buf.toString();
 380         }
 381         return debugName;
 382     }
 383 
 384     private static boolean namesOK(int arity, Name[] names) {
 385         for (int i = 0; i < names.length; i++) {
 386             Name n = names[i];
 387             assert(n != null) : "n is null";
 388             if (i < arity)
 389                 assert( n.isParam()) : n + " is not param at " + i;
 390             else
 391                 assert(!n.isParam()) : n + " is param at " + i;
 392         }
 393         return true;
 394     }
 395 
 396     /** Customize LambdaForm for a particular MethodHandle */
 397     LambdaForm customize(MethodHandle mh) {
 398         LambdaForm customForm = new LambdaForm(debugName, arity, names, result, forceInline, mh);
 399         if (COMPILE_THRESHOLD >= 0 && isCompiled) {
 400             // If shared LambdaForm has been compiled, compile customized version as well.
 401             customForm.compileToBytecode();
 402         }
 403         customForm.transformCache = this; // LambdaFormEditor should always use uncustomized form.
 404         return customForm;
 405     }
 406 
 407     /** Get uncustomized flavor of the LambdaForm */
 408     LambdaForm uncustomize() {
 409         if (customized == null) {
 410             return this;
 411         }
 412         assert(transformCache != null); // Customized LambdaForm should always has a link to uncustomized version.
 413         LambdaForm uncustomizedForm = (LambdaForm)transformCache;
 414         if (COMPILE_THRESHOLD >= 0 && isCompiled) {
 415             // If customized LambdaForm has been compiled, compile uncustomized version as well.
 416             uncustomizedForm.compileToBytecode();
 417         }
 418         return uncustomizedForm;
 419     }
 420 
 421     /** Renumber and/or replace params so that they are interned and canonically numbered.
 422      *  @return maximum argument list length among the names (since we have to pass over them anyway)
 423      */
 424     private int normalize() {
 425         Name[] oldNames = null;
 426         int maxOutArity = 0;
 427         int changesStart = 0;
 428         for (int i = 0; i < names.length; i++) {
 429             Name n = names[i];
 430             if (!n.initIndex(i)) {
 431                 if (oldNames == null) {
 432                     oldNames = names.clone();
 433                     changesStart = i;
 434                 }


 700      * a generic LF with a more specialized one, on the same MH,
 701      * if (a) the MH is frequently executed and (b) the MH cannot
 702      * be inlined into a containing caller, such as an invokedynamic.
 703      *
 704      * Compiled LFs that are no longer used should be GC-able.
 705      * If they contain non-BCP references, they should be properly
 706      * interlinked with the class loader(s) that their embedded types
 707      * depend on.  This probably means that reusable compiled LFs
 708      * will be tabulated (indexed) on relevant class loaders,
 709      * or else that the tables that cache them will have weak links.
 710      */
 711 
 712     /**
 713      * Make this LF directly executable, as part of a MethodHandle.
 714      * Invariant:  Every MH which is invoked must prepare its LF
 715      * before invocation.
 716      * (In principle, the JVM could do this very lazily,
 717      * as a sort of pre-invocation linkage step.)
 718      */
 719     public void prepare() {
 720         if (COMPILE_THRESHOLD == 0 && !forceInterpretation() && !isCompiled) {
 721             compileToBytecode();
 722         }
 723         if (this.vmentry != null) {
 724             // already prepared (e.g., a primitive DMH invoker form)
 725             return;
 726         }
 727         MethodType mtype = methodType();
 728         LambdaForm prep = mtype.form().cachedLambdaForm(MethodTypeForm.LF_INTERPRET);
 729         if (prep == null) {
 730             assert (isValidSignature(basicTypeSignature()));
 731             prep = new LambdaForm(mtype);
 732             prep.vmentry = InvokerBytecodeGenerator.generateLambdaFormInterpreterEntryPoint(mtype);
 733             prep = mtype.form().setCachedLambdaForm(MethodTypeForm.LF_INTERPRET, prep);
 734         }
 735         this.vmentry = prep.vmentry;
 736         // TO DO: Maybe add invokeGeneric, invokeWithArguments
 737     }
 738 
 739     private static final PerfCounter LF_FAILED =
 740             PerfCounter.newPerfCounter("java.lang.invoke.failedLambdaFormCompilations");
 741 
 742     /** Generate optimizable bytecode for this form. */
 743     void compileToBytecode() {
 744         if (forceInterpretation()) {
 745             return; // this should not be compiled
 746         }
 747         if (vmentry != null && isCompiled) {
 748             return;  // already compiled somehow
 749         }
 750         MethodType invokerType = methodType();
 751         assert(vmentry == null || vmentry.getMethodType().basicType().equals(invokerType));
 752         try {
 753             vmentry = InvokerBytecodeGenerator.generateCustomizedCode(this, invokerType);
 754             if (TRACE_INTERPRETER)
 755                 traceInterpreter("compileToBytecode", this);
 756             isCompiled = true;
 757         } catch (InvokerBytecodeGenerator.BytecodeGenerationException bge) {
 758             // bytecode generation failed - mark this LambdaForm as to be run in interpretation mode only
 759             invocationCounter = -1;
 760             LF_FAILED.increment();
 761             if (LOG_LF_COMPILATION_FAILURE) {
 762                 System.out.println("LambdaForm compilation failed: " + this);
 763                 bge.printStackTrace(System.out);
 764             }
 765         } catch (Error | Exception e) {
 766             throw newInternalError(this.toString(), e);
 767         }
 768     }
 769 
 770     private static void computeInitialPreparedForms() {
 771         // Find all predefined invokers and associate them with canonical empty lambda forms.
 772         for (MemberName m : MemberName.getFactory().getMethods(LambdaForm.class, false, null, null, null)) {
 773             if (!m.isStatic() || !m.isPackage())  continue;
 774             MethodType mt = m.getMethodType();
 775             if (mt.parameterCount() > 0 &&
 776                 mt.parameterType(0) == MethodHandle.class &&
 777                 m.getName().startsWith("interpret_")) {
 778                 String sig = null;
 779                 assert((sig = basicTypeSignature(mt)) != null &&
 780                         m.getName().equals("interpret" + sig.substring(sig.indexOf('_'))));
 781                 LambdaForm form = new LambdaForm(mt);
 782                 form.vmentry = m;
 783                 form = mt.form().setCachedLambdaForm(MethodTypeForm.LF_INTERPRET, form);
 784             }
 785         }
 786     }


 852     private static boolean checkInt(Class<?> type, Object x) {
 853         assert(x instanceof Integer);
 854         if (type == int.class)  return true;
 855         Wrapper w = Wrapper.forBasicType(type);
 856         assert(w.isSubwordOrInt());
 857         Object x1 = Wrapper.INT.wrap(w.wrap(x));
 858         return x.equals(x1);
 859     }
 860     private static boolean checkRef(Class<?> type, Object x) {
 861         assert(!type.isPrimitive());
 862         if (x == null)  return true;
 863         if (type.isInterface())  return true;
 864         return type.isInstance(x);
 865     }
 866 
 867     /** If the invocation count hits the threshold we spin bytecodes and call that subsequently. */
 868     private static final int COMPILE_THRESHOLD;
 869     static {
 870         COMPILE_THRESHOLD = Math.max(-1, MethodHandleStatics.COMPILE_THRESHOLD);
 871     }
 872     private int invocationCounter = 0; // a value of -1 indicates LambdaForm interpretation mode forever
 873 
 874     private boolean forceInterpretation() {
 875         return invocationCounter == -1;
 876     }
 877 
 878     @Hidden
 879     @DontInline
 880     /** Interpretively invoke this form on the given arguments. */
 881     Object interpretWithArguments(Object... argumentValues) throws Throwable {
 882         if (TRACE_INTERPRETER)
 883             return interpretWithArgumentsTracing(argumentValues);
 884         checkInvocationCounter();
 885         assert(arityCheck(argumentValues));
 886         Object[] values = Arrays.copyOf(argumentValues, names.length);
 887         for (int i = argumentValues.length; i < values.length; i++) {
 888             values[i] = interpretName(names[i], values);
 889         }
 890         Object rv = (result < 0) ? null : values[result];
 891         assert(resultCheck(argumentValues, rv));
 892         return rv;
 893     }
 894 
 895     @Hidden
 896     @DontInline
 897     /** Evaluate a single Name within this form, applying its function to its arguments. */
 898     Object interpretName(Name name, Object[] values) throws Throwable {
 899         if (TRACE_INTERPRETER)
 900             traceInterpreter("| interpretName", name.debugString(), (Object[]) null);
 901         Object[] arguments = Arrays.copyOf(name.arguments, name.arguments.length, Object[].class);
 902         for (int i = 0; i < arguments.length; i++) {
 903             Object a = arguments[i];
 904             if (a instanceof Name) {
 905                 int i2 = ((Name)a).index();
 906                 assert(names[i2] == a);
 907                 a = values[i2];
 908                 arguments[i] = a;
 909             }
 910         }
 911         return name.function.invokeWithArguments(arguments);
 912     }
 913 
 914     private void checkInvocationCounter() {
 915         if (COMPILE_THRESHOLD != 0 &&
 916             !forceInterpretation() && invocationCounter < COMPILE_THRESHOLD) {
 917             invocationCounter++;  // benign race
 918             if (invocationCounter >= COMPILE_THRESHOLD) {
 919                 // Replace vmentry with a bytecode version of this LF.
 920                 compileToBytecode();
 921             }
 922         }
 923     }
 924     Object interpretWithArgumentsTracing(Object... argumentValues) throws Throwable {
 925         traceInterpreter("[ interpretWithArguments", this, argumentValues);
 926         if (!forceInterpretation() && invocationCounter < COMPILE_THRESHOLD) {
 927             int ctr = invocationCounter++;  // benign race
 928             traceInterpreter("| invocationCounter", ctr);
 929             if (invocationCounter >= COMPILE_THRESHOLD) {
 930                 compileToBytecode();
 931             }
 932         }
 933         Object rval;
 934         try {
 935             assert(arityCheck(argumentValues));
 936             Object[] values = Arrays.copyOf(argumentValues, names.length);
 937             for (int i = argumentValues.length; i < values.length; i++) {
 938                 values[i] = interpretName(names[i], values);
 939             }
 940             rval = (result < 0) ? null : values[result];
 941         } catch (Throwable ex) {
 942             traceInterpreter("] throw =>", ex);
 943             throw ex;
 944         }
 945         traceInterpreter("] return =>", rval);
 946         return rval;


< prev index next >