private readonly String LambdaClassName;      // Generated name for the generated class "X$$Lambda$1"

        /// <summary>
        /// General meta-factory constructor, supporting both standard cases and
        /// allowing for uncommon options such as serialization or bridging.
        /// </summary>
        /// <param name="caller"> Stacked automatically by VM; represents a lookup context
        ///               with the accessibility privileges of the caller. </param>
        /// <param name="invokedType"> Stacked automatically by VM; the signature of the
        ///                    invoked method, which includes the expected static
        ///                    type of the returned lambda object, and the static
        ///                    types of the captured arguments for the lambda.  In
        ///                    the event that the implementation method is an
        ///                    instance method, the first argument in the invocation
        ///                    signature will correspond to the receiver. </param>
        /// <param name="samMethodName"> Name of the method in the functional interface to
        ///                      which the lambda or method reference is being
        ///                      converted, represented as a String. </param>
        /// <param name="samMethodType"> Type of the method in the functional interface to
        ///                      which the lambda or method reference is being
        ///                      converted, represented as a MethodType. </param>
        /// <param name="implMethod"> The implementation method which should be called (with
        ///                   suitable adaptation of argument types, return types,
        ///                   and adjustment for captured arguments) when methods of
        ///                   the resulting functional interface instance are invoked. </param>
        /// <param name="instantiatedMethodType"> The signature of the primary functional
        ///                               interface method after type variables are
        ///                               substituted with their instantiation from
        ///                               the capture site </param>
        /// <param name="isSerializable"> Should the lambda be made serializable?  If set,
        ///                       either the target type or one of the additional SAM
        ///                       types must extend {@code Serializable}. </param>
        /// <param name="markerInterfaces"> Additional interfaces which the lambda object
        ///                       should implement. </param>
        /// <param name="additionalBridges"> Method types for additional signatures to be
        ///                          bridged to the implementation method </param>
        /// <exception cref="LambdaConversionException"> If any of the meta-factory protocol
        /// invariants are violated </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, MethodType invokedType, String samMethodName, MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType, boolean isSerializable, Class[] markerInterfaces, MethodType[] additionalBridges) throws LambdaConversionException
        public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, MethodType invokedType, String samMethodName, MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType, bool isSerializable, Class[] markerInterfaces, MethodType[] additionalBridges) : base(caller, invokedType, samMethodName, samMethodType, implMethod, instantiatedMethodType, isSerializable, markerInterfaces, additionalBridges)
        {
            ImplMethodClassName   = ImplDefiningClass.Name.Replace('.', '/');
            ImplMethodName        = ImplInfo.Name;
            ImplMethodDesc        = ImplMethodType.ToMethodDescriptorString();
            ImplMethodReturnClass = (ImplKind == MethodHandleInfo.REF_newInvokeSpecial) ? ImplDefiningClass : ImplMethodType.ReturnType();
            ConstructorType       = invokedType.ChangeReturnType(Void.TYPE);
            LambdaClassName       = TargetClass.Name.Replace('.', '/') + "$$Lambda$" + Counter.IncrementAndGet();
            Cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
            int parameterCount = invokedType.ParameterCount();

            if (parameterCount > 0)
            {
                ArgNames = new String[parameterCount];
                ArgDescs = new String[parameterCount];
                for (int i = 0; i < parameterCount; i++)
                {
                    ArgNames[i] = "arg$" + (i + 1);
                    ArgDescs[i] = BytecodeDescriptor.unparse(invokedType.ParameterType(i));
                }
            }
            else
            {
                ArgNames = ArgDescs = EMPTY_STRING_ARRAY;
            }
        }
        internal virtual LambdaForm CollectArgumentsForm(int pos, MethodType collectorType)
        {
            int  collectorArity = collectorType.ParameterCount();
            bool dropResult     = (collectorType.ReturnType() == typeof(void));

            if (collectorArity == 1 && !dropResult)
            {
                return(FilterArgumentForm(pos, basicType(collectorType.ParameterType(0))));
            }
            BasicType[]    newTypes = BasicType.basicTypes(collectorType.ParameterList());
            Transform.Kind kind     = (dropResult ? Transform.Kind.COLLECT_ARGS_TO_VOID : Transform.Kind.COLLECT_ARGS);
            if (dropResult && collectorArity == 0)             // pure side effect
            {
                pos = 1;
            }
            Transform  key  = Transform.Of(kind, pos, collectorArity, BasicType.basicTypesOrd(newTypes));
            LambdaForm form = GetInCache(key);

            if (form != null)
            {
                assert(form.Arity_Renamed == LambdaForm.Arity_Renamed - (dropResult ? 0 : 1) + collectorArity);
                return(form);
            }
            form = MakeArgumentCombinationForm(pos, collectorType, false, dropResult);
            return(PutInCache(key, form));
        }
