--- old/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/lookup/MethodHandleFactory.java 2020-04-15 18:48:25.000000000 +0530 +++ /dev/null 2020-04-15 18:48:25.000000000 +0530 @@ -1,589 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.nashorn.internal.lookup; - -import static jdk.nashorn.internal.runtime.JSType.isString; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.invoke.SwitchPoint; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.logging.Level; -import jdk.nashorn.internal.runtime.Context; -import jdk.nashorn.internal.runtime.Debug; -import jdk.nashorn.internal.runtime.ScriptObject; -import jdk.nashorn.internal.runtime.logging.DebugLogger; -import jdk.nashorn.internal.runtime.logging.Loggable; -import jdk.nashorn.internal.runtime.logging.Logger; -import jdk.nashorn.internal.runtime.options.Options; - -/** - * This class is abstraction for all method handle, switchpoint and method type - * operations. This enables the functionality interface to be subclassed and - * instrumented, as it has been proven vital to keep the number of method - * handles in the system down. - * - * All operations of the above type should go through this class, and not - * directly into java.lang.invoke - * - */ -public final class MethodHandleFactory { - - private static final MethodHandles.Lookup PUBLIC_LOOKUP = MethodHandles.publicLookup(); - private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); - - private static final Level TRACE_LEVEL = Level.INFO; - - private MethodHandleFactory() { - } - - /** - * Runtime exception that collects every reason that a method handle lookup operation can go wrong - */ - @SuppressWarnings("serial") - public static class LookupException extends RuntimeException { - /** - * Constructor - * @param e causing exception - */ - public LookupException(final Exception e) { - super(e); - } - } - - /** - * Helper function that takes a class or an object with a toString override - * and shortens it to notation after last dot. This is used to facilitiate - * pretty printouts in various debug loggers - internal only - * - * @param obj class or object - * - * @return pretty version of object as string - */ - public static String stripName(final Object obj) { - if (obj == null) { - return "null"; - } - - if (obj instanceof Class) { - return ((Class)obj).getSimpleName(); - } - return obj.toString(); - } - - private static final MethodHandleFunctionality FUNC = new StandardMethodHandleFunctionality(); - private static final boolean PRINT_STACKTRACE = Options.getBooleanProperty("nashorn.methodhandles.debug.stacktrace"); - - /** - * Return the method handle functionality used for all method handle operations - * @return a method handle functionality implementation - */ - public static MethodHandleFunctionality getFunctionality() { - return FUNC; - } - - private static final MethodHandle TRACE = FUNC.findStatic(LOOKUP, MethodHandleFactory.class, "traceArgs", MethodType.methodType(void.class, DebugLogger.class, String.class, int.class, Object[].class)); - private static final MethodHandle TRACE_RETURN = FUNC.findStatic(LOOKUP, MethodHandleFactory.class, "traceReturn", MethodType.methodType(Object.class, DebugLogger.class, Object.class)); - private static final MethodHandle TRACE_RETURN_VOID = FUNC.findStatic(LOOKUP, MethodHandleFactory.class, "traceReturnVoid", MethodType.methodType(void.class, DebugLogger.class)); - - private static final String VOID_TAG = "[VOID]"; - - private static void err(final String str) { - Context.getContext().getErr().println(str); - } - - /** - * Tracer that is applied before a value is returned from the traced function. It will output the return - * value and its class - * - * @param value return value for filter - * @return return value unmodified - */ - static Object traceReturn(final DebugLogger logger, final Object value) { - final String str = " return" + - (VOID_TAG.equals(value) ? - ";" : - " " + stripName(value) + "; // [type=" + (value == null ? "null]" : stripName(value.getClass()) + ']')); - if (logger == null) { - err(str); - } else if (logger.isEnabled()) { - logger.log(TRACE_LEVEL, str); - } - - return value; - } - - static void traceReturnVoid(final DebugLogger logger) { - traceReturn(logger, VOID_TAG); - } - - /** - * Tracer that is applied before a function is called, printing the arguments - * - * @param tag tag to start the debug printout string - * @param paramStart param index to start outputting from - * @param args arguments to the function - */ - static void traceArgs(final DebugLogger logger, final String tag, final int paramStart, final Object... args) { - final StringBuilder sb = new StringBuilder(); - - sb.append(tag); - - for (int i = paramStart; i < args.length; i++) { - if (i == paramStart) { - sb.append(" => args: "); - } - - sb.append('\''). - append(stripName(argString(args[i]))). - append('\''). - append(' '). - append('['). - append("type="). - append(args[i] == null ? "null" : stripName(args[i].getClass())). - append(']'); - - if (i + 1 < args.length) { - sb.append(", "); - } - } - - if (logger == null) { - err(sb.toString()); - } else { - logger.log(TRACE_LEVEL, sb); - } - stacktrace(logger); - } - - private static void stacktrace(final DebugLogger logger) { - if (!PRINT_STACKTRACE) { - return; - } - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final PrintStream ps = new PrintStream(baos); - new Throwable().printStackTrace(ps); - final String st = baos.toString(); - if (logger == null) { - err(st); - } else { - logger.log(TRACE_LEVEL, st); - } - } - - private static String argString(final Object arg) { - if (arg == null) { - return "null"; - } - - if (arg.getClass().isArray()) { - final List list = new ArrayList<>(); - for (final Object elem : (Object[])arg) { - list.add('\'' + argString(elem) + '\''); - } - - return list.toString(); - } - - if (arg instanceof ScriptObject) { - return arg.toString() + - " (map=" + Debug.id(((ScriptObject)arg).getMap()) + - ')'; - } - - return arg.toString(); - } - - /** - * Add a debug printout to a method handle, tracing parameters and return values - * Output will be unconditional to stderr - * - * @param mh method handle to trace - * @param tag start of trace message - * @return traced method handle - */ - public static MethodHandle addDebugPrintout(final MethodHandle mh, final Object tag) { - return addDebugPrintout(null, Level.OFF, mh, 0, true, tag); - } - - /** - * Add a debug printout to a method handle, tracing parameters and return values - * - * @param logger a specific logger to which to write the output - * @param level level over which to print - * @param mh method handle to trace - * @param tag start of trace message - * @return traced method handle - */ - public static MethodHandle addDebugPrintout(final DebugLogger logger, final Level level, final MethodHandle mh, final Object tag) { - return addDebugPrintout(logger, level, mh, 0, true, tag); - } - - /** - * Add a debug printout to a method handle, tracing parameters and return values - * Output will be unconditional to stderr - * - * @param mh method handle to trace - * @param paramStart first param to print/trace - * @param printReturnValue should we print/trace return value if available? - * @param tag start of trace message - * @return traced method handle - */ - public static MethodHandle addDebugPrintout(final MethodHandle mh, final int paramStart, final boolean printReturnValue, final Object tag) { - return addDebugPrintout(null, Level.OFF, mh, paramStart, printReturnValue, tag); - } - - /** - * Add a debug printout to a method handle, tracing parameters and return values - * - * @param logger a specific logger to which to write the output - * @param level level over which to print - * @param mh method handle to trace - * @param paramStart first param to print/trace - * @param printReturnValue should we print/trace return value if available? - * @param tag start of trace message - * @return traced method handle - */ - public static MethodHandle addDebugPrintout(final DebugLogger logger, final Level level, final MethodHandle mh, final int paramStart, final boolean printReturnValue, final Object tag) { - final MethodType type = mh.type(); - - //if there is no logger, or if it's set to log only coarser events - //than the trace level, skip and return - if (logger == null || !logger.isLoggable(level)) { - return mh; - } - - assert TRACE != null; - - MethodHandle trace = MethodHandles.insertArguments(TRACE, 0, logger, tag, paramStart); - - trace = MethodHandles.foldArguments( - mh, - trace.asCollector( - Object[].class, - type.parameterCount()). - asType(type.changeReturnType(void.class))); - - final Class retType = type.returnType(); - if (printReturnValue) { - if (retType != void.class) { - final MethodHandle traceReturn = MethodHandles.insertArguments(TRACE_RETURN, 0, logger); - trace = MethodHandles.filterReturnValue(trace, - traceReturn.asType( - traceReturn.type().changeParameterType(0, retType).changeReturnType(retType))); - } else { - trace = MethodHandles.filterReturnValue(trace, MethodHandles.insertArguments(TRACE_RETURN_VOID, 0, logger)); - } - } - - return trace; - } - - /** - * Class that marshalls all method handle operations to the java.lang.invoke - * package. This exists only so that it can be subclassed and method handles created from - * Nashorn made possible to instrument. - * - * All Nashorn classes should use the MethodHandleFactory for their method handle operations - */ - @Logger(name="methodhandles") - private static class StandardMethodHandleFunctionality implements MethodHandleFunctionality, Loggable { - - // for bootstrapping reasons, because a lot of static fields use MH for lookups, we - // need to set the logger when the Global object is finished. This means that we don't - // get instrumentation for public static final MethodHandle SOMETHING = MH... in the builtin - // classes, but that doesn't matter, because this is usually not where we want it - private DebugLogger log = DebugLogger.DISABLED_LOGGER; - - public StandardMethodHandleFunctionality() { - } - - @Override - public DebugLogger initLogger(final Context context) { - return this.log = context.getLogger(this.getClass()); - } - - @Override - public DebugLogger getLogger() { - return log; - } - - protected static String describe(final Object... data) { - final StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < data.length; i++) { - final Object d = data[i]; - if (d == null) { - sb.append(" "); - } else if (isString(d)) { - sb.append(d.toString()); - sb.append(' '); - } else if (d.getClass().isArray()) { - sb.append("[ "); - for (final Object da : (Object[])d) { - sb.append(describe(new Object[]{ da })).append(' '); - } - sb.append("] "); - } else { - sb.append(d) - .append('{') - .append(Integer.toHexString(System.identityHashCode(d))) - .append('}'); - } - - if (i + 1 < data.length) { - sb.append(", "); - } - } - - return sb.toString(); - } - - public MethodHandle debug(final MethodHandle master, final String str, final Object... args) { - if (log.isEnabled()) { - if (PRINT_STACKTRACE) { - stacktrace(log); - } - return addDebugPrintout(log, Level.INFO, master, Integer.MAX_VALUE, false, str + ' ' + describe(args)); - } - return master; - } - - @Override - public MethodHandle filterArguments(final MethodHandle target, final int pos, final MethodHandle... filters) { - final MethodHandle mh = MethodHandles.filterArguments(target, pos, filters); - return debug(mh, "filterArguments", target, pos, filters); - } - - @Override - public MethodHandle filterReturnValue(final MethodHandle target, final MethodHandle filter) { - final MethodHandle mh = MethodHandles.filterReturnValue(target, filter); - return debug(mh, "filterReturnValue", target, filter); - } - - @Override - public MethodHandle guardWithTest(final MethodHandle test, final MethodHandle target, final MethodHandle fallback) { - final MethodHandle mh = MethodHandles.guardWithTest(test, target, fallback); - return debug(mh, "guardWithTest", test, target, fallback); - } - - @Override - public MethodHandle insertArguments(final MethodHandle target, final int pos, final Object... values) { - final MethodHandle mh = MethodHandles.insertArguments(target, pos, values); - return debug(mh, "insertArguments", target, pos, values); - } - - @Override - public MethodHandle dropArguments(final MethodHandle target, final int pos, final Class... values) { - final MethodHandle mh = MethodHandles.dropArguments(target, pos, values); - return debug(mh, "dropArguments", target, pos, values); - } - - @Override - public MethodHandle dropArguments(final MethodHandle target, final int pos, final List> values) { - final MethodHandle mh = MethodHandles.dropArguments(target, pos, values); - return debug(mh, "dropArguments", target, pos, values); - } - - @Override - public MethodHandle asType(final MethodHandle handle, final MethodType type) { - final MethodHandle mh = handle.asType(type); - return debug(mh, "asType", handle, type); - } - - @Override - public MethodHandle bindTo(final MethodHandle handle, final Object x) { - final MethodHandle mh = handle.bindTo(x); - return debug(mh, "bindTo", handle, x); - } - - @Override - public MethodHandle foldArguments(final MethodHandle target, final MethodHandle combiner) { - final MethodHandle mh = MethodHandles.foldArguments(target, combiner); - return debug(mh, "foldArguments", target, combiner); - } - - @Override - public MethodHandle explicitCastArguments(final MethodHandle target, final MethodType type) { - final MethodHandle mh = MethodHandles.explicitCastArguments(target, type); - return debug(mh, "explicitCastArguments", target, type); - } - - @Override - public MethodHandle arrayElementGetter(final Class type) { - final MethodHandle mh = MethodHandles.arrayElementGetter(type); - return debug(mh, "arrayElementGetter", type); - } - - @Override - public MethodHandle arrayElementSetter(final Class type) { - final MethodHandle mh = MethodHandles.arrayElementSetter(type); - return debug(mh, "arrayElementSetter", type); - } - - @Override - public MethodHandle throwException(final Class returnType, final Class exType) { - final MethodHandle mh = MethodHandles.throwException(returnType, exType); - return debug(mh, "throwException", returnType, exType); - } - - @Override - public MethodHandle catchException(final MethodHandle target, final Class exType, final MethodHandle handler) { - final MethodHandle mh = MethodHandles.catchException(target, exType, handler); - return debug(mh, "catchException", exType); - } - - @Override - public MethodHandle constant(final Class type, final Object value) { - final MethodHandle mh = MethodHandles.constant(type, value); - return debug(mh, "constant", type, value); - } - - @Override - public MethodHandle identity(final Class type) { - final MethodHandle mh = MethodHandles.identity(type); - return debug(mh, "identity", type); - } - - @Override - public MethodHandle asCollector(final MethodHandle handle, final Class arrayType, final int arrayLength) { - final MethodHandle mh = handle.asCollector(arrayType, arrayLength); - return debug(mh, "asCollector", handle, arrayType, arrayLength); - } - - @Override - public MethodHandle asSpreader(final MethodHandle handle, final Class arrayType, final int arrayLength) { - final MethodHandle mh = handle.asSpreader(arrayType, arrayLength); - return debug(mh, "asSpreader", handle, arrayType, arrayLength); - } - - @Override - public MethodHandle getter(final MethodHandles.Lookup explicitLookup, final Class clazz, final String name, final Class type) { - try { - final MethodHandle mh = explicitLookup.findGetter(clazz, name, type); - return debug(mh, "getter", explicitLookup, clazz, name, type); - } catch (final NoSuchFieldException | IllegalAccessException e) { - throw new LookupException(e); - } - } - - @Override - public MethodHandle staticGetter(final MethodHandles.Lookup explicitLookup, final Class clazz, final String name, final Class type) { - try { - final MethodHandle mh = explicitLookup.findStaticGetter(clazz, name, type); - return debug(mh, "static getter", explicitLookup, clazz, name, type); - } catch (final NoSuchFieldException | IllegalAccessException e) { - throw new LookupException(e); - } - } - - @Override - public MethodHandle setter(final MethodHandles.Lookup explicitLookup, final Class clazz, final String name, final Class type) { - try { - final MethodHandle mh = explicitLookup.findSetter(clazz, name, type); - return debug(mh, "setter", explicitLookup, clazz, name, type); - } catch (final NoSuchFieldException | IllegalAccessException e) { - throw new LookupException(e); - } - } - - @Override - public MethodHandle staticSetter(final MethodHandles.Lookup explicitLookup, final Class clazz, final String name, final Class type) { - try { - final MethodHandle mh = explicitLookup.findStaticSetter(clazz, name, type); - return debug(mh, "static setter", explicitLookup, clazz, name, type); - } catch (final NoSuchFieldException | IllegalAccessException e) { - throw new LookupException(e); - } - } - - @Override - public MethodHandle find(final Method method) { - try { - final MethodHandle mh = PUBLIC_LOOKUP.unreflect(method); - return debug(mh, "find", method); - } catch (final IllegalAccessException e) { - throw new LookupException(e); - } - } - - @Override - public MethodHandle findStatic(final MethodHandles.Lookup explicitLookup, final Class clazz, final String name, final MethodType type) { - try { - final MethodHandle mh = explicitLookup.findStatic(clazz, name, type); - return debug(mh, "findStatic", explicitLookup, clazz, name, type); - } catch (final NoSuchMethodException | IllegalAccessException e) { - throw new LookupException(e); - } - } - - @Override - public MethodHandle findSpecial(final MethodHandles.Lookup explicitLookup, final Class clazz, final String name, final MethodType type, final Class thisClass) { - try { - final MethodHandle mh = explicitLookup.findSpecial(clazz, name, type, thisClass); - return debug(mh, "findSpecial", explicitLookup, clazz, name, type); - } catch (final NoSuchMethodException | IllegalAccessException e) { - throw new LookupException(e); - } - } - - @Override - public MethodHandle findVirtual(final MethodHandles.Lookup explicitLookup, final Class clazz, final String name, final MethodType type) { - try { - final MethodHandle mh = explicitLookup.findVirtual(clazz, name, type); - return debug(mh, "findVirtual", explicitLookup, clazz, name, type); - } catch (final NoSuchMethodException | IllegalAccessException e) { - throw new LookupException(e); - } - } - - @Override - public SwitchPoint createSwitchPoint() { - final SwitchPoint sp = new SwitchPoint(); - log.log(TRACE_LEVEL, "createSwitchPoint ", sp); - return sp; - } - - @Override - public MethodHandle guardWithTest(final SwitchPoint sp, final MethodHandle before, final MethodHandle after) { - final MethodHandle mh = sp.guardWithTest(before, after); - return debug(mh, "guardWithTest", sp, before, after); - } - - @Override - public MethodType type(final Class returnType, final Class... paramTypes) { - final MethodType mt = MethodType.methodType(returnType, paramTypes); - log.log(TRACE_LEVEL, "methodType ", returnType, " ", Arrays.toString(paramTypes), " ", mt); - return mt; - } - } -}