public class BeansLinker implements GuardingDynamicLinker {
    private static final ClassValue<TypeBasedGuardingDynamicLinker> linkers = new ClassValue<TypeBasedGuardingDynamicLinker>() {
        @Override
        protected TypeBasedGuardingDynamicLinker computeValue(final Class<?> clazz) {
            // If ClassValue.put() were public, we could just pre-populate with these known mappings...
            return
                clazz == Class.class ? new ClassLinker() :
                clazz == StaticClass.class ? new StaticClassLinker() :
                DynamicMethod.class.isAssignableFrom(clazz) ? new DynamicMethodLinker() :
                new BeanLinker(clazz);
        }
    };

    /**
     * Creates a new POJO linker.
     */
    public BeansLinker() {
    }

    /**
     * Returns a bean linker for a particular single class. Useful when you need to override or extend the behavior of
     * linking for some classes in your language runtime's linker, but still want to delegate to the default behavior in
     * some cases.
     * @param clazz the class
     * @return a bean linker for that class
     */
    public static TypeBasedGuardingDynamicLinker getLinkerForClass(final Class<?> clazz) {
        return linkers.get(clazz);
    }

    /**
     * Returns a collection of names of all readable instance properties of a class.
     * @param clazz the class
     * @return a collection of names of all readable instance properties of a class.
     */
    public static Collection<String> getReadableInstancePropertyNames(final Class<?> clazz) {
        final TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
        if(linker instanceof BeanLinker) {
            return ((BeanLinker)linker).getReadablePropertyNames();
        }
        return Collections.emptySet();
    }

    /**
     * Returns a collection of names of all writable instance properties of a class.
     * @param clazz the class
     * @return a collection of names of all writable instance properties of a class.
     */
    public static Collection<String> getWritableInstancePropertyNames(final Class<?> clazz) {
        final TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
        if(linker instanceof BeanLinker) {
            return ((BeanLinker)linker).getWritablePropertyNames();
        }
        return Collections.emptySet();
    }

    /**
     * Returns a collection of names of all instance methods of a class.
     * @param clazz the class
     * @return a collection of names of all instance methods of a class.
     */
    public static Collection<String> getInstanceMethodNames(final Class<?> clazz) {
        final TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
        if(linker instanceof BeanLinker) {
            return ((BeanLinker)linker).getMethodNames();
        }
        return Collections.emptySet();
    }

    /**
     * Returns a collection of names of all readable static properties of a class.
     * @param clazz the class
     * @return a collection of names of all readable static properties of a class.
     */
    public static Collection<String> getReadableStaticPropertyNames(final Class<?> clazz) {
        return StaticClassLinker.getReadableStaticPropertyNames(clazz);
    }

    /**
     * Returns a collection of names of all writable static properties of a class.
     * @param clazz the class
     * @return a collection of names of all writable static properties of a class.
     */
    public static Collection<String> getWritableStaticPropertyNames(final Class<?> clazz) {
        return StaticClassLinker.getWritableStaticPropertyNames(clazz);
    }

    /**
     * Returns a collection of names of all static methods of a class.
     * @param clazz the class
     * @return a collection of names of all static methods of a class.
     */
    public static Collection<String> getStaticMethodNames(final Class<?> clazz) {
        return StaticClassLinker.getStaticMethodNames(clazz);
    }

