Ejemplo n.º 1
0
        public static string GenericParameterFullName(GenericParameter genericParameter)
        {
            string name = genericParameter.Name;
            string prefix;

            if (genericParameter.Type == GenericParameterType.Method)
            {
                prefix = "M!" + genericParameter.DeclaringMethod.FullName;
                if (name.StartsWith("!!"))
                {
                    name = CilMethod.AsDefinition(genericParameter.DeclaringMethod)
                           .GenericParameters[genericParameter.Position].Name;
                }
                else if (name.StartsWith("!"))
                {
                    throw new ArgumentException();
                }
            }
            else
            {
                prefix = "T!" + genericParameter.DeclaringType.FullName;
                if (name.StartsWith("!"))
                {
                    name = CilType.AsDefinition(genericParameter.DeclaringType)
                           .GenericParameters[genericParameter.Position].Name;
                }
            }
            return(prefix + "<" + name + ">");
        }
Ejemplo n.º 2
0
            static int GenericParameterPosition(MethodDefinition defMethod,
                                                int parameterIndex,
                                                GenericParameter parameter)
            {
                // when a method has parameters with a generic type, the
                // method name gets a suffix like -generic-$n, where n is
                // the index of the generic parameter in the generic type.
                // e.g., method "int Mth(TY)" in class CA<TX,TY> would be
                // named "Mth-generic-$1" because TY has generic index 1.
                //
                // however when the method overrides a base class method,
                // the n should be the index of the generic parameter in
                // the base type.  e.g., "override int Mth(UZ)" in class
                // CB<UX,UY,UZ> : CA<UY,UZ> translated to "Mth-generic-$2"
                // (as UZ has generic index 2 in CB) would be incorrect,
                // because it breaks the overload/override chain.
                //
                // the code below identifies that CB.Mth is an override
                // of a generic base type method, and that CB.UZ maps to
                // CA.TY in the base Mth(), and prefers the index of CA.TY
                // (i.e. 1) over CB.UZ (i.e. 2), to correctly translate
                // the override as "Mth-generic-$1".

                if (parameter.Type == GenericParameterType.Type &&
                    defMethod != null &&
                    defMethod.IsVirtual && (!defMethod.IsNewSlot))
                {
                    var thisClass = defMethod.DeclaringType;
                    if (thisClass.BaseType is GenericInstanceType baseClass)
                    {
                        var baseGenericArgs = baseClass.GenericArguments;

                        foreach (var baseMethod in CilType.AsDefinition(baseClass).Methods)
                        {
                            if (baseMethod.IsVirtual &&
                                CompareMethods(defMethod, baseMethod))
                            {
                                // we found a base class method that matches
                                // the overriding method, so take the position
                                // (i.e. the generic parameter index within
                                // generic type) from the base method parameter

                                if (baseMethod.Parameters[parameterIndex].ParameterType
                                    .GetElementType() is GenericParameter baseParameter &&
                                    baseGenericArgs.Count > baseParameter.Position &&
                                    baseGenericArgs[baseParameter.Position] == parameter)
                                {
                                    return(baseParameter.Position);
                                }
                            }
                        }
                    }
                }

                // in any other case, for example if this is not an
                // overriding method, or if the base type is not generic,
                // then select the position within the current type

                return(parameter.Position);
            }
