コード例 #1
0
        bool ConvertVirtualToStaticCall(CilType callClass, CilMethod callMethod)
        {
            if (callClass.ClassName == callClass.JavaName)
            {
                if (callClass.ClassName == "system.FunctionalInterfaceDelegate" &&
                    callMethod.Name == "AsInterface")
                {
                    // a call to system.FunctionalInterfaceDelegate::AsInterface()
                    // should be fixed to expect an 'object' return type, and then
                    // cast that return type to the proper interface
                    var tempMethod = new JavaMethodRef(callMethod.Name, JavaType.ObjectType);
                    code.NewInstruction(0xB6 /* invokevirtual */, callClass, tempMethod);
                    code.NewInstruction(0xC0 /* checkcast */, callMethod.ReturnType, null);
                    stackMap.PopStack(CilMain.Where);
                    stackMap.PushStack(callMethod.ReturnType);
                    return(true);
                }

                if (callMethod.IsExternal &&
                    NativeMethodClasses.TryGetValue(callClass.ClassName,
                                                    out var altClassName))
                {
                    // a call to an instance method System.NameSpace.Class::Method,
                    // which is implemented only as a native method, is translated
                    // into a static call to some other class where the method is
                    // implemented.  such implementing classes are listed in the
                    // NativeMethodClasses dictionary the bottom of this file.

                    var altMethodName    = callMethod.Name;
                    int altMethodNameIdx = altMethodName.IndexOf(CilMain.OPEN_PARENS);
                    if (altMethodNameIdx != -1)
                    {
                        altMethodName = altMethodName.Substring(0, altMethodNameIdx);
                    }

                    var tempMethod = new JavaMethodRef(altMethodName, callMethod.ReturnType);
                    var parameters = new List <JavaFieldRef>(callMethod.Parameters);
                    parameters.Insert(0, new JavaFieldRef("this", callClass));
                    tempMethod.Parameters = parameters;

                    code.NewInstruction(0xB8 /* invokestatic */,
                                        new JavaType(0, 0, altClassName), tempMethod);

                    ClearMethodArguments(callMethod, false);
                    PushMethodReturnType(callMethod);
                    return(true);
                }

                // don't bother adjusting the call if the program explicitly
                // refers to the java class rather than the simulated wrapper,
                // e.g. to java.lang.Throwable rather than System.Exception
                return(false);
            }

            if (callClass.Equals(JavaType.StringType) ||
                callClass.Equals(JavaType.ThrowableType) ||
                (callClass.Equals(JavaType.ObjectType) &&
                 callMethod.Name == "GetType" &&
                 callMethod.ToDescriptor() == "()Lsystem/Type;"))
            {
                // we map some basic .Net types their java counterparts, so we
                // can't invoke .Net instance methods on them directly.  instead,
                // we invoke a static method on our helper class.  for example:
                // ((System.String)x).CompareTo(y) -> system.String.CompareTo(x,y)

                var tempMethod = new JavaMethodRef(callMethod.Name, callMethod.ReturnType);
                var parameters = new List <JavaFieldRef>(callMethod.Parameters);
                parameters.Insert(0, new JavaFieldRef("this", callClass));
                tempMethod.Parameters = parameters;

                if (callClass.Equals(JavaType.ThrowableType) &&
                    callMethod.Name == "system-Exception-GetType")
                {
                    // undo the effect of CilMethod::MethodIsShadowing upon calling
                    // the virtual/overriding GetType() from System.Exception, and
                    // instead call the static system.Object.GetType()
                    tempMethod.Name    = "GetType";
                    callClass          = CilType.From(new JavaType(0, 0, "system.Object"));
                    parameters[0].Type = JavaType.ObjectType;
                }

                else
                {
                    CilMethod.FixNameForVirtualToStaticCall(tempMethod, callClass);
                }

                code.NewInstruction(0xB8 /* invokestatic */,
                                    new JavaType(0, 0, callClass.JavaName), tempMethod);

                ClearMethodArguments(callMethod, false);
                PushMethodReturnType(callMethod);

                return(true);
            }

            if (callClass.JavaName == null &&
                callClass.Equals(JavaType.ClassType) &&
                callMethod.Name == "GetRuntimeType")
            {
                // convert virtual call to RuntimeTypeHandle.GetRuntimeType
                // to a static call to system.RuntimeType

                code.NewInstruction(0xB8 /* invokestatic */,
                                    CilType.SystemRuntimeTypeType,
                                    new JavaMethodRef(
                                        callMethod.Name, callMethod.ReturnType,
                                        JavaType.ObjectType));

                ClearMethodArguments(callMethod, false);
                PushMethodReturnType(callMethod);

                return(true);
            }

            return(false);
        }