    @Override
    public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices)
            throws Exception {
        final CallSiteDescriptor callSiteDescriptor = request.getCallSiteDescriptor();
        final int l = callSiteDescriptor.getNameTokenCount();
        // All names conforming to the dynalang MOP should have at least two tokens, the first one being "dyn"
        if(l < 2 || "dyn" != callSiteDescriptor.getNameToken(CallSiteDescriptor.SCHEME)) {
            return null;
        }

        final Object receiver = request.getReceiver();
        if(receiver == null) {
            // Can't operate on null
            return null;
        }
        return getLinkerForClass(receiver.getClass()).getGuardedInvocation(request, linkerServices);
    }
} public interface GuardingDynamicLinker {
    /**
     * Creates a guarded invocation appropriate for a particular invocation with the specified arguments at a call site.
     *
     * @param linkRequest the object describing the request for linking a particular invocation
     * @param linkerServices linker services
     * @return a guarded invocation with a method handle suitable for the arguments, as well as a guard condition that
     * if fails should trigger relinking. Must return null if it can't resolve the invocation. If the returned
     * invocation is unconditional (which is actually quite rare), the guard in the return value can be null. The
     * invocation can also have a switch point for asynchronous invalidation of the linkage, as well as a
     * {@link Throwable} subclass that describes an expected exception condition that also triggers relinking (often it
     * is faster to rely on an infrequent but expected {@link ClassCastException} than on an always evaluated
     * {@code instanceof} guard). If the linker does not recognize any native language runtime contexts in arguments, or
     * does recognize its own, but receives a call site descriptor without its recognized context in the arguments, it
     * should invoke {@link LinkRequest#withoutRuntimeContext()} and link for that. While the linker must produce an
     * invocation with parameter types matching those in the call site descriptor of the link request, it should not try
     * to match the return type expected at the call site except when it can do it with only the conversions that lose
     * neither precision nor magnitude, see {@link LinkerServices#asTypeLosslessReturn(java.lang.invoke.MethodHandle,
     * java.lang.invoke.MethodType)}.
     * @throws Exception if the operation fails for whatever reason
     */
    public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, LinkerServices linkerServices)
            throws Exception;
} public interface GuardingTypeConverterFactory {
    /**
     * Returns a guarded type conversion that receives an Object of the specified source type and returns an Object
     * converted to the specified target type. The type of the invocation is targetType(sourceType), while the type of
     * the guard is boolean(sourceType). Note that this will never be invoked for type conversions allowed by the JLS
     * 5.3 "Method Invocation Conversion", see {@link TypeUtilities#isMethodInvocationConvertible(Class, Class)} for
     * details. An implementation can assume it is never requested to produce a converter for these conversions.
     *
     * @param sourceType source type
     * @param targetType the target type.
     * @return a guarded type conversion that contains a guarded invocation that can take an object (if it passes guard)
     * and return another object that is its representation coerced into the target type. In case the factory is certain
     * it is unable to handle a conversion, it can return null. In case the factory is certain that it can always handle
     * the conversion, it can return an unconditional invocation (one whose guard is null).
     * @throws Exception if there was an error during creation of the converter
     */
    public GuardedTypeConversion convertToType(Class<?> sourceType, Class<?> targetType) throws Exception;
} public interface LinkRequest {
    /**
     * Returns the call site descriptor for the call site being linked.
     *
     * @return the call site descriptor for the call site being linked.
     */
    public CallSiteDescriptor getCallSiteDescriptor();

    /**
     * Returns the call site token for the call site being linked. This token is an opaque object that is guaranteed to
     * have different identity for different call sites, and is also guaranteed to not become weakly reachable before
     * the call site does and to become weakly reachable some time after the call site does. This makes it ideal as a
     * candidate for a key in a weak hash map in which a linker might want to keep per-call site linking state (usually
     * profiling information).
     *
     * @return the call site token for the call site being linked.
     */
    public Object getCallSiteToken();

    /**
     * Returns the arguments for the invocation being linked. The returned array is a clone; modifications to it won't
     * affect the arguments in this request.
     *
     * @return the arguments for the invocation being linked.
     */
    public Object[] getArguments();

    /**
     * Returns the 0th argument for the invocation being linked; this is typically the receiver object.
     *
     * @return the receiver object.
     */
    public Object getReceiver();

    /**
     * Returns the number of times this callsite has been linked/relinked. This can be useful if you want to
     * change e.g. exception based relinking to guard based relinking. It's probably not a good idea to keep,
     * for example, expensive exception throwing relinkage based on failed type checks/ClassCastException in
     * a nested callsite tree where the exception is thrown repeatedly for the common case. There it would be
     * much more performant to use exact type guards instead.
     * 
     * @return link count for call site
     */
    public int getLinkCount();
    
    /**
     * Returns true if the call site is considered unstable, that is, it has been relinked more times than was
     * specified in {@link DynamicLinkerFactory#setUnstableRelinkThreshold(int)}. Linkers should use this as a
     * hint to prefer producing linkage that is more stable (its guard fails less frequently), even if that assumption
     * causes a less effective version of an operation to be linked. This is just a hint, of course, and linkers are
     * free to ignore this property.
     * @return true if the call site is considered unstable.
     */
    public boolean isCallSiteUnstable();

    /**
     * Returns a request stripped from runtime context arguments. Some language runtimes will include runtime-specific
     * context parameters in their call sites as few arguments between 0th argument "this" and the normal arguments. If
     * a linker does not recognize such contexts at all, or does not recognize the call site as one with its own
     * context, it can ask for the alternative link request with context parameters and arguments removed, and link
     * against it instead.
     *
     * @return the context-stripped request. If the link request does not have any language runtime specific context
     * parameters, the same link request is returned.
     */
    public LinkRequest withoutRuntimeContext();

    /**
     * Returns a request identical to this one with call site descriptor and arguments replaced with the ones specified.
     *
     * @param callSiteDescriptor the new call site descriptor
     * @param arguments the new arguments
     * @return a new request identical to this one, except with the call site descriptor and arguments replaced with the
     * specified ones.
     */
    public LinkRequest replaceArguments(CallSiteDescriptor callSiteDescriptor, Object[] arguments);
} public interface LinkerServices {
    /**
     * Similar to {@link MethodHandle#asType(MethodType)} except it also hooks in method handles produced by
     * {@link GuardingTypeConverterFactory} implementations, providing for language-specific type coercing of
     * parameters. It will apply {@link MethodHandle#asType(MethodType)} for all primitive-to-primitive,
     * wrapper-to-primitive, primitive-to-wrapper conversions as well as for all upcasts. For all other conversions,
     * it'll insert {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with composite filters
     * provided by {@link GuardingTypeConverterFactory} implementations.
     *
     * @param handle target method handle
     * @param fromType the types of source arguments
     * @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)},
     * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)}, and
     * {@link MethodHandles#filterReturnValue(MethodHandle, MethodHandle)} with
     * {@link GuardingTypeConverterFactory}-produced type converters as filters.
     */
    public MethodHandle asType(MethodHandle handle, MethodType fromType);

    /**
     * Similar to {@link #asType(MethodHandle, MethodType)} except it only converts the return type of the method handle
     * when it can be done using a conversion that loses neither precision nor magnitude, otherwise it leaves it
     * unchanged. The idea is that other conversions should not be performed by individual linkers, but instead the
     * {@link DynamicLinkerFactory#setPrelinkFilter(org.dynalang.dynalink.GuardedInvocationFilter) pre-link filter of
     * the dynamic linker} should implement the strategy of dealing with potentially lossy return type conversions in a
     * manner specific to the language runtime.
     *
     * @param handle target method handle
     * @param fromType the types of source arguments
     * @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)}, and
     * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with
     * {@link GuardingTypeConverterFactory}-produced type converters as filters.
     */
    public MethodHandle asTypeLosslessReturn(MethodHandle handle, MethodType fromType);

    /**
     * Given a source and target type, returns a method handle that converts between them. Never returns null; in worst
     * case it will return an identity conversion (that might fail for some values at runtime). You rarely need to use
     * this method directly; you should mostly rely on {@link #asType(MethodHandle, MethodType)} instead. You really
     * only need this method if you have a piece of your program that is written in Java, and you need to reuse existing
     * type conversion machinery in a non-invokedynamic context.
     * @param sourceType the type to convert from
     * @param targetType the type to convert to
     * @return a method handle performing the conversion.
     */
    public MethodHandle getTypeConverter(Class<?> sourceType, Class<?> targetType);

    /**
     * Returns true if there might exist a conversion between the requested types (either an automatic JVM conversion,
     * or one provided by any available {@link GuardingTypeConverterFactory}), or false if there definitely does not
     * exist a conversion between the requested types. Note that returning true does not guarantee that the conversion
     * will succeed at runtime (notably, if the "from" or "to" types are sufficiently generic), but returning false
     * guarantees that it would fail.
     *
     * @param from the source type for the conversion
     * @param to the target type for the conversion
     * @return true if there can be a conversion, false if there can not.
     */
    public boolean canConvert(Class<?> from, Class<?> to);

    /**
     * Creates a guarded invocation using the {@link DynamicLinker} that exposes this linker services interface. Linkers
     * can typically use them to delegate linking of wrapped objects.
     *
     * @param linkRequest a request for linking the invocation
     * @return a guarded invocation linked by the top-level linker (or any of its delegates). Can be null if no
     * available linker is able to link the invocation.
     * @throws Exception in case the top-level linker throws an exception
     */
    public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest) throws Exception;

    /**
     * Determines which of the two type conversions from a source type to the two target types is preferred. This is
     * used for dynamic overloaded method resolution. If the source type is convertible to exactly one target type with
     * a method invocation conversion, it is chosen, otherwise available {@link ConversionComparator}s are consulted.
     * @param sourceType the source type.
     * @param targetType1 one potential target type
     * @param targetType2 another potential target type.
     * @return one of Comparison constants that establish which - if any - of the target types is preferable for the
     * conversion.
     */
    public Comparison compareConversion(Class<?> sourceType, Class<?> targetType1, Class<?> targetType2);

    /**
     * Modifies the method handle so that any parameters that can receive potentially internal language runtime objects
     * will have a filter added on them to prevent them from escaping, potentially by wrapping them.
     * It can also potentially add an unwrapping filter to the return value.
     * @param target the target method handle
     * @return a method handle with parameters and/or return type potentially filtered for wrapping and unwrapping.
     */
    public MethodHandle filterInternalObjects(final MethodHandle target);

    /**
     * If we could just use Java 8 constructs, then {@code asTypeSafeReturn} would be a method with default
     * implementation. Since we can't do that, we extract common default implementations into this static class.
     */
    public static class Implementation {
        /**
         * Default implementation for {@link LinkerServices#asTypeLosslessReturn(MethodHandle, MethodType)}.
         * @param linkerServices the linker services that delegates to this implementation
         * @param handle the passed handle
         * @param fromType the passed type
         * @return the converted method handle, as per the {@code asTypeSafeReturn} semantics.
         */
        public static MethodHandle asTypeLosslessReturn(final LinkerServices linkerServices, final MethodHandle handle, final MethodType fromType) {
            final Class<?> handleReturnType = handle.type().returnType();
            return linkerServices.asType(handle, TypeUtilities.isConvertibleWithoutLoss(handleReturnType, fromType.returnType()) ?
                    fromType : fromType.changeReturnType(handleReturnType));
        }
    }
} public interface MethodHandleTransformer {
    /**
     * Transforms a method handle.
     * @param target the method handle being transformed.
     * @return transformed method handle.
     */
    public MethodHandle transform(final MethodHandle target);
} public interface MethodTypeConversionStrategy {
    /**
     * Converts a method handle to a new type.
     * @param target target method handle
     * @param newType new type
     * @return target converted to the new type.
     */
    public MethodHandle asType(final MethodHandle target, final MethodType newType);
} public class AutoDiscovery {

    private AutoDiscovery() {
    }

    /**
     * Discovers all guarding dynamic linkers listed in JAR files of the context class loader of the current thread.
     *
     * @return a list of available linkers. Can be zero-length list but not null.
     */
    public static List<GuardingDynamicLinker> loadLinkers() {
        return getLinkers(ServiceLoader.load(GuardingDynamicLinker.class));
    }

    /**
     * Discovers all guarding dynamic linkers listed in JAR files of the specified class loader.
     *
     * @param cl the class loader to use
     * @return a list of guarding dynamic linkers available through the specified class loader. Can be zero-length list
     * but not null.
     */
    public static List<GuardingDynamicLinker> loadLinkers(final ClassLoader cl) {
        return getLinkers(ServiceLoader.load(GuardingDynamicLinker.class, cl));
    }

    /**
     * I can't believe there's no Collections API for making a List given an Iterator...
     */
    private static <T> List<T> getLinkers(final ServiceLoader<T> loader) {
        final List<T> list = new LinkedList<>();
        for(final T linker: loader) {
            list.add(linker);
        }
        return list;
    }
} public class BottomGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker {

    /**
     * The sole instance of this stateless linker.
     */
    public static final BottomGuardingDynamicLinker INSTANCE = new BottomGuardingDynamicLinker();

    private BottomGuardingDynamicLinker() {
    }

    @Override
    public boolean canLinkType(final Class<?> type) {
        return false;
    }

    @Override
    public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) {
        return null;
    }
} public class ClassLoaderGetterContextProvider {
    /**
     * Canonical instance of {@link AccessControlContext} with a single {@link RuntimePermission} for
     * {@code "getClassLoader"} permission.
     */
    public static final AccessControlContext GET_CLASS_LOADER_CONTEXT;
    static {
        final Permissions perms = new Permissions();
        perms.add(new RuntimePermission("getClassLoader"));
        GET_CLASS_LOADER_CONTEXT = new AccessControlContext(
                new ProtectionDomain[] { new ProtectionDomain(null, perms) });
    }
} public class CompositeGuardingDynamicLinker implements GuardingDynamicLinker, Serializable {

    private static final long serialVersionUID = 1L;

    private final GuardingDynamicLinker[] linkers;

    /**
     * Creates a new composite linker.
     *
     * @param linkers a list of component linkers.
     */
    public CompositeGuardingDynamicLinker(final Iterable<? extends GuardingDynamicLinker> linkers) {
        final List<GuardingDynamicLinker> l = new LinkedList<>();
        for(final GuardingDynamicLinker linker: linkers) {
            l.add(linker);
        }
        this.linkers = l.toArray(new GuardingDynamicLinker[l.size()]);
    }

    @Override
    public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices)
            throws Exception {
        for(final GuardingDynamicLinker linker: linkers) {
            final GuardedInvocation invocation = linker.getGuardedInvocation(linkRequest, linkerServices);
            if(invocation != null) {
                return invocation;
            }
        }
        return null;
    }
} public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker, Serializable {
    private static final long serialVersionUID = 1L;

    // Using a separate static class instance so there's no strong reference from the class value back to the composite
    // linker.
    private static class ClassToLinker extends ClassValue<List<TypeBasedGuardingDynamicLinker>> {
        private static final List<TypeBasedGuardingDynamicLinker> NO_LINKER = Collections.emptyList();
        private final TypeBasedGuardingDynamicLinker[] linkers;
        private final List<TypeBasedGuardingDynamicLinker>[] singletonLinkers;

        @SuppressWarnings("unchecked")
        ClassToLinker(final TypeBasedGuardingDynamicLinker[] linkers) {
            this.linkers = linkers;
            singletonLinkers = new List[linkers.length];
            for(int i = 0; i < linkers.length; ++i) {
                singletonLinkers[i] = Collections.singletonList(linkers[i]);
            }
        }

        @Override
        protected List<TypeBasedGuardingDynamicLinker> computeValue(final Class<?> clazz) {
            List<TypeBasedGuardingDynamicLinker> list = NO_LINKER;
            for(int i = 0; i < linkers.length; ++i) {
                final TypeBasedGuardingDynamicLinker linker = linkers[i];
                if(linker.canLinkType(clazz)) {
                    switch(list.size()) {
                        case 0: {
                            list = singletonLinkers[i];
                            break;
                        }
                        case 1: {
                            list = new LinkedList<>(list);
                        }
                        //$FALL-THROUGH$
                        default: {
                            list.add(linker);
                        }
                    }
                }
            }
            return list;
        }
    }

    private final ClassValue<List<TypeBasedGuardingDynamicLinker>> classToLinker;

    /**
     * Creates a new composite type-based linker.
     *
     * @param linkers the component linkers
     */
    public CompositeTypeBasedGuardingDynamicLinker(final Iterable<? extends TypeBasedGuardingDynamicLinker> linkers) {
        final List<TypeBasedGuardingDynamicLinker> l = new LinkedList<>();
        for(final TypeBasedGuardingDynamicLinker linker: linkers) {
            l.add(linker);
        }
        this.classToLinker = new ClassToLinker(l.toArray(new TypeBasedGuardingDynamicLinker[l.size()]));
    }

    @Override
    public boolean canLinkType(final Class<?> type) {
        return !classToLinker.get(type).isEmpty();
    }

    @Override
    public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices)
            throws Exception {
        final Object obj = linkRequest.getReceiver();
        if(obj == null) {
            return null;
        }
        for(final TypeBasedGuardingDynamicLinker linker: classToLinker.get(obj.getClass())) {
            final GuardedInvocation invocation = linker.getGuardedInvocation(linkRequest, linkerServices);
            if(invocation != null) {
                return invocation;
            }
        }
        return null;
    }

    /**
     * Optimizes a list of type-based linkers. If a group of adjacent linkers in the list all implement
     * {@link TypeBasedGuardingDynamicLinker}, they will be replaced with a single instance of
     * {@link CompositeTypeBasedGuardingDynamicLinker} that contains them.
     *
     * @param linkers the list of linkers to optimize
     * @return the optimized list
     */
    public static List<GuardingDynamicLinker> optimize(final Iterable<? extends GuardingDynamicLinker> linkers) {
        final List<GuardingDynamicLinker> llinkers = new LinkedList<>();
        final List<TypeBasedGuardingDynamicLinker> tblinkers = new LinkedList<>();
        for(final GuardingDynamicLinker linker: linkers) {
            if(linker instanceof TypeBasedGuardingDynamicLinker) {
                tblinkers.add((TypeBasedGuardingDynamicLinker)linker);
            } else {
                addTypeBased(llinkers, tblinkers);
                llinkers.add(linker);
            }
        }
        addTypeBased(llinkers, tblinkers);
        return llinkers;
    }

    private static void addTypeBased(final List<GuardingDynamicLinker> llinkers,
            final List<TypeBasedGuardingDynamicLinker> tblinkers) {
        switch(tblinkers.size()) {
            case 0: {
                break;
            }
            case 1: {
                llinkers.addAll(tblinkers);
                tblinkers.clear();
                break;
            }
            default: {
                llinkers.add(new CompositeTypeBasedGuardingDynamicLinker(tblinkers));
                tblinkers.clear();
                break;
            }
        }
    }
} public class DefaultPrelinkFilter implements GuardedInvocationFilter {
    @Override
    public GuardedInvocation filter(final GuardedInvocation inv, final LinkRequest request, final LinkerServices linkerServices) {
        return inv.asType(linkerServices, request.getCallSiteDescriptor().getMethodType());
    }
} public class LinkerServicesImpl implements LinkerServices {

    private static final RuntimePermission GET_CURRENT_LINK_REQUEST = new RuntimePermission("dynalink.getCurrentLinkRequest");
    private static final ThreadLocal<LinkRequest> threadLinkRequest = new ThreadLocal<>();

    private final TypeConverterFactory typeConverterFactory;
    private final GuardingDynamicLinker topLevelLinker;
    private final MethodHandleTransformer internalObjectsFilter;

    /**
     * Creates a new linker services object.
     *
     * @param typeConverterFactory the type converter factory exposed by the services.
     * @param topLevelLinker the top level linker used by the services.
     * @param internalObjectsFilter a method handle transformer that is supposed to act as the implementation of this
     * services' {@link #filterInternalObjects(java.lang.invoke.MethodHandle)} method.
     */
    public LinkerServicesImpl(final TypeConverterFactory typeConverterFactory,
            final GuardingDynamicLinker topLevelLinker, final MethodHandleTransformer internalObjectsFilter) {
        this.typeConverterFactory = typeConverterFactory;
        this.topLevelLinker = topLevelLinker;
        this.internalObjectsFilter = internalObjectsFilter;
    }

    @Override
    public boolean canConvert(final Class<?> from, final Class<?> to) {
        return typeConverterFactory.canConvert(from, to);
    }

    @Override
    public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
        return typeConverterFactory.asType(handle, fromType);
    }

    @Override
    public MethodHandle asTypeLosslessReturn(final MethodHandle handle, final MethodType fromType) {
        return Implementation.asTypeLosslessReturn(this, handle, fromType);
    }

    @Override
    public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
        return typeConverterFactory.getTypeConverter(sourceType, targetType);
    }

    @Override
    public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
        return typeConverterFactory.compareConversion(sourceType, targetType1, targetType2);
    }

    @Override
    public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest) throws Exception {
        final LinkRequest prevLinkRequest = threadLinkRequest.get();
        threadLinkRequest.set(linkRequest);
        try {
            return topLevelLinker.getGuardedInvocation(linkRequest, this);
        } finally {
            threadLinkRequest.set(prevLinkRequest);
        }
    }

    @Override
    public MethodHandle filterInternalObjects(final MethodHandle target) {
        return internalObjectsFilter != null ? internalObjectsFilter.transform(target) : target;
    }

    /**
     * Returns the currently processed link request, or null if the method is invoked outside of the linking process.
     * @return the currently processed link request, or null.
     * @throws SecurityException if the calling code doesn't have the {@code "dynalink.getCurrentLinkRequest"} runtime
     * permission.
     */
    public static LinkRequest getCurrentLinkRequest() {
        final SecurityManager sm = System.getSecurityManager();
        if(sm != null) {
            sm.checkPermission(GET_CURRENT_LINK_REQUEST);
        }
        return threadLinkRequest.get();
    }
} public class TypeConverterFactory {

    private final GuardingTypeConverterFactory[] factories;
    private final ConversionComparator[] comparators;
    private final MethodTypeConversionStrategy autoConversionStrategy;

    private final ClassValue<ClassMap<MethodHandle>> converterMap = new ClassValue<ClassMap<MethodHandle>>() {
        @Override
        protected ClassMap<MethodHandle> computeValue(final Class<?> sourceType) {
            return new ClassMap<MethodHandle>(getClassLoader(sourceType)) {
                @Override
                protected MethodHandle computeValue(final Class<?> targetType) {
                    try {
                        return createConverter(sourceType, targetType);
                    } catch (final RuntimeException e) {
                        throw e;
                    } catch (final Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            };
        }
    };

    private final ClassValue<ClassMap<MethodHandle>> converterIdentityMap = new ClassValue<ClassMap<MethodHandle>>() {
        @Override
        protected ClassMap<MethodHandle> computeValue(final Class<?> sourceType) {
            return new ClassMap<MethodHandle>(getClassLoader(sourceType)) {
                @Override
                protected MethodHandle computeValue(final Class<?> targetType) {
                    if(!canAutoConvert(sourceType, targetType)) {
                        final MethodHandle converter = getCacheableTypeConverter(sourceType, targetType);
                        if(converter != IDENTITY_CONVERSION) {
                            return converter;
                        }
                    }
                    return IDENTITY_CONVERSION.asType(MethodType.methodType(targetType, sourceType));
                }
            };
        }
    };

    private final ClassValue<ClassMap<Boolean>> canConvert = new ClassValue<ClassMap<Boolean>>() {
        @Override
        protected ClassMap<Boolean> computeValue(final Class<?> sourceType) {
            return new ClassMap<Boolean>(getClassLoader(sourceType)) {
                @Override
                protected Boolean computeValue(final Class<?> targetType) {
                    try {
                        return getTypeConverterNull(sourceType, targetType) != null;
                    } catch (final RuntimeException e) {
                        throw e;
                    } catch (final Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            };
        }
    };

    private static final ClassLoader getClassLoader(final Class<?> clazz) {
        return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
            @Override
            public ClassLoader run() {
                return clazz.getClassLoader();
            }
        }, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT);
    }

    /**
     * Creates a new type converter factory from the available {@link GuardingTypeConverterFactory} instances.
     *
     * @param factories the {@link GuardingTypeConverterFactory} instances to compose.
     * @param autoConversionStrategy conversion strategy for automatic type conversions. After
     * {@link #asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)} has applied all custom
     * conversions to a method handle, it still needs to effect
     * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method invocation conversions} that
     * can usually be automatically applied as per
     * {@link java.lang.invoke.MethodHandle#asType(java.lang.invoke.MethodType)}.
     * However, sometimes language runtimes will want to customize even those conversions for their own call
     * sites. A typical example is allowing unboxing of null return values, which is by default prohibited by
     * ordinary {@code MethodHandles.asType}. In this case, a language runtime can install its own custom
     * automatic conversion strategy, that can deal with null values. Note that when the strategy's
     * {@link MethodTypeConversionStrategy#asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)}
     * is invoked, the custom language conversions will already have been applied to the method handle, so by
     * design the difference between the handle's current method type and the desired final type will always
     * only be ones that can be subjected to method invocation conversions. Can be null, in which case no
     * custom strategy is employed.
     */
    public TypeConverterFactory(final Iterable<? extends GuardingTypeConverterFactory> factories,
            final MethodTypeConversionStrategy autoConversionStrategy) {
        final List<GuardingTypeConverterFactory> l = new LinkedList<>();
        final List<ConversionComparator> c = new LinkedList<>();
        for(final GuardingTypeConverterFactory factory: factories) {
            l.add(factory);
            if(factory instanceof ConversionComparator) {
                c.add((ConversionComparator)factory);
            }
        }
        this.factories = l.toArray(new GuardingTypeConverterFactory[l.size()]);
        this.comparators = c.toArray(new ConversionComparator[c.size()]);
        this.autoConversionStrategy = autoConversionStrategy;
    }

    /**
     * Similar to {@link MethodHandle#asType(MethodType)} except it also hooks in method handles produced by
     * {@link GuardingTypeConverterFactory} implementations, providing for language-specific type coercing of
     * parameters. For all conversions that are not a JLS method invocation conversion it'll insert
     * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with composite filters
     * provided by {@link GuardingTypeConverterFactory} implementations. For the remaining JLS method invocation
     * conversions, it will invoke {@link MethodTypeConversionStrategy#asType(MethodHandle, MethodType)} first
     * if an automatic conversion strategy was specified in the
     * {@link #TypeConverterFactory(Iterable, MethodTypeConversionStrategy) constructor}, and finally apply
     * {@link MethodHandle#asType(MethodType)} for any remaining conversions.
     *
     * @param handle target method handle
     * @param fromType the types of source arguments
     * @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)},
     * {@link MethodTypeConversionStrategy#asType(MethodHandle, MethodType)}, and
     * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with
     * {@link GuardingTypeConverterFactory} produced type converters as filters.
     */
    public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
        MethodHandle newHandle = handle;
        final MethodType toType = newHandle.type();
        final int l = toType.parameterCount();
        if(l != fromType.parameterCount()) {
            throw new WrongMethodTypeException("Parameter counts differ: " + handle.type() + " vs. " + fromType);
        }
        int pos = 0;
        final List<MethodHandle> converters = new LinkedList<>();
        for(int i = 0; i < l; ++i) {
            final Class<?> fromParamType = fromType.parameterType(i);
            final Class<?> toParamType = toType.parameterType(i);
            if(canAutoConvert(fromParamType, toParamType)) {
                newHandle = applyConverters(newHandle, pos, converters);
            } else {
                final MethodHandle converter = getTypeConverterNull(fromParamType, toParamType);
                if(converter != null) {
                    if(converters.isEmpty()) {
                        pos = i;
                    }
                    converters.add(converter);
                } else {
                    newHandle = applyConverters(newHandle, pos, converters);
                }
            }
        }
        newHandle = applyConverters(newHandle, pos, converters);

        // Convert return type
        final Class<?> fromRetType = fromType.returnType();
        final Class<?> toRetType = toType.returnType();
        if(fromRetType != Void.TYPE && toRetType != Void.TYPE) {
            if(!canAutoConvert(toRetType, fromRetType)) {
                final MethodHandle converter = getTypeConverterNull(toRetType, fromRetType);
                if(converter != null) {
                    newHandle = MethodHandles.filterReturnValue(newHandle, converter);
                }
            }
        }

        // Give change to automatic conversion strategy, if one is present.
        final MethodHandle autoConvertedHandle =
                autoConversionStrategy != null ? autoConversionStrategy.asType(newHandle, fromType) : newHandle;

        // Do a final asType for any conversions that remain.
        return autoConvertedHandle.asType(fromType);
    }

    private static MethodHandle applyConverters(final MethodHandle handle, final int pos, final List<MethodHandle> converters) {
        if(converters.isEmpty()) {
            return handle;
        }
        final MethodHandle newHandle =
                MethodHandles.filterArguments(handle, pos, converters.toArray(new MethodHandle[converters.size()]));
        converters.clear();
        return newHandle;
    }

    /**
     * Returns true if there might exist a conversion between the requested types (either an automatic JVM conversion,
     * or one provided by any available {@link GuardingTypeConverterFactory}), or false if there definitely does not
     * exist a conversion between the requested types. Note that returning true does not guarantee that the conversion
     * will succeed at runtime (notably, if the "from" or "to" types are sufficiently generic), but returning false
     * guarantees that it would fail.
     *
     * @param from the source type for the conversion
     * @param to the target type for the conversion
     * @return true if there can be a conversion, false if there can not.
     */
    public boolean canConvert(final Class<?> from, final Class<?> to) {
        return canAutoConvert(from, to) || canConvert.get(from).get(to).booleanValue();
    }

    /**
     * Determines which of the two type conversions from a source type to the two target types is preferred. This is
     * used for dynamic overloaded method resolution. If the source type is convertible to exactly one target type with
     * a method invocation conversion, it is chosen, otherwise available {@link ConversionComparator}s are consulted.
     * @param sourceType the source type.
     * @param targetType1 one potential target type
     * @param targetType2 another potential target type.
     * @return one of Comparison constants that establish which - if any - of the target types is preferable for the
     * conversion.
     */
    public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
        for(final ConversionComparator comparator: comparators) {
            final Comparison result = comparator.compareConversion(sourceType, targetType1, targetType2);
            if(result != Comparison.INDETERMINATE) {
                return result;
            }
        }
        if(TypeUtilities.isMethodInvocationConvertible(sourceType, targetType1)) {
            if(!TypeUtilities.isMethodInvocationConvertible(sourceType, targetType2)) {
                return Comparison.TYPE_1_BETTER;
            }
        } else if(TypeUtilities.isMethodInvocationConvertible(sourceType, targetType2)) {
            return Comparison.TYPE_2_BETTER;
        }
        return Comparison.INDETERMINATE;
    }

    /**
     * Determines whether it's safe to perform an automatic conversion between the source and target class.
     *
     * @param fromType convert from this class
     * @param toType convert to this class
     * @return true if it's safe to let MethodHandles.convertArguments() to handle this conversion.
     */
    /*private*/ static boolean canAutoConvert(final Class<?> fromType, final Class<?> toType) {
        return TypeUtilities.isMethodInvocationConvertible(fromType, toType);
    }

    /*private*/ MethodHandle getCacheableTypeConverterNull(final Class<?> sourceType, final Class<?> targetType) {
        final MethodHandle converter = getCacheableTypeConverter(sourceType, targetType);
        return converter == IDENTITY_CONVERSION ? null : converter;
    }

    /*private*/ MethodHandle getTypeConverterNull(final Class<?> sourceType, final Class<?> targetType) {
        try {
            return getCacheableTypeConverterNull(sourceType, targetType);
        } catch(final NotCacheableConverter e) {
            return e.converter;
        }
    }

    /*private*/ MethodHandle getCacheableTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
        return converterMap.get(sourceType).get(targetType);
    }

    /**
     * Given a source and target type, returns a method handle that converts between them. Never returns null; in worst
     * case it will return an identity conversion (that might fail for some values at runtime). You can use this method
     * if you have a piece of your program that is written in Java, and you need to reuse existing type conversion
     * machinery in a non-invokedynamic context.
     * @param sourceType the type to convert from
     * @param targetType the type to convert to
     * @return a method handle performing the conversion.
     */
    public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
        try {
            return converterIdentityMap.get(sourceType).get(targetType);
        } catch(final NotCacheableConverter e) {
            return e.converter;
        }
    }

    /*private*/ MethodHandle createConverter(final Class<?> sourceType, final Class<?> targetType) throws Exception {
        final MethodType type = MethodType.methodType(targetType, sourceType);
        final MethodHandle identity = IDENTITY_CONVERSION.asType(type);
        MethodHandle last = identity;
        boolean cacheable = true;
        for(int i = factories.length; i-- > 0;) {
            final GuardedTypeConversion next = factories[i].convertToType(sourceType, targetType);
            if(next != null) {
                cacheable = cacheable && next.isCacheable();
                final GuardedInvocation conversionInvocation = next.getConversionInvocation();
                conversionInvocation.assertType(type);
                last = conversionInvocation.compose(last);
            }
        }
        if(last == identity) {
            return IDENTITY_CONVERSION;
        }
        if(cacheable) {
            return last;
        }
        throw new NotCacheableConverter(last);
    }

    /*private*/ static final MethodHandle IDENTITY_CONVERSION = MethodHandles.identity(Object.class);

    @SuppressWarnings("serial")
    private static class NotCacheableConverter extends RuntimeException {
        final MethodHandle converter;

        NotCacheableConverter(final MethodHandle converter) {
            super("", null, false, false);
            this.converter = converter;
        }
    }
} public class TypeUtilities {
    static final Class<Object> OBJECT_CLASS = Object.class;

    private TypeUtilities() {
    }

    /**
     * Given two types represented by c1 and c2, returns a type that is their most specific common supertype for
     * purposes of lossless conversions.
     *
     * @param c1 one type
     * @param c2 another type
     * @return their most common superclass or superinterface for purposes of lossless conversions. If they have several
     * unrelated superinterfaces as their most specific common type, or the types themselves are completely
     * unrelated interfaces, {@link java.lang.Object} is returned.
     */
    public static Class<?> getCommonLosslessConversionType(final Class<?> c1, final Class<?> c2) {
        if(c1 == c2) {
            return c1;
        } else if (c1 == void.class || c2 == void.class) {
            return Object.class;
        } else if(isConvertibleWithoutLoss(c2, c1)) {
            return c1;
        } else if(isConvertibleWithoutLoss(c1, c2)) {
            return c2;
        } else if(c1.isPrimitive() && c2.isPrimitive()) {
            if((c1 == byte.class && c2 == char.class) || (c1 == char.class && c2 == byte.class)) {
                // byte + char = int
                return int.class;
            } else if((c1 == short.class && c2 == char.class) || (c1 == char.class && c2 == short.class)) {
                // short + char = int
                return int.class;
            } else if((c1 == int.class && c2 == float.class) || (c1 == float.class && c2 == int.class)) {
                // int + float = double
                return double.class;
            }
        }
        // For all other cases. This will handle long + (float|double) = Number case as well as boolean + anything = Object case too.
        return getMostSpecificCommonTypeUnequalNonprimitives(c1, c2);
    }

    private static Class<?> getMostSpecificCommonTypeUnequalNonprimitives(final Class<?> c1, final Class<?> c2) {
        final Class<?> npc1 = c1.isPrimitive() ? getWrapperType(c1) : c1;
        final Class<?> npc2 = c2.isPrimitive() ? getWrapperType(c2) : c2;
        final Set<Class<?>> a1 = getAssignables(npc1, npc2);
        final Set<Class<?>> a2 = getAssignables(npc2, npc1);
        a1.retainAll(a2);
        if(a1.isEmpty()) {
            // Can happen when at least one of the arguments is an interface,
            // as they don't have Object at the root of their hierarchy.
            return Object.class;
        }
        // Gather maximally specific elements. Yes, there can be more than one
        // thank to interfaces. I.e., if you call this method for String.class
        // and Number.class, you'll have Comparable, Serializable, and Object
        // as maximal elements.
        final List<Class<?>> max = new ArrayList<>();
        outer: for(final Class<?> clazz: a1) {
            for(final Iterator<Class<?>> maxiter = max.iterator(); maxiter.hasNext();) {
                final Class<?> maxClazz = maxiter.next();
                if(isSubtype(maxClazz, clazz)) {
                    // It can't be maximal, if there's already a more specific
                    // maximal than it.
                    continue outer;
                }
                if(isSubtype(clazz, maxClazz)) {
                    // If it's more specific than a currently maximal element,
                    // that currently maximal is no longer a maximal.
                    maxiter.remove();
                }
            }
            // If we get here, no current maximal is more specific than the
            // current class, so it is considered maximal as well
            max.add(clazz);
        }
        if(max.size() > 1) {
            return Object.class;
        }
        return max.get(0);
    }

    private static Set<Class<?>> getAssignables(final Class<?> c1, final Class<?> c2) {
        final Set<Class<?>> s = new HashSet<>();
        collectAssignables(c1, c2, s);
        return s;
    }

    private static void collectAssignables(final Class<?> c1, final Class<?> c2, final Set<Class<?>> s) {
        if(c1.isAssignableFrom(c2)) {
            s.add(c1);
        }
        final Class<?> sc = c1.getSuperclass();
        if(sc != null) {
            collectAssignables(sc, c2, s);
        }
        final Class<?>[] itf = c1.getInterfaces();
        for(int i = 0; i < itf.length; ++i) {
            collectAssignables(itf[i], c2, s);
        }
    }

    private static final Map<Class<?>, Class<?>> WRAPPER_TYPES = createWrapperTypes();
    private static final Map<Class<?>, Class<?>> PRIMITIVE_TYPES = invertMap(WRAPPER_TYPES);
    private static final Map<String, Class<?>> PRIMITIVE_TYPES_BY_NAME = createClassNameMapping(WRAPPER_TYPES.keySet());

    private static Map<Class<?>, Class<?>> createWrapperTypes() {
        final Map<Class<?>, Class<?>> wrapperTypes = new IdentityHashMap<>(8);
        wrapperTypes.put(Boolean.TYPE, Boolean.class);
        wrapperTypes.put(Byte.TYPE, Byte.class);
        wrapperTypes.put(Character.TYPE, Character.class);
        wrapperTypes.put(Short.TYPE, Short.class);
        wrapperTypes.put(Integer.TYPE, Integer.class);
        wrapperTypes.put(Long.TYPE, Long.class);
        wrapperTypes.put(Float.TYPE, Float.class);
        wrapperTypes.put(Double.TYPE, Double.class);
        return Collections.unmodifiableMap(wrapperTypes);
    }

    private static Map<String, Class<?>> createClassNameMapping(final Collection<Class<?>> classes) {
        final Map<String, Class<?>> map = new HashMap<>();
        for(final Class<?> clazz: classes) {
            map.put(clazz.getName(), clazz);
        }
        return map;
    }

    private static <K, V> Map<V, K> invertMap(final Map<K, V> map) {
        final Map<V, K> inverted = new IdentityHashMap<>(map.size());
        for(final Map.Entry<K, V> entry: map.entrySet()) {
            inverted.put(entry.getValue(), entry.getKey());
        }
        return Collections.unmodifiableMap(inverted);
    }

    /**
     * Determines whether one type can be converted to another type using a method invocation conversion, as per JLS 5.3
     * "Method Invocation Conversion". This is basically all conversions allowed by subtyping (see
     * {@link #isSubtype(Class, Class)}) as well as boxing conversion (JLS 5.1.7) optionally followed by widening
     * reference conversion and unboxing conversion (JLS 5.1.8) optionally followed by widening primitive conversion.
     *
     * @param sourceType the type being converted from (call site type for parameter types, method type for return types)
     * @param targetType the parameter type being converted to (method type for parameter types, call site type for return types)
     * @return true if source type is method invocation convertible to target type.
     */
    public static boolean isMethodInvocationConvertible(final Class<?> sourceType, final Class<?> targetType) {
        if(targetType.isAssignableFrom(sourceType)) {
            return true;
        }
        if(sourceType.isPrimitive()) {
            if(targetType.isPrimitive()) {
                return isProperPrimitiveSubtype(sourceType, targetType);
            }
            // Boxing + widening reference conversion
            assert WRAPPER_TYPES.get(sourceType) != null : sourceType.getName();
            return targetType.isAssignableFrom(WRAPPER_TYPES.get(sourceType));
        }
        if(targetType.isPrimitive()) {
            final Class<?> unboxedCallSiteType = PRIMITIVE_TYPES.get(sourceType);
            return unboxedCallSiteType != null
                    && (unboxedCallSiteType == targetType || isProperPrimitiveSubtype(unboxedCallSiteType, targetType));
        }
        return false;
    }

    /**
     * Determines whether a type can be converted to another without losing any precision. As a special case,
     * void is considered convertible only to Object and void, while anything can be converted to void. This
     * is because a target type of void means we don't care about the value, so the conversion is always
     * permissible.
     *
     * @param sourceType the source type
     * @param targetType the target type
     * @return true if lossless conversion is possible
     */
    public static boolean isConvertibleWithoutLoss(final Class<?> sourceType, final Class<?> targetType) {
        if(targetType.isAssignableFrom(sourceType) || targetType == void.class) {
            return true;
        }
        if(sourceType.isPrimitive()) {
            if(sourceType == void.class) {
                // Void should be losslessly representable by Object, either as null or as a custom value that
                // can be set with DynamicLinkerFactory.setAutoConversionStrategy.
                return targetType == Object.class;
            }
            if(targetType.isPrimitive()) {
                return isProperPrimitiveLosslessSubtype(sourceType, targetType);
            }
            // Boxing + widening reference conversion
            assert WRAPPER_TYPES.get(sourceType) != null : sourceType.getName();
            return targetType.isAssignableFrom(WRAPPER_TYPES.get(sourceType));
        }
        // Can't convert from any non-primitive type to any primitive type without data loss because of null.
        // Also, can't convert non-assignable reference types.
        return false;
    }
    /**
     * Determines whether one type can be potentially converted to another type at runtime. Allows a conversion between
     * any subtype and supertype in either direction, and also allows a conversion between any two primitive types, as
     * well as between any primitive type and any reference type that can hold a boxed primitive.
     *
     * @param callSiteType the parameter type at the call site
     * @param methodType the parameter type in the method declaration
     * @return true if callSiteType is potentially convertible to the methodType.
     */
    public static boolean isPotentiallyConvertible(final Class<?> callSiteType, final Class<?> methodType) {
        // Widening or narrowing reference conversion
        if(areAssignable(callSiteType, methodType)) {
            return true;
        }
        if(callSiteType.isPrimitive()) {
            // Allow any conversion among primitives, as well as from any
            // primitive to any type that can receive a boxed primitive.
            // TODO: narrow this a bit, i.e. allow, say, boolean to Character?
            // MethodHandles.convertArguments() allows it, so we might need to
            // too.
            return methodType.isPrimitive() || isAssignableFromBoxedPrimitive(methodType);
        }
        if(methodType.isPrimitive()) {
            // Allow conversion from any reference type that can contain a
            // boxed primitive to any primitive.
            // TODO: narrow this a bit too?
            return isAssignableFromBoxedPrimitive(callSiteType);
        }
        return false;
    }

    /**
     * Returns true if either of the types is assignable from the other.
     * @param c1 one of the types
     * @param c2 another one of the types
     * @return true if either c1 is assignable from c2 or c2 is assignable from c1.
     */
    public static boolean areAssignable(final Class<?> c1, final Class<?> c2) {
        return c1.isAssignableFrom(c2) || c2.isAssignableFrom(c1);
    }

    /**
     * Determines whether one type is a subtype of another type, as per JLS 4.10 "Subtyping". Note: this is not strict
     * or proper subtype, therefore true is also returned for identical types; to be completely precise, it allows
     * identity conversion (JLS 5.1.1), widening primitive conversion (JLS 5.1.2) and widening reference conversion (JLS
     * 5.1.5).
     *
     * @param subType the supposed subtype
     * @param superType the supposed supertype of the subtype
     * @return true if subType can be converted by identity conversion, widening primitive conversion, or widening
     * reference conversion to superType.
     */
    public static boolean isSubtype(final Class<?> subType, final Class<?> superType) {
        // Covers both JLS 4.10.2 "Subtyping among Class and Interface Types"
        // and JLS 4.10.3 "Subtyping among Array Types", as well as primitive
        // type identity.
        if(superType.isAssignableFrom(subType)) {
            return true;
        }
        // JLS 4.10.1 "Subtyping among Primitive Types". Note we don't test for
        // identity, as identical types were taken care of in the
        // isAssignableFrom test. As per 4.10.1, the supertype relation is as
        // follows:
        // double > float
        // float > long
        // long > int
        // int > short
        // int > char
        // short > byte
        if(superType.isPrimitive() && subType.isPrimitive()) {
            return isProperPrimitiveSubtype(subType, superType);
        }
        return false;
    }

    /**
     * Returns true if a supposed primitive subtype is a proper subtype ( meaning, subtype and not identical) of the
     * supposed primitive supertype
     *
     * @param subType the supposed subtype
     * @param superType the supposed supertype
     * @return true if subType is a proper (not identical to) primitive subtype of the superType
     */
    private static boolean isProperPrimitiveSubtype(final Class<?> subType, final Class<?> superType) {
        if(superType == boolean.class || subType == boolean.class) {
            return false;
        }
        if(subType == byte.class) {
            return superType != char.class;
        }
        if(subType == char.class) {
            return superType != short.class && superType != byte.class;
        }
        if(subType == short.class) {
            return superType != char.class && superType != byte.class;
        }
        if(subType == int.class) {
            return superType == long.class || superType == float.class || superType == double.class;
        }
        if(subType == long.class) {
            return superType == float.class || superType == double.class;
        }
        if(subType == float.class) {
            return superType == double.class;
        }
        return false;
    }

    /**
     * Similar to {@link #isProperPrimitiveSubtype(Class, Class)}, except it disallows conversions from int and long to
     * float, and from long to double, as those can lose precision. It also disallows conversion from and to char and
     * anything else (similar to boolean) as char is not meant to be an arithmetic type.
     * @param subType the supposed subtype
     * @param superType the supposed supertype
     * @return true if subType is a proper (not identical to) primitive subtype of the superType that can be represented
     * by the supertype without no precision loss.
     */
    private static boolean isProperPrimitiveLosslessSubtype(final Class<?> subType, final Class<?> superType) {
        if(superType == boolean.class || subType == boolean.class) {
            return false;
        }
        if(superType == char.class || subType == char.class) {
            return false;
        }
        if(subType == byte.class) {
            return true;
        }
        if(subType == short.class) {
            return superType != byte.class;
        }
        if(subType == int.class) {
            return superType == long.class || superType == double.class;
        }
        if(subType == float.class) {
            return superType == double.class;
        }
        return false;
    }

    private static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE_TYPES = createWrapperToPrimitiveTypes();

    private static Map<Class<?>, Class<?>> createWrapperToPrimitiveTypes() {
        final Map<Class<?>, Class<?>> classes = new IdentityHashMap<>();
        classes.put(Void.class, Void.TYPE);
        classes.put(Boolean.class, Boolean.TYPE);
        classes.put(Byte.class, Byte.TYPE);
        classes.put(Character.class, Character.TYPE);
        classes.put(Short.class, Short.TYPE);
        classes.put(Integer.class, Integer.TYPE);
        classes.put(Long.class, Long.TYPE);
        classes.put(Float.class, Float.TYPE);
        classes.put(Double.class, Double.TYPE);
        return classes;
    }

    private static final Set<Class<?>> PRIMITIVE_WRAPPER_TYPES = createPrimitiveWrapperTypes();

    private static Set<Class<?>> createPrimitiveWrapperTypes() {
        final Map<Class<?>, Class<?>> classes = new IdentityHashMap<>();
        addClassHierarchy(classes, Boolean.class);
        addClassHierarchy(classes, Byte.class);
        addClassHierarchy(classes, Character.class);
        addClassHierarchy(classes, Short.class);
        addClassHierarchy(classes, Integer.class);
        addClassHierarchy(classes, Long.class);
        addClassHierarchy(classes, Float.class);
        addClassHierarchy(classes, Double.class);
        return classes.keySet();
    }

    private static void addClassHierarchy(final Map<Class<?>, Class<?>> map, final Class<?> clazz) {
        if(clazz == null) {
            return;
        }
        map.put(clazz, clazz);
        addClassHierarchy(map, clazz.getSuperclass());
        for(final Class<?> itf: clazz.getInterfaces()) {
            addClassHierarchy(map, itf);
        }
    }

    /**
     * Returns true if the class can be assigned from any boxed primitive.
     *
     * @param clazz the class
     * @return true if the class can be assigned from any boxed primitive. Basically, it is true if the class is any
     * primitive wrapper class, or a superclass or superinterface of any primitive wrapper class.
     */
    private static boolean isAssignableFromBoxedPrimitive(final Class<?> clazz) {
        return PRIMITIVE_WRAPPER_TYPES.contains(clazz);
    }

    /**
     * Given a name of a primitive type (except "void"), returns the class representing it. I.e. when invoked with
     * "int", returns {@link Integer#TYPE}.
     * @param name the name of the primitive type
     * @return the class representing the primitive type, or null if the name does not correspond to a primitive type
     * or is "void".
     */
    public static Class<?> getPrimitiveTypeByName(final String name) {
        return PRIMITIVE_TYPES_BY_NAME.get(name);
    }

    /**
     * When passed a class representing a wrapper for a primitive type, returns the class representing the corresponding
     * primitive type. I.e. calling it with {@code Integer.class} will return {@code Integer.TYPE}. If passed a class
     * that is not a wrapper for primitive type, returns null.
     * @param wrapperType the class object representing a wrapper for a primitive type
     * @return the class object representing the primitive type, or null if the passed class is not a primitive wrapper.
     */
    public static Class<?> getPrimitiveType(final Class<?> wrapperType) {
        return WRAPPER_TO_PRIMITIVE_TYPES.get(wrapperType);
    }


    /**
     * When passed a class representing a primitive type, returns the class representing the corresponding
     * wrapper type. I.e. calling it with {@code int.class} will return {@code Integer.class}. If passed a class
     * that is not a primitive type, returns null.
     * @param primitiveType the class object representing a primitive type
     * @return the class object representing the wrapper type, or null if the passed class is not a primitive.
     */
    public static Class<?> getWrapperType(final Class<?> primitiveType) {
        return WRAPPER_TYPES.get(primitiveType);
    }

    /**
     * Returns true if the passed type is a wrapper for a primitive type.
     * @param type the examined type
     * @return true if the passed type is a wrapper for a primitive type.
     */
    public static boolean isWrapperType(final Class<?> type) {
        return PRIMITIVE_TYPES.containsKey(type);
    }
}
import java.lang.invoke.MutableCallSite;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.dynalang.dynalink.beans.BeansLinker;
import org.dynalang.dynalink.linker.GuardingDynamicLinker;
import org.dynalang.dynalink.linker.GuardingTypeConverterFactory;
import org.dynalang.dynalink.linker.LinkRequest;
import org.dynalang.dynalink.linker.LinkerServices;
import org.dynalang.dynalink.linker.MethodHandleTransformer;
import org.dynalang.dynalink.linker.MethodTypeConversionStrategy;
import org.dynalang.dynalink.support.AutoDiscovery;
import org.dynalang.dynalink.support.BottomGuardingDynamicLinker;
import org.dynalang.dynalink.support.ClassLoaderGetterContextProvider;
import org.dynalang.dynalink.support.CompositeGuardingDynamicLinker;
import org.dynalang.dynalink.support.CompositeTypeBasedGuardingDynamicLinker;
import org.dynalang.dynalink.support.DefaultPrelinkFilter;
import org.dynalang.dynalink.support.LinkerServicesImpl;
import org.dynalang.dynalink.support.TypeConverterFactory;
import org.dynalang.dynalink.support.TypeUtilities;
/*
   Copyright 2009-2013 Attila Szegedi

   Licensed under both the Apache License, Version 2.0 (the "Apache License")
   and the BSD License (the "BSD License"), with licensee being free to
   choose either of the two at their discretion.

   You may not use this file except in compliance with either the Apache
   License or the BSD License.

   If you choose to use this file in compliance with the Apache License, the
   following notice applies to you:

       You may obtain a copy of the Apache License at

           http://www.apache.org/licenses/LICENSE-2.0

       Unless required by applicable law or agreed to in writing, software
       distributed under the License is distributed on an "AS IS" BASIS,
       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
       implied. See the License for the specific language governing
       permissions and limitations under the License.

   If you choose to use this file in compliance with the BSD License, the
   following notice applies to you:

       Redistribution and use in source and binary forms, with or without
       modification, are permitted provided that the following conditions are
       met:
       * Redistributions of source code must retain the above copyright
         notice, this list of conditions and the following disclaimer.
       * Redistributions in binary form must reproduce the above copyright
         notice, this list of conditions and the following disclaimer in the
         documentation and/or other materials provided with the distribution.
       * Neither the name of the copyright holder nor the names of
         contributors may be used to endorse or promote products derived from
         this software without specific prior written permission.

       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
       IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
       TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
       BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
       SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
       BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
       WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
       OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.dynalang.dynalink;


/**
 * A factory class for creating {@link DynamicLinker}s. The most usual dynamic linker is a linker that is a composition
 * of all {@link GuardingDynamicLinker}s known and pre-created by the caller as well as any
 * {@link AutoDiscovery automatically discovered} guarding linkers and the standard fallback {@link BeansLinker} and a
 * {@link DefaultPrelinkFilter}. See {@link DynamicLinker} documentation for tips on how to use this class.
 *
 * @author Attila Szegedi
 */