Ejemplo n.º 3
0
        public static List <CilInterfaceMethod> CollectAll(TypeDefinition fromType)
        {
            var map = new Dictionary <string, List <CilInterfaceMethod> >();

            Process(fromType, map);

            var newList = new List <CilInterfaceMethod>();

            foreach (var oldList in map.Values)
            {
                newList.AddRange(oldList);
            }
            return(newList);

            void Process(TypeDefinition fromType, Dictionary <string, List <CilInterfaceMethod> > map)
            {
                foreach (var fromMethod in fromType.Methods)
                {
                    if ((fromMethod.IsPublic || fromMethod.HasOverrides) &&
                        !(fromMethod.IsStatic || fromMethod.IsConstructor))
                    {
                        if (fromType.IsInterface && fromMethod.HasBody)
                        {
                            // skip default interface methods, they are not needed
                            // in the context of resolving interface implementations
                            continue;
                        }

                        if (fromMethod.HasCustomAttribute("Discard"))
                        {
                            continue; // skip if decorated with [java.attr.Discard]
                        }
                        var genericMark = CilMain.GenericStack.Mark();
                        var inputMethod = CilMain.GenericStack.EnterMethod(fromMethod);

                        var outputMethod = new CilInterfaceMethod(inputMethod);

                        if (map.TryGetValue(inputMethod.Name, out var list))
                        {
                            bool dup = false;
                            foreach (var oldMethod in list)
                            {
                                if (oldMethod.EqualParameters(outputMethod))
                                {
                                    dup = true;
                                    break;
                                }
                            }
                            if (!dup)
                            {
                                list.Add(outputMethod);
                            }
                        }
                        else
                        {
                            var list2 = new List <CilInterfaceMethod>();
                            list2.Add(outputMethod);
                            map.Add(inputMethod.Name, list2);
                        }

                        CilMain.GenericStack.Release(genericMark);
                    }
                }

                var fromBaseTypeRef = fromType.BaseType;

                if (fromBaseTypeRef != null && !fromType.IsInterface)
                {
                    var fromBaseTypeDef = CilType.AsDefinition(fromBaseTypeRef);

                    var genericMark = CilMain.GenericStack.Mark();
                    CilMain.GenericStack.EnterType(fromBaseTypeDef);

                    Process(fromBaseTypeDef, map);

                    CilMain.GenericStack.Release(genericMark);
                }
            }
        }
Ejemplo n.º 4
0
        public static List <CilInterface> CollectAll(TypeDefinition fromType)
        {
            var list = new List <CilInterface>();

            if (fromType.HasInterfaces)
            {
                Process(fromType, list, true, false);
            }
            return(list);

            void Process(TypeDefinition fromType, List <CilInterface> list,
                         bool directReference, bool markSuperImplements)
            {
                if (fromType.HasInterfaces)
                {
                    foreach (var ifcIterator in fromType.Interfaces)
                    {
                        var fromInterfaceRef = ifcIterator.InterfaceType;
                        var fromInterfaceDef = CilType.AsDefinition(fromInterfaceRef);

                        var genericMark   = CilMain.GenericStack.Mark();
                        var interfaceType = CilMain.GenericStack.EnterType(fromInterfaceRef);

                        var myInterface = interfaceType.HasGenericParameters
                                        ? ImportGenericInterface(interfaceType, list)
                                        : ImportPlainInterface(interfaceType, list);

                        if (!myInterface.Inserted)
                        {
                            // interface not inserted yet, which means it was just created

                            myInterface.Methods = CilInterfaceMethod.CollectAll(fromInterfaceDef);
                            myInterface.LoadType(fromInterfaceRef);
                            myInterface.DirectReference = directReference;
                            myInterface.SuperImplements = markSuperImplements;
                            myInterface.Inserted        = true;

                            list.Add(myInterface);

                            Process(fromInterfaceDef, list, false, markSuperImplements);
                        }
                        else if (markSuperImplements)
                        {
                            // an interface that was found for the initial type,
                            // was also found in a base type, mark it so

                            myInterface.SuperImplements = true;
                        }

                        CilMain.GenericStack.Release(genericMark);
                    }
                }

                //
                // scan base types to detect interfaces implemented there
                //

                var fromBaseTypeRef = fromType.BaseType;

                if (fromBaseTypeRef != null && !fromType.IsInterface)
                {
                    var fromBaseTypeDef = CilType.AsDefinition(fromBaseTypeRef);

                    var genericMark = CilMain.GenericStack.Mark();
                    CilMain.GenericStack.EnterType(fromBaseTypeDef);

                    Process(fromBaseTypeDef, list, false, true);

                    CilMain.GenericStack.Release(genericMark);
                }
            }
        }