コード例 #2
0
        bool Translate_Call(CilMethod callMethod)
        {
            var currentClass = method.DeclType;
            var callClass    = callMethod.DeclType;

            byte op;

            if (callMethod.IsStatic)
            {
                if (ConvertCallToNop())
                {
                    return(true);
                }

                if (callClass.Equals(JavaType.ObjectType) ||
                    callClass.Equals(JavaType.StringType))
                {
                    // generally we translate System.Object to java.lang.Object,
                    //                    and System.String to java.lang.String,
                    // but not in the case of a static method call
                    callClass = CilType.From(new JavaType(0, 0, callClass.JavaName));
                }

                else if (IsSystemTypeOperatorOrIsCallToIsInterface(callClass, callMethod))
                {
                    // rename System.Type operators == and != to system.RuntimeType, and
                    // rename call to RuntimeTypeHandle.IsInterface to system.RuntimeType
                    callClass = CilType.SystemRuntimeTypeType;
                }

                else if (callMethod.IsExternal &&
                         NativeMethodClasses.TryGetValue(callClass.ClassName, out var altClassName))
                {
                    // when the call target is a native methods, redirect it
                    callClass = CilType.From(new JavaType(0, 0, altClassName));
                }

                op = 0xB8; // invokestatic
            }
            else if (callMethod.IsConstructor || currentClass.IsDerivedFrom(callClass))
            {
                if (callClass.Equals(JavaType.ThrowableType))
                {
                    // generally we translate System.Exception to java.lang.Throwable,
                    // but not in the case of a super constructor call
                    callClass = CilType.From(new JavaType(0, 0, callClass.JavaName));
                }

                if (ConvertVirtualToStaticCall(callClass, callMethod))
                {
                    return(true);
                }

                if (callMethod.IsVirtual && currentClass.Equals(callClass))
                {
                    // Android 'D8' does not support 'invokespecial' on a method
                    // on the same class, unless the method is marked final.
                    // if we know the target method is a virtual method, then
                    // it surely is not marked final, so use 'invokevirtual'.

                    op = 0xB6; // invokevirtual
                }
                else
                {
                    op = 0xB7; // invokespecial
                }

                if (callMethod.Name == "clone" && callMethod.Parameters.Count == 0)
                {
                    // if calling clone on the super object, implement Cloneable
                    code.Method.Class.AddInterface("java.lang.Cloneable");
                }
            }
            else
            {
                if (ConvertVirtualToStaticCall(callClass, callMethod))
                {
                    return(true);
                }

                op = 0xB6; // invokevirtual
            }

            if (callMethod.IsArrayMethod)
            {
                arrays.Call(callMethod, cilInst);
            }
            else
            {
                CheckAndBoxArguments(callMethod, (op == 0xB6));
                PushGenericArguments(callMethod);
                code.NewInstruction(op, callClass.AsWritableClass,
                                    callMethod.WithGenericParameters);

                ClearMethodArguments(callMethod, (op == 0xB7));

                PushMethodReturnType(callMethod);
            }

            return(true);

            bool IsSystemTypeOperatorOrIsCallToIsInterface(CilType callClass, CilMethod callMethod)
            {
                if (callClass.Equals(CilType.SystemTypeType) && (
                        callMethod.Name == "op_Equality" || callMethod.Name == "op_Inequality"))
                {
                    return(true);
                }
                if (callClass.Equals(JavaType.ClassType) && callMethod.Name == "IsInterface")
                {
                    return(true);
                }
                return(false);
            }
        }