public class DynamicLinkerFactory {
    /**
     * Default value for {@link #setUnstableRelinkThreshold(int) unstable relink threshold}.
     */
    public static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8;

    private boolean classLoaderExplicitlySet = false;
    private ClassLoader classLoader;

    private List<? extends GuardingDynamicLinker> prioritizedLinkers;
    private List<? extends GuardingDynamicLinker> fallbackLinkers;
    private int runtimeContextArgCount = 0;
    private boolean syncOnRelink = false;
    private int unstableRelinkThreshold = DEFAULT_UNSTABLE_RELINK_THRESHOLD;
    private GuardedInvocationFilter prelinkFilter;
    private MethodTypeConversionStrategy autoConversionStrategy;
    private MethodHandleTransformer internalObjectsFilter;

    /**
     * Sets the class loader for automatic discovery of available linkers. If not set explicitly, then the thread
     * context class loader at the time of {@link #createLinker()} invocation will be used.
     *
     * @param classLoader the class loader used for the autodiscovery of available linkers.
     */
    public void setClassLoader(final ClassLoader classLoader) {
        this.classLoader = classLoader;
        classLoaderExplicitlySet = true;
    }

    /**
     * Sets the prioritized linkers. Language runtimes using this framework will usually precreate at least the linker
     * for their own language. These linkers will be consulted first in the resulting dynamic linker, before any
     * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the prioritized
     * linkers, it will be ignored and the explicit prioritized instance will be used.
     *
     * @param prioritizedLinkers the list of prioritized linkers. Null can be passed to indicate no prioritized linkers
     * (this is also the default value).
     */
    public void setPrioritizedLinkers(final List<? extends GuardingDynamicLinker> prioritizedLinkers) {
        this.prioritizedLinkers =
                prioritizedLinkers == null ? null : new ArrayList<>(prioritizedLinkers);
    }