Ejemplo n.º 5
0
        public static List <CilInterfaceMethod> CollectAll(TypeDefinition fromType)
        {
            var list = new List <CilInterfaceMethod>();

            Process(fromType, list);
            return(list);

            void Process(TypeDefinition fromType, List <CilInterfaceMethod> list)
            {
                foreach (var fromMethod in fromType.Methods)
                {
                    if ((fromMethod.IsPublic || fromMethod.HasOverrides) &&
                        !(fromMethod.IsStatic || fromMethod.IsConstructor))
                    {
                        if (fromType.IsInterface && fromMethod.HasBody)
                        {
                            // skip default interface methods, they are not needed
                            // in the context of resolving interface implementations
                            continue;
                        }

                        var genericMark = CilMain.GenericStack.Mark();
                        var inputMethod = CilMain.GenericStack.EnterMethod(fromMethod);

                        var outputMethod = new CilInterfaceMethod(inputMethod);

                        bool dup = false;
                        foreach (var oldMethod in list)
                        {
                            if (oldMethod.Method.Name == outputMethod.Method.Name &&
                                oldMethod.EqualParameters(outputMethod))
                            {
                                dup = true;
                                break;
                            }
                        }

                        if (!dup)
                        {
                            list.Add(outputMethod);
                        }

                        CilMain.GenericStack.Release(genericMark);
                    }
                }

                var fromBaseTypeRef = fromType.BaseType;

                if (fromBaseTypeRef != null && !fromType.IsInterface)
                {
                    var fromBaseTypeDef = CilType.AsDefinition(fromBaseTypeRef);

                    var genericMark = CilMain.GenericStack.Mark();
                    CilMain.GenericStack.EnterType(fromBaseTypeDef);

                    Process(fromBaseTypeDef, list);

                    CilMain.GenericStack.Release(genericMark);
                }
            }
        }
