src/jdk/nashorn/internal/lookup/MethodHandleFactory.java

Thu, 31 Aug 2017 15:30:47 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:30:47 +0800
changeset 952
6d5471a497fb
parent 546
2d4c8fa8a5f4
parent 0
b1a7da25b547
child 1205
4112748288bb
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     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  */
    26 package jdk.nashorn.internal.lookup;
    28 import java.io.ByteArrayOutputStream;
    29 import java.io.PrintStream;
    30 import java.lang.invoke.MethodHandle;
    31 import java.lang.invoke.MethodHandles;
    32 import java.lang.invoke.MethodType;
    33 import java.lang.invoke.SwitchPoint;
    34 import java.lang.reflect.Method;
    35 import java.util.ArrayList;
    36 import java.util.Arrays;
    37 import java.util.List;
    38 import java.util.logging.Level;
    39 import jdk.nashorn.internal.runtime.ConsString;
    40 import jdk.nashorn.internal.runtime.Debug;
    41 import jdk.nashorn.internal.runtime.DebugLogger;
    42 import jdk.nashorn.internal.runtime.ScriptObject;
    43 import jdk.nashorn.internal.runtime.options.Options;
    45 /**
    46  * This class is abstraction for all method handle, switchpoint and method type
    47  * operations. This enables the functionality interface to be subclassed and
    48  * intrumensted, as it has been proven vital to keep the number of method
    49  * handles in the system down.
    50  *
    51  * All operations of the above type should go through this class, and not
    52  * directly into java.lang.invoke
    53  *
    54  */
    55 public final class MethodHandleFactory {
    57     private static final MethodHandles.Lookup PUBLIC_LOOKUP = MethodHandles.publicLookup();
    58     private static final MethodHandles.Lookup LOOKUP        = MethodHandles.lookup();
    60     private static final Level TRACE_LEVEL = Level.INFO;
    62     private MethodHandleFactory() {
    63     }
    65     /**
    66      * Runtime exception that collects every reason that a method handle lookup operation can go wrong
    67      */
    68     @SuppressWarnings("serial")
    69     public static class LookupException extends RuntimeException {
    70         /**
    71          * Constructor
    72          * @param e causing exception
    73          */
    74         public LookupException(final Exception e) {
    75             super(e);
    76         }
    77     }
    79     /**
    80      * Helper function that takes a class or an object with a toString override
    81      * and shortens it to notation after last dot. This is used to facilitiate
    82      * pretty printouts in various debug loggers - internal only
    83      *
    84      * @param obj class or object
    85      *
    86      * @return pretty version of object as string
    87      */
    88     public static String stripName(final Object obj) {
    89         if (obj == null) {
    90             return "null";
    91         }
    93         if (obj instanceof Class) {
    94             return ((Class<?>)obj).getSimpleName();
    95         }
    96         return obj.toString();
    97     }
    99     private static final MethodHandleFunctionality STANDARD = new StandardMethodHandleFunctionality();
   100     private static final MethodHandleFunctionality FUNC;
   102     private static final String DEBUG_PROPERTY = "nashorn.methodhandles.debug";
   103     private static final DebugLogger LOG = new DebugLogger("methodhandles", DEBUG_PROPERTY);
   105     static {
   106         if (LOG.isEnabled() || Options.getBooleanProperty(DEBUG_PROPERTY)) {
   107             if (Options.getStringProperty(DEBUG_PROPERTY, "").equals("create")) {
   108                 FUNC = new TraceCreateMethodHandleFunctionality();
   109             } else {
   110                 FUNC = new TraceMethodHandleFunctionality();
   111             }
   112         } else {
   113             FUNC  = STANDARD;
   114         }
   115     }
   117     private static final boolean PRINT_STACKTRACE = Options.getBooleanProperty("nashorn.methodhandles.debug.stacktrace");
   120     /**
   121      * Return the method handle functionality used for all method handle operations
   122      * @return a method handle functionality implementation
   123      */
   124     public static MethodHandleFunctionality getFunctionality() {
   125         return FUNC;
   126     }
   128     private static final MethodHandle TRACE        = STANDARD.findStatic(LOOKUP, MethodHandleFactory.class, "traceArgs",   MethodType.methodType(void.class, DebugLogger.class, String.class, int.class, Object[].class));
   129     private static final MethodHandle TRACE_RETURN = STANDARD.findStatic(LOOKUP, MethodHandleFactory.class, "traceReturn", MethodType.methodType(Object.class, DebugLogger.class, Object.class));
   131     /**
   132      * Tracer that is applied before a value is returned from the traced function. It will output the return
   133      * value and its class
   134      *
   135      * @param value return value for filter
   136      * @return return value unmodified
   137      */
   138     static Object traceReturn(final DebugLogger logger, final Object value) {
   139         final String str = "\treturn: " + stripName(value) + " [type=" + (value == null ? "null" : stripName(value.getClass()) + ']');
   140         logger.log(TRACE_LEVEL, str);
   141         return value;
   142     }
   144     /**
   145      * Tracer that is applied before a function is called, printing the arguments
   146      *
   147      * @param tag  tag to start the debug printout string
   148      * @param paramStart param index to start outputting from
   149      * @param args arguments to the function
   150      */
   151     static void traceArgs(final DebugLogger logger, final String tag, final int paramStart, final Object... args) {
   152         final StringBuilder sb = new StringBuilder();
   154         sb.append(tag);
   156         for (int i = paramStart; i < args.length; i++) {
   157             if (i == paramStart) {
   158                 sb.append(" => args: ");
   159             }
   161             sb.append('\'').
   162                 append(stripName(argString(args[i]))).
   163                 append('\'').
   164                 append(' ').
   165                 append('[').
   166                 append("type=").
   167                 append(args[i] == null ? "null" : stripName(args[i].getClass())).
   168                 append(']');
   170             if (i + 1 < args.length) {
   171                 sb.append(", ");
   172             }
   173         }
   175         assert logger != null;
   176         logger.log(TRACE_LEVEL, sb);
   177         stacktrace(logger);
   178     }
   180     private static void stacktrace(final DebugLogger logger) {
   181         if (!PRINT_STACKTRACE) {
   182             return;
   183         }
   184         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
   185         final PrintStream ps = new PrintStream(baos);
   186         new Throwable().printStackTrace(ps);
   187         logger.log(TRACE_LEVEL, baos.toString());
   188     }
   190     private static String argString(final Object arg) {
   191         if (arg == null) {
   192             return "null";
   193         }
   195         if (arg.getClass().isArray()) {
   196             final List<Object> list = new ArrayList<>();
   197             for (final Object elem : (Object[])arg) {
   198                 list.add('\'' + argString(elem) + '\'');
   199             }
   201             return list.toString();
   202         }
   204         if (arg instanceof ScriptObject) {
   205             return arg.toString() +
   206                 " (map=" + Debug.id((((ScriptObject)arg).getMap())) +
   207                 ")";
   208         }
   210         return arg.toString();
   211     }
   213     /**
   214      * Add a debug printout to a method handle, tracing parameters and return values
   215      *
   216      * @param logger a specific logger to which to write the output
   217      * @param mh  method handle to trace
   218      * @param tag start of trace message
   219      * @return traced method handle
   220      */
   221     public static MethodHandle addDebugPrintout(final DebugLogger logger, final MethodHandle mh, final Object tag) {
   222         return addDebugPrintout(logger, mh, 0, true, tag);
   223     }
   226     /**
   227      * Add a debug printout to a method handle, tracing parameters and return values
   228      *
   229      * @param logger a specific logger to which to write the output
   230      * @param mh  method handle to trace
   231      * @param paramStart first param to print/trace
   232      * @param printReturnValue should we print/trace return value if available?
   233      * @param tag start of trace message
   234      * @return  traced method handle
   235      */
   236     public static MethodHandle addDebugPrintout(final DebugLogger logger, final MethodHandle mh, final int paramStart, final boolean printReturnValue, final Object tag) {
   237         final MethodType type = mh.type();
   239         if (logger != null && logger.levelAbove(TRACE_LEVEL)) {
   240             return mh;
   241         }
   243         assert logger != null;
   244         assert TRACE != null;
   246         MethodHandle trace = MethodHandles.insertArguments(TRACE, 0, logger, tag, paramStart);
   248         trace = MethodHandles.foldArguments(
   249                 mh,
   250                 trace.asCollector(
   251                     Object[].class,
   252                     type.parameterCount()).
   253                 asType(type.changeReturnType(void.class)));
   255         final Class<?> retType = type.returnType();
   256         if (retType != void.class && printReturnValue) {
   257             final MethodHandle traceReturn = MethodHandles.insertArguments(TRACE_RETURN, 0, logger);
   258             trace = MethodHandles.filterReturnValue(trace,
   259                     traceReturn.asType(
   260                         traceReturn.type().changeParameterType(0, retType).changeReturnType(retType)));
   261         }
   263         return trace;
   264     }
   266     /**
   267      * The standard class that marshalls all method handle operations to the java.lang.invoke
   268      * package. This exists only so that it can be subclassed and method handles created from
   269      * Nashorn made possible to instrument.
   270      *
   271      * All Nashorn classes should use the MethodHandleFactory for their method handle operations
   272      */
   273     private static class StandardMethodHandleFunctionality implements MethodHandleFunctionality {
   275         @Override
   276         public MethodHandle filterArguments(final MethodHandle target, final int pos, final MethodHandle... filters) {
   277             return MethodHandles.filterArguments(target, pos, filters);
   278         }
   280         @Override
   281         public MethodHandle filterReturnValue(final MethodHandle target, final MethodHandle filter) {
   282             return MethodHandles.filterReturnValue(target, filter);
   283         }
   285         @Override
   286         public MethodHandle guardWithTest(final MethodHandle test, final MethodHandle target, final MethodHandle fallback) {
   287             return MethodHandles.guardWithTest(test, target, fallback);
   288         }
   290         @Override
   291         public MethodHandle insertArguments(final MethodHandle target, final int pos, final Object... values) {
   292             return MethodHandles.insertArguments(target, pos, values);
   293         }
   295         @Override
   296         public MethodHandle dropArguments(final MethodHandle target, final int pos, final Class<?>... valueTypes) {
   297             return MethodHandles.dropArguments(target, pos, valueTypes);
   298         }
   300         @Override
   301         public MethodHandle dropArguments(final MethodHandle target, final int pos, final List<Class<?>> valueTypes) {
   302             return MethodHandles.dropArguments(target, pos, valueTypes);
   303         }
   305         @Override
   306         public MethodHandle asType(final MethodHandle handle, final MethodType type) {
   307             return handle.asType(type);
   308         }
   310         @Override
   311         public MethodHandle bindTo(final MethodHandle handle, final Object x) {
   312             return handle.bindTo(x);
   313         }
   315         @Override
   316         public MethodHandle foldArguments(final MethodHandle target, final MethodHandle combiner) {
   317             return MethodHandles.foldArguments(target, combiner);
   318         }
   320         @Override
   321         public MethodHandle explicitCastArguments(final MethodHandle target, final MethodType type) {
   322             return MethodHandles.explicitCastArguments(target, type);
   323         }
   325         @Override
   326         public MethodHandle arrayElementGetter(final Class<?> type) {
   327             return MethodHandles.arrayElementGetter(type);
   328         }
   330         @Override
   331         public MethodHandle arrayElementSetter(final Class<?> type) {
   332             return MethodHandles.arrayElementSetter(type);
   333         }
   335         @Override
   336         public MethodHandle throwException(final Class<?> returnType, final Class<? extends Throwable> exType) {
   337             return MethodHandles.throwException(returnType, exType);
   338         }
   340         @Override
   341         public MethodHandle constant(final Class<?> type, final Object value) {
   342             return MethodHandles.constant(type, value);
   343         }
   345         @Override
   346         public MethodHandle asCollector(final MethodHandle handle, final Class<?> arrayType, final int arrayLength) {
   347             return handle.asCollector(arrayType, arrayLength);
   348         }
   350         @Override
   351         public MethodHandle asSpreader(final MethodHandle handle, final Class<?> arrayType, final int arrayLength) {
   352             return handle.asSpreader(arrayType, arrayLength);
   353         }
   355         @Override
   356         public MethodHandle getter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
   357             try {
   358                 return explicitLookup.findGetter(clazz, name, type);
   359             } catch (final NoSuchFieldException | IllegalAccessException e) {
   360                 throw new LookupException(e);
   361             }
   362         }
   364         @Override
   365         public MethodHandle staticGetter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
   366             try {
   367                 return explicitLookup.findStaticGetter(clazz, name, type);
   368             } catch (final NoSuchFieldException | IllegalAccessException e) {
   369                 throw new LookupException(e);
   370             }
   371         }
   374         @Override
   375         public MethodHandle setter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
   376             try {
   377                 return explicitLookup.findSetter(clazz, name, type);
   378             } catch (final NoSuchFieldException | IllegalAccessException e) {
   379                 throw new LookupException(e);
   380             }
   381         }
   383         @Override
   384         public MethodHandle staticSetter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
   385             try {
   386                 return explicitLookup.findStaticSetter(clazz, name, type);
   387             } catch (final NoSuchFieldException | IllegalAccessException e) {
   388                 throw new LookupException(e);
   389             }
   390         }
   392         @Override
   393         public MethodHandle find(final Method method) {
   394             try {
   395                 return PUBLIC_LOOKUP.unreflect(method);
   396             } catch (final IllegalAccessException e) {
   397                 throw new LookupException(e);
   398             }
   399         }
   401         @Override
   402         public MethodHandle findStatic(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type) {
   403             try {
   404                 return explicitLookup.findStatic(clazz, name, type);
   405             } catch (final NoSuchMethodException | IllegalAccessException e) {
   406                 throw new LookupException(e);
   407             }
   408         }
   410         @Override
   411         public MethodHandle findVirtual(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type) {
   412             try {
   413                 return explicitLookup.findVirtual(clazz, name, type);
   414             } catch (final NoSuchMethodException | IllegalAccessException e) {
   415                 throw new LookupException(e);
   416             }
   417         }
   419         @Override
   420         public SwitchPoint createSwitchPoint() {
   421             return new SwitchPoint();
   422         }
   424         @Override
   425         public MethodHandle guardWithTest(final SwitchPoint sp, final MethodHandle before, final MethodHandle after) {
   426             return sp.guardWithTest(before, after);
   427         }
   429         @Override
   430         public MethodType type(final Class<?> returnType, final Class<?>... paramTypes) {
   431             return MethodType.methodType(returnType, paramTypes);
   432         }
   434     }
   436     /**
   437      * Class used for instrumenting and debugging Nashorn generated method handles
   438      */
   439     private static class TraceMethodHandleFunctionality extends StandardMethodHandleFunctionality {
   441         protected static String describe(final Object... data) {
   442             final StringBuilder sb = new StringBuilder();
   444             for (int i = 0; i < data.length; i++) {
   445                 final Object d = data[i];
   446                 if (d == null) {
   447                     sb.append("<null> ");
   448                 } else if (d instanceof String || d instanceof ConsString) {
   449                     sb.append(d.toString());
   450                     sb.append(' ');
   451                 } else if (d.getClass().isArray()) {
   452                     sb.append("[ ");
   453                     for (final Object da : (Object[])d) {
   454                         sb.append(describe(new Object[]{ da })).append(' ');
   455                     }
   456                     sb.append("] ");
   457                 } else {
   458                     sb.append(d)
   459                         .append('{')
   460                         .append(Integer.toHexString(System.identityHashCode(d)))
   461                         .append('}');
   462                 }
   464                 if (i + 1 < data.length) {
   465                     sb.append(", ");
   466                 }
   467             }
   469             return sb.toString();
   470         }
   472         public MethodHandle debug(final MethodHandle master, final String str, final Object... args) {
   473             return addDebugPrintout(LOG, master, Integer.MAX_VALUE, false, str + ' ' + describe(args));
   474         }
   476         @Override
   477         public MethodHandle filterArguments(final MethodHandle target, final int pos, final MethodHandle... filters) {
   478             final MethodHandle mh = super.filterArguments(target, pos, filters);
   479             return debug(mh, "filterArguments", target, pos, filters);
   480         }
   482         @Override
   483         public MethodHandle filterReturnValue(final MethodHandle target, final MethodHandle filter) {
   484             final MethodHandle mh = super.filterReturnValue(target, filter);
   485             return debug(mh, "filterReturnValue", target, filter);
   486         }
   488         @Override
   489         public MethodHandle guardWithTest(final MethodHandle test, final MethodHandle target, final MethodHandle fallback) {
   490             final MethodHandle mh = super.guardWithTest(test, target, fallback);
   491             return debug(mh, "guardWithTest", test, target, fallback);
   492         }
   494         @Override
   495         public MethodHandle insertArguments(final MethodHandle target, final int pos, final Object... values) {
   496             final MethodHandle mh = super.insertArguments(target, pos, values);
   497             return debug(mh, "insertArguments", target, pos, values);
   498         }
   500         @Override
   501         public MethodHandle dropArguments(final MethodHandle target, final int pos, final Class<?>... values) {
   502             final MethodHandle mh = super.dropArguments(target, pos, values);
   503             return debug(mh, "dropArguments", target, pos, values);
   504         }
   506         @Override
   507         public MethodHandle dropArguments(final MethodHandle target, final int pos, final List<Class<?>> values) {
   508             final MethodHandle mh = super.dropArguments(target, pos, values);
   509             return debug(mh, "dropArguments", target, pos, values);
   510         }
   512         @Override
   513         public MethodHandle asType(final MethodHandle handle, final MethodType type) {
   514             final MethodHandle mh = super.asType(handle, type);
   515             return debug(mh, "asType", handle, type);
   516         }
   518         @Override
   519         public MethodHandle bindTo(final MethodHandle handle, final Object x) {
   520             final MethodHandle mh = super.bindTo(handle, x);
   521             return debug(mh, "bindTo", handle, x);
   522         }
   524         @Override
   525         public MethodHandle foldArguments(final MethodHandle target, final MethodHandle combiner) {
   526             final MethodHandle mh = super.foldArguments(target, combiner);
   527             return debug(mh, "foldArguments", target, combiner);
   528         }
   530         @Override
   531         public MethodHandle explicitCastArguments(final MethodHandle target, final MethodType type) {
   532             final MethodHandle mh = super.explicitCastArguments(target, type);
   533             return debug(mh, "explicitCastArguments", target, type);
   534         }
   536         @Override
   537         public MethodHandle arrayElementGetter(final Class<?> type) {
   538             final MethodHandle mh = super.arrayElementGetter(type);
   539             return debug(mh, "arrayElementGetter", type);
   540         }
   542         @Override
   543         public MethodHandle arrayElementSetter(final Class<?> type) {
   544             final MethodHandle mh = super.arrayElementSetter(type);
   545             return debug(mh, "arrayElementSetter", type);
   546         }
   548         @Override
   549         public MethodHandle throwException(final Class<?> returnType, final Class<? extends Throwable> exType) {
   550             final MethodHandle mh = super.throwException(returnType, exType);
   551             return debug(mh, "throwException", returnType, exType);
   552         }
   554         @Override
   555         public MethodHandle constant(final Class<?> type, final Object value) {
   556             final MethodHandle mh = super.constant(type, value);
   557             return debug(mh, "constant", type, value);
   558         }
   560         @Override
   561         public MethodHandle asCollector(final MethodHandle handle, final Class<?> arrayType, final int arrayLength) {
   562             final MethodHandle mh = super.asCollector(handle, arrayType, arrayLength);
   563             return debug(mh, "asCollector", handle, arrayType, arrayLength);
   564         }
   566         @Override
   567         public MethodHandle asSpreader(final MethodHandle handle, final Class<?> arrayType, final int arrayLength) {
   568             final MethodHandle mh = super.asSpreader(handle, arrayType, arrayLength);
   569             return debug(mh, "asSpreader", handle, arrayType, arrayLength);
   570         }
   572         @Override
   573         public MethodHandle getter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
   574             final MethodHandle mh = super.getter(explicitLookup, clazz, name, type);
   575             return debug(mh, "getter", explicitLookup, clazz, name, type);
   576         }
   578         @Override
   579         public MethodHandle staticGetter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
   580             final MethodHandle mh = super.staticGetter(explicitLookup, clazz, name, type);
   581             return debug(mh, "static getter", explicitLookup, clazz, name, type);
   582         }
   584         @Override
   585         public MethodHandle setter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
   586             final MethodHandle mh = super.setter(explicitLookup, clazz, name, type);
   587             return debug(mh, "setter", explicitLookup, clazz, name, type);
   588         }
   590         @Override
   591         public MethodHandle staticSetter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
   592             final MethodHandle mh = super.staticSetter(explicitLookup, clazz, name, type);
   593             return debug(mh, "static setter", explicitLookup, clazz, name, type);
   594         }
   596         @Override
   597         public MethodHandle find(final Method method) {
   598             final MethodHandle mh = super.find(method);
   599             return debug(mh, "find", method);
   600         }
   602         @Override
   603         public MethodHandle findStatic(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type) {
   604             final MethodHandle mh = super.findStatic(explicitLookup, clazz, name, type);
   605             return debug(mh, "findStatic", explicitLookup, clazz, name, type);
   606         }
   608         @Override
   609         public MethodHandle findVirtual(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type) {
   610             final MethodHandle mh = super.findVirtual(explicitLookup, clazz, name, type);
   611             return debug(mh, "findVirtual", explicitLookup, clazz, name, type);
   612         }
   614         @Override
   615         public SwitchPoint createSwitchPoint() {
   616             final SwitchPoint sp = super.createSwitchPoint();
   617             LOG.log(TRACE_LEVEL, "createSwitchPoint ", sp);
   618             return sp;
   619         }
   621         @Override
   622         public MethodHandle guardWithTest(final SwitchPoint sp, final MethodHandle before, final MethodHandle after) {
   623             final MethodHandle mh = super.guardWithTest(sp, before, after);
   624             return debug(mh, "guardWithTest", sp, before, after);
   625         }
   627         @Override
   628         public MethodType type(final Class<?> returnType, final Class<?>... paramTypes) {
   629             final MethodType mt = super.type(returnType, paramTypes);
   630             LOG.log(TRACE_LEVEL, "methodType ", returnType, " ", Arrays.toString(paramTypes), " ", mt);
   631             return mt;
   632         }
   633     }
   635     /**
   636      * Class used for debugging Nashorn generated method handles
   637      */
   638     private static class TraceCreateMethodHandleFunctionality extends TraceMethodHandleFunctionality {
   639         @Override
   640         public MethodHandle debug(final MethodHandle master, final String str, final Object... args) {
   641             LOG.log(TRACE_LEVEL, str, " ", describe(args));
   642             stacktrace(LOG);
   643             return master;
   644         }
   645     }
   646 }

mercurial