    /**
     * Sets the prioritized linkers. Language runtimes using this framework will usually precreate at least the linker
     * for their own language. These linkers will be consulted first in the resulting dynamic linker, before any
     * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the prioritized
     * linkers, it will be ignored and the explicit prioritized instance will be used.
     *
     * @param prioritizedLinkers a list of prioritized linkers.
     */
    public void setPrioritizedLinkers(final GuardingDynamicLinker... prioritizedLinkers) {
        setPrioritizedLinkers(Arrays.asList(prioritizedLinkers));
    }

    /**
     * Sets a single prioritized linker. Identical to calling {@link #setPrioritizedLinkers(List)} with a single-element
     * list.
     *
     * @param prioritizedLinker the single prioritized linker. Must not be null.
     * @throws IllegalArgumentException if null is passed.
     */
    public void setPrioritizedLinker(final GuardingDynamicLinker prioritizedLinker) {
        if(prioritizedLinker == null) {
            throw new IllegalArgumentException("prioritizedLinker == null");
        }
        this.prioritizedLinkers = Collections.singletonList(prioritizedLinker);
    }

    /**
     * Sets the fallback linkers. These linkers will be consulted last in the resulting composite linker, after any
     * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the fallback
     * linkers, it will be ignored and the explicit fallback instance will be used.
     *
     * @param fallbackLinkers the list of fallback linkers. Can be empty to indicate the caller wishes to set no
     * fallback linkers.
     */
    public void setFallbackLinkers(final List<? extends GuardingDynamicLinker> fallbackLinkers) {
        this.fallbackLinkers = fallbackLinkers == null ? null : new ArrayList<>(fallbackLinkers);
    }