Beispiel #3
0
        /// <summary>
        /// Create a LF which simply reinvokes a target of the given basic type. </summary>
        internal static LambdaForm MakeReinvokerForm(MethodHandle target, int whichCache, Object constraint, String debugString, bool forceInline, NamedFunction getTargetFn, NamedFunction preActionFn)
        {
            MethodType mtype        = target.Type().BasicType();
            bool       customized   = (whichCache <0 || mtype.ParameterSlotCount()> MethodType.MAX_MH_INVOKER_ARITY);
            bool       hasPreAction = (preActionFn != null);
            LambdaForm form;

            if (!customized)
            {
                form = mtype.Form().CachedLambdaForm(whichCache);
                if (form != null)
                {
                    return(form);
                }
            }
            const int THIS_DMH = 0;
            const int ARG_BASE = 1;
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
            int ARG_LIMIT  = ARG_BASE + mtype.ParameterCount();
            int nameCursor = ARG_LIMIT;
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int PRE_ACTION = hasPreAction ? nameCursor++ : -1;
            int PRE_ACTION = hasPreAction ? nameCursor++: -1;
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int NEXT_MH = customized ? -1 : nameCursor++;
            int NEXT_MH = customized ? -1 : nameCursor++;
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int REINVOKE = nameCursor++;
            int REINVOKE = nameCursor++;

            LambdaForm.Name[] names = LambdaForm.Arguments(nameCursor - ARG_LIMIT, mtype.InvokerType());
            assert(names.Length == nameCursor);
            names[THIS_DMH] = names[THIS_DMH].WithConstraint(constraint);
            Object[] targetArgs;
            if (hasPreAction)
            {
                names[PRE_ACTION] = new LambdaForm.Name(preActionFn, names[THIS_DMH]);
            }
            if (customized)
            {
                targetArgs      = Arrays.CopyOfRange(names, ARG_BASE, ARG_LIMIT, typeof(Object[]));
                names[REINVOKE] = new LambdaForm.Name(target, targetArgs);                 // the invoker is the target itself
            }
            else
            {
                names[NEXT_MH]  = new LambdaForm.Name(getTargetFn, names[THIS_DMH]);
                targetArgs      = Arrays.CopyOfRange(names, THIS_DMH, ARG_LIMIT, typeof(Object[]));
                targetArgs[0]   = names[NEXT_MH];               // overwrite this MH with next MH
                names[REINVOKE] = new LambdaForm.Name(mtype, targetArgs);
            }
            form = new LambdaForm(debugString, ARG_LIMIT, names, forceInline);
            if (!customized)
            {
                form = mtype.Form().SetCachedLambdaForm(whichCache, form);
            }
            return(form);
        }
        private static MethodHandle BindCaller(MethodHandle target, Class hostClass)
        {
            MethodHandle cbmh = MethodHandleImpl.BindCaller(target, hostClass);

            if (target.VarargsCollector)
            {
                MethodType type  = cbmh.Type();
                int        arity = type.ParameterCount();
                return(cbmh.AsVarargsCollector(type.ParameterType(arity - 1)));
            }
            return(cbmh);
        }
        internal virtual LambdaForm FoldArgumentsForm(int foldPos, bool dropResult, MethodType combinerType)
        {
            int combinerArity = combinerType.ParameterCount();

            Transform.Kind kind = (dropResult ? Transform.Kind.FOLD_ARGS_TO_VOID : Transform.Kind.FOLD_ARGS);
            Transform      key  = Transform.Of(kind, foldPos, combinerArity);
            LambdaForm     form = GetInCache(key);

            if (form != null)
            {
                assert(form.Arity_Renamed == LambdaForm.Arity_Renamed - (kind == Transform.Kind.FOLD_ARGS ? 1 : 0));
                return(form);
            }
            form = MakeArgumentCombinationForm(foldPos, combinerType, true, dropResult);
            return(PutInCache(key, form));
        }
        private static LambdaForm MakePreparedLambdaForm(MethodType mtype, int which)
        {
            bool   needsInit = (which == LF_INVSTATIC_INIT);
            bool   doesAlloc = (which == LF_NEWINVSPECIAL);
            String linkerName, lambdaName;

            switch (which)
            {
            case LF_INVVIRTUAL:
                linkerName = "linkToVirtual";
                lambdaName = "DMH.invokeVirtual";
                break;

            case LF_INVSTATIC:
                linkerName = "linkToStatic";
                lambdaName = "DMH.invokeStatic";
                break;

            case LF_INVSTATIC_INIT:
                linkerName = "linkToStatic";
                lambdaName = "DMH.invokeStaticInit";
                break;

            case LF_INVSPECIAL:
                linkerName = "linkToSpecial";
                lambdaName = "DMH.invokeSpecial";
                break;

            case LF_INVINTERFACE:
                linkerName = "linkToInterface";
                lambdaName = "DMH.invokeInterface";
                break;

            case LF_NEWINVSPECIAL:
                linkerName = "linkToSpecial";
                lambdaName = "DMH.newInvokeSpecial";
                break;

            default:
                throw new InternalError("which=" + which);
            }
            MethodType mtypeWithArg = mtype.AppendParameterTypes(typeof(MemberName));

            if (doesAlloc)
            {
                mtypeWithArg = mtypeWithArg.InsertParameterTypes(0, typeof(Object)).ChangeReturnType(typeof(void));                 // <init> returns void -  insert newly allocated obj
            }
            MemberName linker = new MemberName(typeof(MethodHandle), linkerName, mtypeWithArg, REF_invokeStatic);

            try
            {
                linker = IMPL_NAMES.ResolveOrFail(REF_invokeStatic, linker, null, typeof(NoSuchMethodException));
            }
            catch (ReflectiveOperationException ex)
            {
                throw newInternalError(ex);
            }
            const int DMH_THIS = 0;
            const int ARG_BASE = 1;
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
            int ARG_LIMIT  = ARG_BASE + mtype.ParameterCount();
            int nameCursor = ARG_LIMIT;
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int NEW_OBJ = (doesAlloc ? nameCursor++ : -1);
            int NEW_OBJ = (doesAlloc ? nameCursor++: -1);
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int GET_MEMBER = nameCursor++;
            int GET_MEMBER = nameCursor++;
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int LINKER_CALL = nameCursor++;
            int LINKER_CALL = nameCursor++;

            Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.InvokerType());
            assert(names.Length == nameCursor);
            if (doesAlloc)
            {
                // names = { argx,y,z,... new C, init method }
                names[NEW_OBJ]    = new Name(Lazy.NF_allocateInstance, names[DMH_THIS]);
                names[GET_MEMBER] = new Name(Lazy.NF_constructorMethod, names[DMH_THIS]);
            }
            else if (needsInit)
            {
                names[GET_MEMBER] = new Name(Lazy.NF_internalMemberNameEnsureInit, names[DMH_THIS]);
            }
            else
            {
                names[GET_MEMBER] = new Name(Lazy.NF_internalMemberName, names[DMH_THIS]);
            }
            assert(FindDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]);
            Object[] outArgs = Arrays.CopyOfRange(names, ARG_BASE, GET_MEMBER + 1, typeof(Object[]));
            assert(outArgs[outArgs.Length - 1] == names[GET_MEMBER]);             // look, shifted args!
            int result = LAST_RESULT;

            if (doesAlloc)
            {
                assert(outArgs[outArgs.Length - 2] == names[NEW_OBJ]);                 // got to move this one
                System.Array.Copy(outArgs, 0, outArgs, 1, outArgs.Length - 2);
                outArgs[0] = names[NEW_OBJ];
                result     = NEW_OBJ;
            }
            names[LINKER_CALL] = new Name(linker, outArgs);
            lambdaName        += "_" + shortenSignature(basicTypeSignature(mtype));
            LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result);

            // This is a tricky bit of code.  Don't send it through the LF interpreter.
            lform.CompileToBytecode();
            return(lform);
        }
        private LambdaForm MakeArgumentCombinationForm(int pos, MethodType combinerType, bool keepArguments, bool dropResult)
        {
            LambdaFormBuffer buf = Buffer();

            buf.StartEdit();
            int combinerArity = combinerType.ParameterCount();
            int resultArity   = (dropResult ? 0 : 1);

            assert(pos <= MethodType.MAX_JVM_ARITY);
            assert(pos + resultArity + (keepArguments ? combinerArity : 0) <= LambdaForm.Arity_Renamed);
            assert(pos > 0);             // cannot filter the MH arg itself
            assert(combinerType == combinerType.BasicType());
            assert(combinerType.ReturnType() != typeof(void) || dropResult);

            BoundMethodHandle.SpeciesData oldData = OldSpeciesData();
            BoundMethodHandle.SpeciesData newData = NewSpeciesData(L_TYPE);

            // The newly created LF will run with a different BMH.
            // Switch over any pre-existing BMH field references to the new BMH class.
            Name oldBaseAddress = LambdaForm.Parameter(0);             // BMH holding the values

            buf.ReplaceFunctions(oldData.GetterFunctions(), newData.GetterFunctions(), oldBaseAddress);
            Name newBaseAddress = oldBaseAddress.withConstraint(newData);

            buf.RenameParameter(0, newBaseAddress);

            Name getCombiner = new Name(newData.GetterFunction(oldData.FieldCount()), newBaseAddress);

            Object[] combinerArgs = new Object[1 + combinerArity];
            combinerArgs[0] = getCombiner;
            Name[] newParams;
            if (keepArguments)
            {
                newParams = new Name[0];
                System.Array.Copy(LambdaForm.Names, pos + resultArity, combinerArgs, 1, combinerArity);
            }
            else
            {
                newParams = new Name[combinerArity];
                BasicType[] newTypes = basicTypes(combinerType.ParameterList());
                for (int i = 0; i < newTypes.Length; i++)
                {
                    newParams[i] = new Name(pos + i, newTypes[i]);
                }
                System.Array.Copy(newParams, 0, combinerArgs, 1, combinerArity);
            }
            Name callCombiner = new Name(combinerType, combinerArgs);

            // insert the two new expressions
            int exprPos = LambdaForm.Arity();

            buf.InsertExpression(exprPos + 0, getCombiner);
            buf.InsertExpression(exprPos + 1, callCombiner);

            // insert new arguments, if needed
            int argPos = pos + resultArity;             // skip result parameter

            foreach (Name newParam in newParams)
            {
                buf.InsertParameter(argPos++, newParam);
            }
            assert(buf.LastIndexOf(callCombiner) == exprPos + 1 + newParams.Length);
            if (!dropResult)
            {
                buf.ReplaceParameterByCopy(pos, exprPos + 1 + newParams.Length);
            }

            return(buf.EndEdit());
        }
        internal virtual LambdaForm CollectArgumentArrayForm(int pos, MethodHandle arrayCollector)
        {
            MethodType collectorType  = arrayCollector.Type();
            int        collectorArity = collectorType.ParameterCount();

            assert(arrayCollector.IntrinsicName() == Intrinsic.NEW_ARRAY);
            Class     arrayType   = collectorType.ReturnType();
            Class     elementType = arrayType.ComponentType;
            BasicType argType     = basicType(elementType);
            int       argTypeKey  = argType.ordinal();

            if (argType.basicTypeClass() != elementType)
            {
                // return null if it requires more metadata (like String[].class)
                if (!elementType.Primitive)
                {
                    return(null);
                }
                argTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal();
            }
            assert(collectorType.ParameterList().Equals(Collections.NCopies(collectorArity, elementType)));
            Transform.Kind kind = Transform.Kind.COLLECT_ARGS_TO_ARRAY;
            Transform      key  = Transform.Of(kind, pos, collectorArity, argTypeKey);
            LambdaForm     form = GetInCache(key);

            if (form != null)
            {
                assert(form.Arity_Renamed == LambdaForm.Arity_Renamed - 1 + collectorArity);
                return(form);
            }
            LambdaFormBuffer buf = Buffer();

            buf.StartEdit();

            assert(pos + 1 <= LambdaForm.Arity_Renamed);
            assert(pos > 0);             // cannot filter the MH arg itself

            Name[] newParams = new Name[collectorArity];
            for (int i = 0; i < collectorArity; i++)
            {
                newParams[i] = new Name(pos + i, argType);
            }
            Name callCombiner = new Name(arrayCollector, (Object[])newParams);              //...

            // insert the new expression
            int exprPos = LambdaForm.Arity();

            buf.InsertExpression(exprPos, callCombiner);

            // insert new arguments
            int argPos = pos + 1;             // skip result parameter

            foreach (Name newParam in newParams)
            {
                buf.InsertParameter(argPos++, newParam);
            }
            assert(buf.LastIndexOf(callCombiner) == exprPos + newParams.Length);
            buf.ReplaceParameterByCopy(pos, exprPos + newParams.Length);

            form = buf.EndEdit();
            return(PutInCache(key, form));
        }
        /// <summary>
        /// Produces an instance of the given single-method interface which redirects
        /// its calls to the given method handle.
        /// <para>
        /// A single-method interface is an interface which declares a uniquely named method.
        /// When determining the uniquely named method of a single-method interface,
        /// the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode})
        /// are disregarded.  For example, <seealso cref="java.util.Comparator"/> is a single-method interface,
        /// even though it re-declares the {@code Object.equals} method.
        /// </para>
        /// <para>
        /// The interface must be public.  No additional access checks are performed.
        /// </para>
        /// <para>
        /// The resulting instance of the required type will respond to
        /// invocation of the type's uniquely named method by calling
        /// the given target on the incoming arguments,
        /// and returning or throwing whatever the target
        /// returns or throws.  The invocation will be as if by
        /// {@code target.invoke}.
        /// The target's type will be checked before the
        /// instance is created, as if by a call to {@code asType},
        /// which may result in a {@code WrongMethodTypeException}.
        /// </para>
        /// <para>
        /// The uniquely named method is allowed to be multiply declared,
        /// with distinct type descriptors.  (E.g., it can be overloaded,
        /// or can possess bridge methods.)  All such declarations are
        /// connected directly to the target method handle.
        /// Argument and return types are adjusted by {@code asType}
        /// for each individual declaration.
        /// </para>
        /// <para>
        /// The wrapper instance will implement the requested interface
        /// and its super-types, but no other single-method interfaces.
        /// This means that the instance will not unexpectedly
        /// pass an {@code instanceof} test for any unrequested type.
        /// <p style="font-size:smaller;">
        /// <em>Implementation Note:</em>
        /// Therefore, each instance must implement a unique single-method interface.
        /// Implementations may not bundle together
        /// multiple single-method interfaces onto single implementation classes
        /// in the style of <seealso cref="java.awt.AWTEventMulticaster"/>.
        /// </para>
        /// <para>
        /// The method handle may throw an <em>undeclared exception</em>,
        /// which means any checked exception (or other checked throwable)
        /// not declared by the requested type's single abstract method.
        /// If this happens, the throwable will be wrapped in an instance of
        /// <seealso cref="java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException"/>
        /// and thrown in that wrapped form.
        /// </para>
        /// <para>
        /// Like <seealso cref="java.lang.Integer#valueOf Integer.valueOf"/>,
        /// {@code asInterfaceInstance} is a factory method whose results are defined
        /// by their behavior.
        /// It is not guaranteed to return a new instance for every call.
        /// </para>
        /// <para>
        /// Because of the possibility of <seealso cref="java.lang.reflect.Method#isBridge bridge methods"/>
        /// and other corner cases, the interface may also have several abstract methods
        /// with the same name but having distinct descriptors (types of returns and parameters).
        /// In this case, all the methods are bound in common to the one given target.
        /// The type check and effective {@code asType} conversion is applied to each
        /// method type descriptor, and all abstract methods are bound to the target in common.
        /// Beyond this type check, no further checks are made to determine that the
        /// abstract methods are related in any way.
        /// </para>
        /// <para>
        /// Future versions of this API may accept additional types,
        /// such as abstract classes with single abstract methods.
        /// Future versions of this API may also equip wrapper instances
        /// with one or more additional public "marker" interfaces.
        /// </para>
        /// <para>
        /// If a security manager is installed, this method is caller sensitive.
        /// During any invocation of the target method handle via the returned wrapper,
        /// the original creator of the wrapper (the caller) will be visible
        /// to context checks requested by the security manager.
        ///
        /// </para>
        /// </summary>
        /// @param <T> the desired type of the wrapper, a single-method interface </param>
        /// <param name="intfc"> a class object representing {@code T} </param>
        /// <param name="target"> the method handle to invoke from the wrapper </param>
        /// <returns> a correctly-typed wrapper for the given target </returns>
        /// <exception cref="NullPointerException"> if either argument is null </exception>
        /// <exception cref="IllegalArgumentException"> if the {@code intfc} is not a
        ///         valid argument to this method </exception>
        /// <exception cref="WrongMethodTypeException"> if the target cannot
        ///         be converted to the type required by the requested interface </exception>
        // Other notes to implementors:
        // <p>
        // No stable mapping is promised between the single-method interface and
        // the implementation class C.  Over time, several implementation
        // classes might be used for the same type.
        // <p>
        // If the implementation is able
        // to prove that a wrapper of the required type
        // has already been created for a given
        // method handle, or for another method handle with the
        // same behavior, the implementation may return that wrapper in place of
        // a new wrapper.
        // <p>
        // This method is designed to apply to common use cases
        // where a single method handle must interoperate with
        // an interface that implements a function-like
        // API.  Additional variations, such as single-abstract-method classes with
        // private constructors, or interfaces with multiple but related
        // entry points, must be covered by hand-written or automatically
        // generated adapter classes.
        //
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @CallerSensitive public static <T> T asInterfaceInstance(final Class intfc, final MethodHandle target)
//JAVA TO C# CONVERTER WARNING: 'final' parameters are not allowed in .NET:
        public static T asInterfaceInstance <T>(Class intfc, MethodHandle target)
        {
            if (!intfc.Interface || !Modifier.IsPublic(intfc.Modifiers))
            {
                throw newIllegalArgumentException("not a public interface", intfc.Name);
            }
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final MethodHandle mh;
            MethodHandle mh;

            if (System.SecurityManager != null)
            {
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final Class caller = sun.reflect.Reflection.getCallerClass();
                Class caller = Reflection.CallerClass;
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final ClassLoader ccl = caller != null ? caller.getClassLoader() : null;
                ClassLoader ccl = caller != null ? caller.ClassLoader : null;
                ReflectUtil.checkProxyPackageAccess(ccl, intfc);
                mh = ccl != null?BindCaller(target, caller) : target;
            }
            else
            {
                mh = target;
            }
            ClassLoader proxyLoader = intfc.ClassLoader;

            if (proxyLoader == null)
            {
                ClassLoader cl = Thread.CurrentThread.ContextClassLoader;                 // avoid use of BCP
                proxyLoader = cl != null ? cl : ClassLoader.SystemClassLoader;
            }
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final Method[] methods = getSingleNameMethods(intfc);
            Method[] methods = GetSingleNameMethods(intfc);
            if (methods == null)
            {
                throw newIllegalArgumentException("not a single-method interface", intfc.Name);
            }
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final MethodHandle[] vaTargets = new MethodHandle[methods.length];
            MethodHandle[] vaTargets = new MethodHandle[methods.Length];
            for (int i = 0; i < methods.Length; i++)
            {
                Method       sm          = methods[i];
                MethodType   smMT        = MethodType.MethodType(sm.ReturnType, sm.ParameterTypes);
                MethodHandle checkTarget = mh.AsType(smMT);                 // make throw WMT
                checkTarget  = checkTarget.AsType(checkTarget.Type().ChangeReturnType(typeof(Object)));
                vaTargets[i] = checkTarget.AsSpreader(typeof(Object[]), smMT.ParameterCount());
            }
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final InvocationHandler ih = new InvocationHandler()
            InvocationHandler ih = new InvocationHandlerAnonymousInnerClassHelper(intfc, target, methods, vaTargets);

//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final Object proxy;
            Object proxy;

            if (System.SecurityManager != null)
            {
                // sun.invoke.WrapperInstance is a restricted interface not accessible
                // by any non-null class loader.
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final ClassLoader loader = proxyLoader;
                ClassLoader loader = proxyLoader;
                proxy = AccessController.doPrivileged(new PrivilegedActionAnonymousInnerClassHelper(intfc, ih, loader));
            }
            else
            {
                proxy = Proxy.NewProxyInstance(proxyLoader, new Class[] { intfc, typeof(WrapperInstance) }, ih);
            }
            return(intfc.Cast(proxy));
        }
        /// <summary>
        /// Check the meta-factory arguments for errors </summary>
        /// <exception cref="LambdaConversionException"> if there are improper conversions </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: void validateMetafactoryArgs() throws LambdaConversionException
        internal virtual void ValidateMetafactoryArgs()
        {
            switch (ImplKind)
            {
            case MethodHandleInfo.REF_invokeInterface:
            case MethodHandleInfo.REF_invokeVirtual:
            case MethodHandleInfo.REF_invokeStatic:
            case MethodHandleInfo.REF_newInvokeSpecial:
            case MethodHandleInfo.REF_invokeSpecial:
                break;

            default:
                throw new LambdaConversionException(string.Format("Unsupported MethodHandle kind: {0}", ImplInfo));
            }

            // Check arity: optional-receiver + captured + SAM == impl
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int implArity = implMethodType.parameterCount();
            int implArity = ImplMethodType.ParameterCount();
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int receiverArity = implIsInstanceMethod ? 1 : 0;
            int receiverArity = ImplIsInstanceMethod ? 1 : 0;
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int capturedArity = invokedType.parameterCount();
            int capturedArity = InvokedType.ParameterCount();
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int samArity = samMethodType.parameterCount();
            int samArity = SamMethodType.ParameterCount();
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int instantiatedArity = instantiatedMethodType.parameterCount();
            int instantiatedArity = InstantiatedMethodType.ParameterCount();

            if (implArity + receiverArity != capturedArity + samArity)
            {
                throw new LambdaConversionException(string.Format("Incorrect number of parameters for {0} method {1}; {2:D} captured parameters, {3:D} functional interface method parameters, {4:D} implementation parameters", ImplIsInstanceMethod ? "instance" : "static", ImplInfo, capturedArity, samArity, implArity));
            }
            if (instantiatedArity != samArity)
            {
                throw new LambdaConversionException(string.Format("Incorrect number of parameters for {0} method {1}; {2:D} instantiated parameters, {3:D} functional interface method parameters", ImplIsInstanceMethod ? "instance" : "static", ImplInfo, instantiatedArity, samArity));
            }
            foreach (MethodType bridgeMT in AdditionalBridges)
            {
                if (bridgeMT.ParameterCount() != samArity)
                {
                    throw new LambdaConversionException(string.Format("Incorrect number of parameters for bridge signature {0}; incompatible with {1}", bridgeMT, SamMethodType));
                }
            }

            // If instance: first captured arg (receiver) must be subtype of class where impl method is defined
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int capturedStart;
            int capturedStart;
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int samStart;
            int samStart;

            if (ImplIsInstanceMethod)
            {
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final Class receiverClass;
                Class receiverClass;

                // implementation is an instance method, adjust for receiver in captured variables / SAM arguments
                if (capturedArity == 0)
                {
                    // receiver is function parameter
                    capturedStart = 0;
                    samStart      = 1;
                    receiverClass = InstantiatedMethodType.ParameterType(0);
                }
                else
                {
                    // receiver is a captured variable
                    capturedStart = 1;
                    samStart      = 0;
                    receiverClass = InvokedType.ParameterType(0);
                }

                // check receiver type
                if (!receiverClass.IsSubclassOf(ImplDefiningClass))
                {
                    throw new LambdaConversionException(string.Format("Invalid receiver type {0}; not a subtype of implementation type {1}", receiverClass, ImplDefiningClass));
                }

                Class implReceiverClass = ImplMethod.Type().ParameterType(0);
                if (implReceiverClass != ImplDefiningClass && !receiverClass.IsSubclassOf(implReceiverClass))
                {
                    throw new LambdaConversionException(string.Format("Invalid receiver type {0}; not a subtype of implementation receiver type {1}", receiverClass, implReceiverClass));
                }
            }
            else
            {
                // no receiver
                capturedStart = 0;
                samStart      = 0;
            }

            // Check for exact match on non-receiver captured arguments
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int implFromCaptured = capturedArity - capturedStart;
            int implFromCaptured = capturedArity - capturedStart;

            for (int i = 0; i < implFromCaptured; i++)
            {
                Class implParamType     = ImplMethodType.ParameterType(i);
                Class capturedParamType = InvokedType.ParameterType(i + capturedStart);
                if (!capturedParamType.Equals(implParamType))
                {
                    throw new LambdaConversionException(string.Format("Type mismatch in captured lambda parameter {0:D}: expecting {1}, found {2}", i, capturedParamType, implParamType));
                }
            }
            // Check for adaptation match on SAM arguments
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final int samOffset = samStart - implFromCaptured;
            int samOffset = samStart - implFromCaptured;

            for (int i = implFromCaptured; i < implArity; i++)
            {
                Class implParamType         = ImplMethodType.ParameterType(i);
                Class instantiatedParamType = InstantiatedMethodType.ParameterType(i + samOffset);
                if (!IsAdaptableTo(instantiatedParamType, implParamType, true))
                {
                    throw new LambdaConversionException(string.Format("Type mismatch for lambda argument {0:D}: {1} is not convertible to {2}", i, instantiatedParamType, implParamType));
                }
            }

            // Adaptation match: return type
            Class expectedType     = InstantiatedMethodType.ReturnType();
            Class actualReturnType = (ImplKind == MethodHandleInfo.REF_newInvokeSpecial) ? ImplDefiningClass : ImplMethodType.ReturnType();
            Class samReturnType    = SamMethodType.ReturnType();

            if (!IsAdaptableToAsReturn(actualReturnType, expectedType))
            {
                throw new LambdaConversionException(string.Format("Type mismatch for lambda return: {0} is not convertible to {1}", actualReturnType, expectedType));
            }
            if (!IsAdaptableToAsReturnStrict(expectedType, samReturnType))
            {
                throw new LambdaConversionException(string.Format("Type mismatch for lambda expected return: {0} is not convertible to {1}", expectedType, samReturnType));
            }
            foreach (MethodType bridgeMT in AdditionalBridges)
            {
                if (!IsAdaptableToAsReturnStrict(expectedType, bridgeMT.ReturnType()))
                {
                    throw new LambdaConversionException(string.Format("Type mismatch for lambda expected return: {0} is not convertible to {1}", expectedType, bridgeMT.ReturnType()));
                }
            }
        }