Ejemplo n.º 6
0
        public static void BuildOverloadProxy(TypeDefinition fromType, MethodDefinition fromMethod,
                                              CilMethod targetMethod, JavaClass intoClass)
        {
            // create a proxy bridge to forward invocations of a virtual method from
            // the base class, to an implementation in a derived class.  this is needed
            // where the base virtual method has generic parameters or return type,
            // for example:  virtual T SomeMethod(T arg)   will be translated as:
            //      java.lang.Object SomeMethod(-generic-$)(java.lang.Object arg)
            // and in a derived class that specializes T as String:
            //      java.lang.String SomeMethod(java.lang.String arg)
            // so the derived class must also include a proxy bridge method with the
            // same name as in the base class, and forward the call.

            //Console.WriteLine($"CHECK OVERRIDE {fromMethod}");
            int targetMethodCount = targetMethod.Parameters.Count;

            for (;;)
            {
                var baseType = fromType.BaseType;
                if (baseType == null)
                {
                    break;
                }
                fromType = CilType.AsDefinition(baseType);
                if (!baseType.IsGenericInstance)
                {
                    continue;
                }

                foreach (var fromMethod2 in fromType.Methods)
                {
                    //Console.WriteLine($"\tCOMPARE {fromMethod2} {fromMethod2.IsVirtual} {fromMethod2.Name == fromMethod.Name} {targetMethodCount == fromMethod2.Parameters.Count}");
                    if (fromMethod2.IsVirtual && fromMethod2.Name == fromMethod.Name &&
                        targetMethodCount == fromMethod2.Parameters.Count)
                    {
                        if (CilMethod.CompareMethods(fromMethod, fromMethod2))
                        {
                            //Console.WriteLine(">>>>>>>>>>>>> WARNING SAME: " + fromMethod.ToString() + " AND " + fromType);
                            continue;
                        }

                        var genericMark = CilMain.GenericStack.Mark();
                        CilMain.GenericStack.EnterType(baseType);
                        var baseMethod = new CilInterfaceMethod(
                            CilMain.GenericStack.EnterMethod(fromMethod2));
                        CilMain.GenericStack.Release(genericMark);

                        //Console.WriteLine($"\twould compare with {fromMethod2} in class {baseType}");
                        //Console.WriteLine($"\t\t{baseMethod}");

                        if (targetMethodCount != baseMethod.Parameters.Count)
                        {
                            continue;
                        }
                        if (!IsGenericOrEqual(targetMethod.ReturnType, baseMethod.ReturnType))
                        {
                            continue;
                        }
                        bool sameParameters = true;
                        for (int i = 0; i < targetMethodCount; i++)
                        {
                            if (!IsGenericOrEqual(targetMethod.Parameters[i].Type,
                                                  baseMethod.Parameters[i]))
                            {
                                bool equalsAfterUnboxing = (
                                    targetMethod.Parameters[i].Type is BoxedType boxedType &&
                                    boxedType.UnboxedType.Equals(baseMethod.Parameters[i]));

                                if (!equalsAfterUnboxing)
                                {
                                    //Console.WriteLine($"\tMISMATCH {targetMethod.Parameters[i].Type} vs {baseMethod.Parameters[i]}/{baseMethod.Parameters[i].IsGenericParameter}");
                                    sameParameters = false;
                                    break;
                                }
                            }
                        }
                        if (sameParameters)
                        {
                            //Console.WriteLine($"proxying {targetMethod} in class {targetMethod.DeclType}");
                            BuildGenericProxy2(baseMethod, targetMethod,
                                               false, targetMethod.DeclType, intoClass);
                            return;
                        }
                    }
                }
            }
Ejemplo n.º 7
0
        public static void LoadFunction(JavaCode code, Mono.Cecil.Cil.Instruction cilInst)
        {
            if (cilInst.Operand is MethodReference implMethodRef)
            {
                var implMethod = CilMethod.From(implMethodRef);

                var(declType, declMethod, dlgMethodName) = FindInterfaceType(cilInst);

                if (dlgMethodName != null)
                {
                    // if this is an artificial delegate for a functional interface,
                    // then we can't actually instantiate this particular delegate,
                    // because its definition only exists in the DLL created by
                    // DotNetImporter;  see BuildDelegate there.  we fix the Newobj
                    // instruction to instantiate system.FunctionalInterfaceDelegate.

                    cilInst.Next.Operand = DelegateConstructor(cilInst.Next.Operand);

                    declMethod = new JavaMethodRef(dlgMethodName,
                                                   implMethod.ReturnType,
                                                   implMethod.Parameters);
                }

                if (IsPrimitive(declMethod.ReturnType))
                {
                    // primitive return value is translated to java.lang.Object,
                    // because the delegate target may return a generic type that
                    // is specialized for the primitive type in the delegate.
                    // see also MakeInterface and GenerateInvoke
                    declMethod = new JavaMethodRef(
                        declMethod.Name, JavaType.ObjectType, declMethod.Parameters);
                }

                // select the method handle kind for the dynamic call site.
                // for a non-static invocation, we need to push an object reference.

                JavaMethodHandle.HandleKind callKind;
                if (implMethod.DeclType.IsInterface)
                {
                    callKind = JavaMethodHandle.HandleKind.InvokeInterface;
                }
                else
                {
                    callKind = JavaMethodHandle.HandleKind.InvokeVirtual;
                }

                if (cilInst.OpCode.Code == Code.Ldftn)
                {
                    if (implMethod.IsStatic)
                    {
                        callKind = JavaMethodHandle.HandleKind.InvokeStatic;
                    }

                    else
                    {
                        var  implMethodDef = CilMethod.AsDefinition(implMethodRef);
                        bool isVirtual     = implMethodDef.IsVirtual;
                        if (isVirtual && implMethodDef.DeclaringType.IsSealed)
                        {
                            isVirtual = false;
                        }

                        if (!isVirtual)
                        {
                            // non-virtual instance method
                            code.NewInstruction(0x59 /* dup */, null, null);
                            code.StackMap.PushStack(JavaType.ObjectType);
                        }
                        else
                        {
                            // virtual method should only be specified in 'ldvirtftn'
                            throw new Exception("virtual method referenced");
                        }
                    }
                }

                //
                // the method may take generic type parameters, i.e. the System.Type
                // parameters that are added at the end of the parameter list, by
                // CilMethod::ImportGenericParameters.  but when the delegate is
                // called, these parameters will not be pushed.  therefore we do
                // the following when assigning such a method to a delegate:
                //
                // (1) we select a different implementing method, i.e. the bridge
                // method generated by CreateCapturingBridgeMethod (see below),
                // which moves the type arguments to the head of the parameter list.
                // (2) we generate and push the type arguments at this time, via
                // calls to GenericUtil.LoadGeneric.
                // (3) we specify the type arguments as capture parameters of the
                // call site.  (see also JavaCallSite.)  this means the generated
                // proxy will inject these parameters when it calls the bridge
                // method from step (1), and that bridge method will push these
                // parameters at the end of the parameter list, when it invokes
                // the actual target method.
                //

                List <JavaFieldRef> TypeArgs    = null;
                JavaMethodRef       implMethod2 = implMethod;

                var implGenericMethod = implMethod.WithGenericParameters;
                if (implGenericMethod != implMethod)
                {
                    implMethod2 = new JavaMethodRef(
                        "delegate-bridge-" + implGenericMethod.Name,
                        implMethod.ReturnType, implMethod.Parameters);

                    var count1 = implMethod.Parameters.Count;
                    var count2 = implGenericMethod.Parameters.Count;
                    TypeArgs = implGenericMethod.Parameters.GetRange(count1, count2 - count1);

                    var callMethod = CilMain.GenericStack.EnterMethod(implMethodRef);
                    for (int i = count1; i < count2; i++)
                    {
                        GenericUtil.LoadGeneric(implGenericMethod.Parameters[i].Name, code);
                    }
                    for (int i = count1; i < count2; i++)
                    {
                        code.StackMap.PopStack(CilMain.Where);
                    }
                }

                // create a CallSite that implements the method signature
                // declMethod, in the functional interface declType, in order
                // to proxy-invoke the method implMethod.DeclType::implMethod.

                var callSite = new JavaCallSite(declType, declMethod,
                                                implMethod.DeclType, implMethod2,
                                                TypeArgs, callKind);

                code.NewInstruction(0xBA /* invokedynamic */, null, callSite);

                if (callKind != JavaMethodHandle.HandleKind.InvokeStatic)
                {
                    code.StackMap.PopStack(CilMain.Where);
                }

                code.StackMap.PushStack(CilType.From(declType));
            }
            else
            {
                throw new InvalidProgramException();
            }

            //
            // ldftn or ldvirtftn should be followed by newobj, which we can use
            // to identify the delegate, and therefore, the interface
            //

            (JavaType, JavaMethodRef, string) FindInterfaceType(
                Mono.Cecil.Cil.Instruction cilInst)
            {
                cilInst = cilInst.Next;
                if (cilInst != null && cilInst.OpCode.Code == Code.Newobj &&
                    cilInst.Operand is MethodReference constructorRef)
                {
                    var dlgType = CilType.From(constructorRef.DeclaringType);
                    if (dlgType.IsDelegate)
                    {
                        //
                        // check for an artificial delegate, generated to represent a
                        // java functional interface: (BuildDelegate in DotNetImporter)
                        //
                        // delegate type is marked [java.lang.attr.AsInterface],
                        // and is child of an interface type.
                        // interface type is marked [java.lang.attr.RetainName],
                        // and has one method.
                        //

                        var dlgType0 = CilType.AsDefinition(constructorRef.DeclaringType);
                        if (dlgType0.HasCustomAttribute("AsInterface"))
                        {
                            var ifcType0 = dlgType0.DeclaringType;
                            var ifcType  = CilType.From(ifcType0);
                            if (ifcType.IsInterface && ifcType.IsRetainName &&
                                ifcType0.HasMethods && ifcType0.Methods.Count == 1)
                            {
                                return(ifcType, null, ifcType0.Methods[0].Name);
                            }
                        }

                        //
                        // otherwise, a normal delegate, which may be generic, or plain.
                        // interface name is DelegateType$interface.
                        // we look for a method named Invoke.
                        //

                        foreach (var method in dlgType0.Methods)
                        {
                            if (method.Name == "Invoke")
                            {
                                return(InterfaceType(dlgType), CilMethod.From(method), null);
                            }
                        }
                    }
                }
                throw new InvalidProgramException();
            }

            //
            // create a method reference to delegate constructor from baselib:
            // system.MulticastDelegate::.ctor(object, object)
            //

            CilMethod DelegateConstructor(object Operand)
            {
                var baseType = CilType.AsDefinition(((MethodReference)Operand)
                                                    .DeclaringType).BaseType;

                if (baseType.Namespace != "System" || baseType.Name != "MulticastDelegate")
                {
                    throw CilMain.Where.Exception(
                              $"delegate base type is '{baseType.Name}', "
                              + "but expected 'System.MulticastDelegate'");
                }

                return(CilMethod.CreateDelegateConstructor());
            }
        }