    /**
     * Sets the fallback linkers. These linkers will be consulted last in the resulting composite linker, after any
     * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the fallback
     * linkers, it will be ignored and the explicit fallback instance will be used.
     *
     * @param fallbackLinkers the list of fallback linkers. Can be empty to indicate the caller wishes to set no
     * fallback linkers. If it is left as null, the standard fallback {@link BeansLinker} will be used.
     */
    public void setFallbackLinkers(final GuardingDynamicLinker... fallbackLinkers) {
        setFallbackLinkers(Arrays.asList(fallbackLinkers));
    }

    /**
     * Sets the number of arguments in the call sites that represent the stack context of the language runtime creating
     * the linker. If the language runtime uses no context information passed on stack, then it should be zero
     * (the default value). If it is set to nonzero value, then every dynamic call site emitted by this runtime must
     * have the argument list of the form: {@code (this, contextArg1[, contextArg2[, ...]], normalArgs)}. It is
     * advisable to only pass one context-specific argument, though, of an easily recognizable, runtime specific type
     * encapsulating the runtime thread local state.
     *
     * @param runtimeContextArgCount the number of language runtime context arguments in call sites.
     */
    public void setRuntimeContextArgCount(final int runtimeContextArgCount) {
        if(runtimeContextArgCount < 0) {
            throw new IllegalArgumentException("runtimeContextArgCount < 0");
        }
        this.runtimeContextArgCount = runtimeContextArgCount;
    }

    /**
     * Sets whether the linker created by this factory will invoke {@link MutableCallSite#syncAll(MutableCallSite[])}
     * after a call site is relinked. Defaults to false. You probably want to set it to true if your runtime supports
     * multithreaded execution of dynamically linked code.
     * @param syncOnRelink true for invoking sync on relink, false otherwise.
     */
    public void setSyncOnRelink(final boolean syncOnRelink) {
        this.syncOnRelink = syncOnRelink;
    }

    /**
     * Sets the unstable relink threshold; the number of times a call site is relinked after which it will be
     * considered unstable, and subsequent link requests for it will indicate this.
     * @param unstableRelinkThreshold the new threshold. Must not be less than zero. The value of zero means that
     * call sites will never be considered unstable.
     * @see LinkRequest#isCallSiteUnstable()
     */
    public void setUnstableRelinkThreshold(final int unstableRelinkThreshold) {
        if(unstableRelinkThreshold < 0) {
            throw new IllegalArgumentException("unstableRelinkThreshold < 0");
        }
        this.unstableRelinkThreshold = unstableRelinkThreshold;
    }

    /**
     * Set the pre-link filter. This is a {@link GuardedInvocationFilter} that will get the final chance to modify the
     * guarded invocation after it has been created by a component linker and before the dynamic linker links it into
     * the call site. It is normally used to adapt the return value type of the invocation to the type of the call site.
     * When not set explicitly, {@link DefaultPrelinkFilter} will be used.
     * @param prelinkFilter the pre-link filter for the dynamic linker.
     */
    public void setPrelinkFilter(final GuardedInvocationFilter prelinkFilter) {
        this.prelinkFilter = prelinkFilter;
    }

    /**
     * Sets an object representing the conversion strategy for automatic type conversions. After
     * {@link TypeConverterFactory#asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)} has
     * applied all custom conversions to a method handle, it still needs to effect
     * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method invocation conversions} that
     * can usually be automatically applied as per
     * {@link java.lang.invoke.MethodHandle#asType(java.lang.invoke.MethodType)}.
     * However, sometimes language runtimes will want to customize even those conversions for their own call
     * sites. A typical example is allowing unboxing of null return values, which is by default prohibited by
     * ordinary {@code MethodHandles.asType}. In this case, a language runtime can install its own custom
     * automatic conversion strategy, that can deal with null values. Note that when the strategy's
     * {@link MethodTypeConversionStrategy#asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)}
     * is invoked, the custom language conversions will already have been applied to the method handle, so by
     * design the difference between the handle's current method type and the desired final type will always
     * only be ones that can be subjected to method invocation conversions. The strategy also doesn't need to
     * invoke a final {@code MethodHandle.asType()} as the converter factory will do that as the final step.
     * @param autoConversionStrategy the strategy for applying method invocation conversions for the linker
     * created by this factory.
     */
    public void setAutoConversionStrategy(final MethodTypeConversionStrategy autoConversionStrategy) {
        this.autoConversionStrategy = autoConversionStrategy;
    }

    /**
     * Sets a method handle transformer that is supposed to act as the implementation of this linker factory's linkers'
     * services {@link LinkerServices#filterInternalObjects(java.lang.invoke.MethodHandle)} method.
     * @param internalObjectsFilter a method handle transformer filtering out internal objects, or null.
     */
    public void setInternalObjectsFilter(final MethodHandleTransformer internalObjectsFilter) {
        this.internalObjectsFilter = internalObjectsFilter;
    }

    /**
     * Creates a new dynamic linker consisting of all the prioritized, autodiscovered, and fallback linkers as well as
     * the pre-link filter.
     *
     * @return the new dynamic Linker
     */
    public DynamicLinker createLinker() {
        // Treat nulls appropriately
        if(prioritizedLinkers == null) {
            prioritizedLinkers = Collections.emptyList();
        }
        if(fallbackLinkers == null) {
            fallbackLinkers = Collections.singletonList(new BeansLinker());
        }

        // Gather classes of all precreated (prioritized and fallback) linkers.
        // We'll filter out any discovered linkers of the same class.
        final Set<Class<? extends GuardingDynamicLinker>> knownLinkerClasses =
                new HashSet<>();
        addClasses(knownLinkerClasses, prioritizedLinkers);
        addClasses(knownLinkerClasses, fallbackLinkers);

        final ClassLoader effectiveClassLoader = classLoaderExplicitlySet ? classLoader : getThreadContextClassLoader();
        final List<GuardingDynamicLinker> discovered = AutoDiscovery.loadLinkers(effectiveClassLoader);
        // Now, concatenate ...
        final List<GuardingDynamicLinker> linkers =
                new ArrayList<>(prioritizedLinkers.size() + discovered.size()
                        + fallbackLinkers.size());
        // ... prioritized linkers, ...
        linkers.addAll(prioritizedLinkers);
        // ... filtered discovered linkers, ...
        for(final GuardingDynamicLinker linker: discovered) {
            if(!knownLinkerClasses.contains(linker.getClass())) {
                linkers.add(linker);
            }
        }
        // ... and finally fallback linkers.
        linkers.addAll(fallbackLinkers);
        final List<GuardingDynamicLinker> optimized = CompositeTypeBasedGuardingDynamicLinker.optimize(linkers);
        final GuardingDynamicLinker composite;
        switch(linkers.size()) {
            case 0: {
                composite = BottomGuardingDynamicLinker.INSTANCE;
                break;
            }
            case 1: {
                composite = optimized.get(0);
                break;
            }
            default: {
                composite = new CompositeGuardingDynamicLinker(optimized);
                break;
            }
        }

        final List<GuardingTypeConverterFactory> typeConverters = new LinkedList<>();
        for(final GuardingDynamicLinker linker: linkers) {
            if(linker instanceof GuardingTypeConverterFactory) {
                typeConverters.add((GuardingTypeConverterFactory)linker);
            }
        }

        if(prelinkFilter == null) {
            prelinkFilter = new DefaultPrelinkFilter();
        }

        return new DynamicLinker(new LinkerServicesImpl(new TypeConverterFactory(typeConverters,